import chai from 'chai' import sinon from 'sinon' import chaiAsPromised from 'chai-as-promised' import initSqlJs from 'sql.js' import database from '@/lib/database' import fu from '@/lib/utils/fileIo' chai.use(chaiAsPromised) const expect = chai.expect chai.should() const getSQL = initSqlJs() let db describe('database.js', () => { beforeEach(() => { db = database.getNewDatabase() }) afterEach(() => { db.shutDown() sinon.restore() }) it('creates schema', async () => { const SQL = await getSQL const tempDb = new SQL.Database() tempDb.run('CREATE TABLE test (col1, col2 integer)') const data = tempDb.export() const buffer = new Blob([data]) buffer.name = 'foo.sqlite' sinon.spy(db, 'refreshSchema') await db.loadDb(buffer) await db.refreshSchema.returnValues[0] const schema = db.schema expect(db.dbName).to.equal('foo') expect(schema).to.have.lengthOf(1) expect(schema[0].name).to.equal('test') expect(schema[0].columns[0].name).to.equal('col1') expect(schema[0].columns[0].type).to.equal('N/A') expect(schema[0].columns[1].name).to.equal('col2') expect(schema[0].columns[1].type).to.equal('integer') }) it('creates empty db with name database', async () => { sinon.spy(db, 'refreshSchema') await db.loadDb() await db.refreshSchema.returnValues[0] expect(db.dbName).to.equal('database') }) it('loadDb throws errors', async () => { const buffer = new Blob([]) buffer.name = 'foo.sqlite' sinon.stub(db.pw, 'postMessage').resolves({ error: new Error('foo') }) await expect(db.loadDb(buffer)).to.be.rejectedWith('foo') }) it('returns the last query result', async () => { const SQL = await getSQL const tempDb = new SQL.Database() tempDb.run(` CREATE TABLE test ( id integer, name varchar(100), faculty varchar(100) ); INSERT INTO test (id, name, faculty) VALUES ( 1, 'Harry Potter', 'Griffindor'), ( 2, 'Draco Malfoy', 'Slytherin'); `) const data = tempDb.export() const buffer = new Blob([data]) buffer.name = 'foo.sqlite' await db.loadDb(buffer) const result = await db.execute('SELECT * from test limit 1; SELECT * from test;') expect(result.values).to.eql({ id: [1, 2], name: ['Harry Potter', 'Draco Malfoy'], faculty: ['Griffindor', 'Slytherin'] }) }) it('returns an error', async () => { const SQL = await getSQL const tempDb = new SQL.Database() tempDb.run(` CREATE TABLE test ( id integer, name varchar(100), faculty varchar(100) ); INSERT INTO test (id, name, faculty) VALUES ( 1, 'Harry Potter', 'Griffindor'), ( 2, 'Draco Malfoy', 'Slytherin'); `) const data = tempDb.export() const buffer = new Blob([data]) buffer.name = 'foo.sqlite' await db.loadDb(buffer) await expect(db.execute('SELECT * from foo')).to.be.rejectedWith(/^no such table: foo$/) }) it('adds table from csv', async () => { const data = { columns: ['id', 'name', 'faculty'], values: { id: [1, 2], name: ['Harry Potter', 'Draco Malfoy'], faculty: ['Griffindor', 'Slytherin'] } } const progressHandler = sinon.spy() const progressCounterId = db.createProgressCounter(progressHandler) sinon.spy(db, 'refreshSchema') await db.addTableFromCsv('foo', data, progressCounterId) await db.refreshSchema.returnValues[0] expect(db.dbName).to.equal('database') expect(db.schema).to.have.lengthOf(1) expect(db.schema[0].name).to.equal('foo') expect(db.schema[0].columns).to.have.lengthOf(3) expect(db.schema[0].columns[0]).to.eql({ name: 'id', type: 'real' }) expect(db.schema[0].columns[1]).to.eql({ name: 'name', type: 'text' }) expect(db.schema[0].columns[2]).to.eql({ name: 'faculty', type: 'text' }) const result = await db.execute('SELECT * from foo') expect(result).to.eql(data) expect(progressHandler.calledTwice).to.equal(true) expect(progressHandler.firstCall.calledWith(0)).to.equal(true) expect(progressHandler.secondCall.calledWith(100)).to.equal(true) }) it('addTableFromCsv throws errors', async () => { const data = { columns: [], values: { id: [1, 2], name: ['Harry Potter', 'Draco Malfoy'], faculty: null } } const progressHandler = sinon.stub() const progressCounterId = db.createProgressCounter(progressHandler) await expect(db.addTableFromCsv('foo', data, progressCounterId)).to.be.rejected }) it('progressCounters', () => { const firstHandler = sinon.stub() const firstId = db.createProgressCounter(firstHandler) db.worker.dispatchEvent(new MessageEvent('message', { data: { progress: 50, id: firstId } })) expect(firstHandler.calledOnceWith(50)).to.equal(true) const secondHandler = sinon.stub() const secondId = db.createProgressCounter(secondHandler) db.worker.dispatchEvent(new MessageEvent('message', { data: { progress: 70, id: secondId } })) expect(firstId).to.not.equals(secondId) expect(secondHandler.calledOnceWith(70)).to.equal(true) db.worker.dispatchEvent(new MessageEvent('message', { data: { progress: 80, id: firstId } })) expect(firstHandler.calledTwice).to.equal(true) expect(firstHandler.secondCall.calledWith(80)).to.equal(true) db.deleteProgressCounter(firstId) expect(db.importProgresses[firstId]).to.equal(undefined) }) it('exports db', async () => { sinon.stub(fu, 'exportToFile').resolves() // create db with table foo const stmt = ` CREATE TABLE foo(id, name); INSERT INTO foo VALUES (1, 'Harry Potter') ` let result = await db.execute(stmt) // export db to a file await db.export('fooDb.sqlite') expect(fu.exportToFile.called).to.equal(true) // get data from export const data = fu.exportToFile.getCall(0).args[0] const file = new Blob([data]) file.name = 'fooDb.sqlite' // loadDb from exported data const anotherDb = database.getNewDatabase() await anotherDb.loadDb(file) // check that new db works and has the same table and data result = await anotherDb.execute('SELECT * from foo') expect(result).to.eql({ columns: ['id', 'name'], values: { id: [1], name: ['Harry Potter'] } }) }) it('sanitizeTableName', () => { let name = 'foo[]bar' expect(db.sanitizeTableName(name)).to.equal('foo_bar') name = '1 foo(01.05.2020)' expect(db.sanitizeTableName(name)).to.equal('_1_foo_01_05_2020_') }) it('validateTableName', async () => { await db.execute('CREATE TABLE foo(id)') await expect(db.validateTableName('foo')).to.be.rejectedWith('table "foo" already exists') await expect(db.validateTableName('1foo')) .to.be.rejectedWith("Table name can't start with a digit") await expect(db.validateTableName('foo(05.08.2020)')) .to.be.rejectedWith('Table name can contain only letters, digits and underscores') await expect(db.validateTableName('sqlite_foo')) .to.be.rejectedWith("Table name can't start with sqlite_") }) })