From ef461be3e529d35702ebb5d7706e607138731aba Mon Sep 17 00:00:00 2001 From: lana-k Date: Fri, 1 Jan 2021 18:47:16 +0100 Subject: [PATCH] add store tests --- src/components/Tab.vue | 4 +- src/database.js | 5 +- src/store/index.js | 123 +++++----- tests/unit/database.spec.js | 98 +++++++- tests/unit/store.spec.js | 441 ++++++++++++++++++++++++++++++++++++ 5 files changed, 601 insertions(+), 70 deletions(-) create mode 100644 tests/unit/store.spec.js diff --git a/src/components/Tab.vue b/src/components/Tab.vue index 3abb35e..f30de25 100644 --- a/src/components/Tab.vue +++ b/src/components/Tab.vue @@ -34,7 +34,7 @@ :sql-result="result" :init-chart="initChart" ref="chart" - @update="$store.commit('updateTabState', { index: tabIndex, isUnsaved: true })" + @update="$store.commit('updateTab', { index: tabIndex, isUnsaved: true })" /> @@ -93,7 +93,7 @@ export default { } }, query () { - this.$store.commit('updateTabState', { index: this.tabIndex, isUnsaved: true }) + this.$store.commit('updateTab', { index: this.tabIndex, isUnsaved: true }) } }, methods: { diff --git a/src/database.js b/src/database.js index e5206ad..6601444 100644 --- a/src/database.js +++ b/src/database.js @@ -47,9 +47,10 @@ export default { worker.onmessage = (event) => { if (event.data.error) { reject(event.data.error) + } else { + // if it was more than one select - take only the first one + resolve(event.data.results[0]) } - // if it was more than one select - take only the first one - resolve(event.data.results[0]) } worker.postMessage({ action: 'exec', sql: commands }) }) diff --git a/src/store/index.js b/src/store/index.js index 093e4e0..0d048ae 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -3,59 +3,55 @@ import Vuex from 'vuex' Vue.use(Vuex) -export default new Vuex.Store({ - state: { - schema: null, - dbFile: null, - dbName: null, - tabs: [], - currentTab: null, - currentTabId: null, - untitledLastIndex: 0, - predefinedQueries: [] +export const state = { + schema: null, + dbFile: null, + dbName: null, + tabs: [], + currentTab: null, + currentTabId: null, + untitledLastIndex: 0, + predefinedQueries: [] +} + +export const mutations = { + saveSchema (state, { dbName, schema }) { + state.dbName = dbName + state.schema = schema }, - mutations: { - saveSchema (state, { dbName, schema }) { - state.dbName = dbName - state.schema = schema - }, - saveDbFile (state, file) { - state.dbFile = file - }, - addTab (state, tab) { - // add new tab only if was not already opened - if (!state.tabs.some(openedTab => openedTab.id === tab.id)) { - state.tabs.push(tab) - if (!tab.name) { - state.untitledLastIndex += 1 - } + addTab (state, tab) { + // add new tab only if was not already opened + if (!state.tabs.some(openedTab => openedTab.id === tab.id)) { + state.tabs.push(tab) + if (!tab.name) { + state.untitledLastIndex += 1 } - }, - updateTab (state, { index, name, id, query, chart, isUnsaved }) { - const tab = state.tabs[index] - const oldId = tab.id + } + }, + updateTab (state, { index, name, id, query, chart, isUnsaved }) { + const tab = state.tabs[index] + const oldId = tab.id - if (state.currentTabId === oldId) { - state.currentTabId = id - } + if (id && state.currentTabId === oldId) { + state.currentTabId = id + } - tab.id = id - if (name) { tab.name = name } - if (query) { tab.query = query } - if (chart) { tab.chart = chart } - if (isUnsaved !== undefined) { tab.isUnsaved = isUnsaved } + if (id) { tab.id = id } + if (name) { tab.name = name } + if (query) { tab.query = query } + if (chart) { tab.chart = chart } + if (isUnsaved !== undefined) { tab.isUnsaved = isUnsaved } + if (!isUnsaved) { + // Saved query is not predefined delete tab.isPredefined + } - Vue.set(state.tabs, index, tab) - }, - updateTabState (state, { index, isUnsaved }) { - const tab = state.tabs[index] - tab.isUnsaved = isUnsaved - Vue.set(state.tabs, index, tab) - }, - deleteTab (state, index) { - if (state.tabs[index].id !== state.currentTabId) { - } else if (index < state.tabs.length - 1) { + Vue.set(state.tabs, index, tab) + }, + deleteTab (state, index) { + // If closing tab is the current opened + if (state.tabs[index].id === state.currentTabId) { + if (index < state.tabs.length - 1) { state.currentTabId = state.tabs[index + 1].id } else if (index > 0) { state.currentTabId = state.tabs[index - 1].id @@ -64,22 +60,25 @@ export default new Vuex.Store({ state.currentTab = null state.untitledLastIndex = 0 } - state.tabs.splice(index, 1) - }, - setCurrentTabId (state, id) { - state.currentTabId = id - }, - setCurrentTab (state, tab) { - state.currentTab = tab - }, - updatePredefinedQueries (state, queries) { - if (Array.isArray(queries)) { - state.predefinedQueries = queries - } else { - state.predefinedQueries = [queries] - } } + state.tabs.splice(index, 1) }, - actions: { + setCurrentTabId (state, id) { + state.currentTabId = id + }, + setCurrentTab (state, tab) { + state.currentTab = tab + }, + updatePredefinedQueries (state, queries) { + if (Array.isArray(queries)) { + state.predefinedQueries = queries + } else { + state.predefinedQueries = [queries] + } } +} + +export default new Vuex.Store({ + state, + mutations }) diff --git a/tests/unit/database.spec.js b/tests/unit/database.spec.js index 6af1105..ea122d3 100644 --- a/tests/unit/database.spec.js +++ b/tests/unit/database.spec.js @@ -15,12 +15,12 @@ describe('HelloWorld.vue', () => { import { expect } from 'chai' import initSqlJs from 'sql.js' import db from '@/database.js' +const config = { + locateFile: filename => `js/sql-wasm.wasm` +} describe('database.js', () => { it('creates schema', () => { - const config = { - locateFile: filename => `js/sql-wasm.wasm` - } return initSqlJs(config) .then(SQL => { const database = new SQL.Database() @@ -38,7 +38,6 @@ describe('database.js', () => { return db.loadDb(buffer) }) .then(({dbName, schema}) => { - console.log(schema[0].columns) expect(schema.length).to.equal(1) expect(schema[0].name).to.equal('test') expect(schema[0].columns[0].name).to.equal('col1') @@ -51,4 +50,95 @@ describe('database.js', () => { expect(schema[0].columns[3].type).to.equal('varchar(30)') }) }) + + it('creates schema with virtual table', () => { + return initSqlJs(config) + .then(SQL => { + const database = new SQL.Database() + database.run(` + CREATE VIRTUAL TABLE test_virtual USING fts4( + col1, col2, + notindexed=col1, notindexed=col2, + tokenize=unicode61 "tokenchars=.+#") + `) + + const data = database.export() + const buffer = new Blob([data]) + return db.loadDb(buffer) + }) + .then(({dbName, schema}) => { + expect(schema[0].name).to.equal('test_virtual') + 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('N/A') + }) + }) + + it('returns a query result', () => { + return initSqlJs(config) + .then(SQL => { + const database = new SQL.Database() + database.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 = database.export() + const buffer = new Blob([data]) + return db.loadDb(buffer) + }) + .then(({dbName, schema}) => { + return db.execute('SELECT * from test') + }) + .then(result => { + expect(result.columns.length).to.equal(3) + expect(result.columns[0]).to.equal('id') + expect(result.columns[1]).to.equal('name') + expect(result.columns[2]).to.equal('faculty') + expect(result.values.length).to.equal(2) + expect(result.values[0][0]).to.equal(1) + expect(result.values[0][1]).to.equal('Harry Potter') + expect(result.values[0][2]).to.equal('Griffindor') + expect(result.values[1][0]).to.equal(2) + expect(result.values[1][1]).to.equal('Draco Malfoy') + expect(result.values[1][2]).to.equal('Slytherin') + }) + }) + + it('returns an error', () => { + return initSqlJs(config) + .then(SQL => { + const database = new SQL.Database() + database.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 = database.export() + const buffer = new Blob([data]) + return db.loadDb(buffer) + }) + .then(() => { + return db.execute('SELECT * from foo') + }) + .catch(result => { + console.log(result) + expect(result).to.equal('no such table: foo') + }) + }) }) \ No newline at end of file diff --git a/tests/unit/store.spec.js b/tests/unit/store.spec.js new file mode 100644 index 0000000..25df8ae --- /dev/null +++ b/tests/unit/store.spec.js @@ -0,0 +1,441 @@ +import { expect } from 'chai' +import { mutations } from '@/store' +const { + saveSchema, + addTab, + updateTab, + deleteTab, + setCurrentTabId, + setCurrentTab, + updatePredefinedQueries +} = mutations + +describe('mutations', () => { + it('saveSchema', () => { + // mock state + const state = {} + + const schema = [ + { name: 'table1', columns: [ + { name: 'id', type: 'INTEGER' } + ]} + ] + saveSchema(state, { + dbName: 'test', + schema + }) + expect(state.dbName).to.equal('test') + expect(JSON.stringify(state.schema)).to.equal(JSON.stringify(schema)) + }) + + it('addTab (new)', () => { + // mock state + const state = { + tabs: [], + untitledLastIndex: 0 + } + + const tab = { + id: 1, + name: null, + tempName: 'Untitled', + query: 'SELECT * from foo', + chart: {}, + isUnsaved: true + } + addTab(state, tab) + expect(JSON.stringify(state.tabs[0])).to.equal(JSON.stringify(tab)) + expect(state.untitledLastIndex).to.equal(1) + }) + + it('addTab (saved)', () => { + // mock state + const state = { + tabs: [], + untitledLastIndex: 0 + } + const tab = { + id: 1, + name: 'test', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: false + } + addTab(state, tab) + expect(JSON.stringify(state.tabs[0])).to.equal(JSON.stringify(tab)) + expect(state.untitledLastIndex).to.equal(0) + }) + + it('addTab (existed)', () => { + const tab1 = { + id: 1, + name: 'test', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: false + } + + const tab2 = { + id: 2, + name: 'bar', + tempName: null, + query: 'SELECT * from bar', + chart: {}, + isUnsaved: false + } + + // mock state + const state = { + tabs: [ tab1, tab2 ], + untitledLastIndex: 0, + } + + addTab(state, tab1) + expect(state.tabs.length).to.equal(2) + expect(state.untitledLastIndex).to.equal(0) + }) + + it('updateTab (save)', () => { + const tab = { + id: 1, + name: 'test', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: true, + isPredefined: false + } + + const newTab = { + index: 0, + id: 1, + name: 'new test', + query: 'SELECT * from bar', + isUnsaved: false + } + + // mock state + const state = { + tabs: [tab] + } + + updateTab(state, newTab) + expect(state.tabs[0].id).to.equal(1) + expect(state.tabs[0].name).to.equal('new test') + expect(state.tabs[0].tempName).to.equal(null) + expect(state.tabs[0].query).to.equal('SELECT * from bar') + expect(state.tabs[0].isUnsaved).to.equal(false) + }) + + it('updateTab (save predefined)', () => { + const tab = { + id: 1, + name: 'test', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: true, + isPredefined: true + } + + const newTab = { + index: 0, + id: 2, + name: 'new test', + query: 'SELECT * from bar', + chart: {}, + isUnsaved: false + } + + // mock state + const state = { + tabs: [tab], + currentTabId: 1 + } + + updateTab(state, newTab) + expect(state.tabs.length).to.equal(1) + expect(state.currentTabId).to.equal(2) + expect(state.tabs[0].id).to.equal(2) + expect(state.tabs[0].name).to.equal('new test') + expect(state.tabs[0].query).to.equal('SELECT * from bar') + expect(state.tabs[0].isUnsaved).to.equal(false) + expect(state.tabs[0].isPredefined).to.equal(undefined) + }) + + it('updateTab (rename)', () => { + const tab = { + id: 1, + name: 'test', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: true + } + + const newTab = { + index: 0, + id: 1, + name: 'new test' + } + + // mock state + const state = { + tabs: [tab] + } + + updateTab(state, newTab) + expect(state.tabs.length).to.equal(1) + expect(state.tabs[0].id).to.equal(1) + expect(state.tabs[0].name).to.equal('new test') + expect(state.tabs[0].query).to.equal('SELECT * from foo') + expect(state.tabs[0].isUnsaved).to.equal(true) + }) + + it('updateTab (changes detected)', () => { + const tab = { + id: 1, + name: 'test', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: false, + isPredefined: true + } + + const newTab = { + index: 0, + isUnsaved: true + } + + // mock state + const state = { + tabs: [tab] + } + + updateTab(state, newTab) + expect(state.tabs.length).to.equal(1) + expect(state.tabs[0].id).to.equal(1) + expect(state.tabs[0].name).to.equal('test') + expect(state.tabs[0].query).to.equal('SELECT * from foo') + expect(state.tabs[0].isUnsaved).to.equal(true) + }) + + it('deleteTab (opened, first)', () => { + const tab1 = { + id: 1, + name: 'foo', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: false + } + + const tab2 = { + id: 2, + name: 'bar', + tempName: null, + query: 'SELECT * from bar', + chart: {}, + isUnsaved: false + } + + // mock state + const state = { + tabs: [tab1, tab2], + currentTabId: 1 + } + + deleteTab(state, 0) + expect(state.tabs.length).to.equal(1) + expect(state.tabs[0].id).to.equal(2) + expect(state.currentTabId).to.equal(2) + }) + + it('deleteTab (opened, last)', () => { + const tab1 = { + id: 1, + name: 'foo', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: false + } + + const tab2 = { + id: 2, + name: 'bar', + tempName: null, + query: 'SELECT * from bar', + chart: {}, + isUnsaved: false + } + + // mock state + const state = { + tabs: [tab1, tab2], + currentTabId: 2 + } + + deleteTab(state, 1) + expect(state.tabs.length).to.equal(1) + expect(state.tabs[0].id).to.equal(1) + expect(state.currentTabId).to.equal(1) + }) + + it('deleteTab (opened, in the middle)', () => { + const tab1 = { + id: 1, + name: 'foo', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: false + } + + const tab2 = { + id: 2, + name: 'bar', + tempName: null, + query: 'SELECT * from bar', + chart: {}, + isUnsaved: false + } + + const tab3 = { + id: 3, + name: 'foobar', + tempName: null, + query: 'SELECT * from foobar', + chart: {}, + isUnsaved: false + } + + // mock state + const state = { + tabs: [tab1, tab2, tab3], + currentTabId: 2 + } + + deleteTab(state, 1) + expect(state.tabs.length).to.equal(2) + expect(state.tabs[0].id).to.equal(1) + expect(state.tabs[1].id).to.equal(3) + expect(state.currentTabId).to.equal(3) + }) + + it('deleteTab (opened, single)', () => { + const tab1 = { + id: 1, + name: 'foo', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: false + } + + // mock state + const state = { + tabs: [tab1], + currentTabId: 1 + } + + deleteTab(state, 0) + expect(state.tabs.length).to.equal(0) + expect(state.currentTabId).to.equal(null) + }) + + it('deleteTab (not opened)', () => { + const tab1 = { + id: 1, + name: 'foo', + tempName: null, + query: 'SELECT * from foo', + chart: {}, + isUnsaved: false + } + + const tab2 = { + id: 2, + name: 'bar', + tempName: null, + query: 'SELECT * from bar', + chart: {}, + isUnsaved: false + } + + // mock state + const state = { + tabs: [tab1, tab2], + currentTabId: 1 + } + + deleteTab(state, 1) + expect(state.tabs.length).to.equal(1) + expect(state.tabs[0].id).to.equal(1) + expect(state.currentTabId).to.equal(1) + }) + + it('setCurrentTabId', () => { + // mock state + const state = { + currentTabId: 1 + } + + setCurrentTabId(state, 2) + expect(state.currentTabId).to.equal(2) + }) + + it('setCurrentTab', () => { + // mock state + const state = { + currentTab: { id: 1} + } + + setCurrentTab(state, { id: 2 }) + expect(JSON.stringify(state.currentTab)).to.equal('{"id":2}') + }) + + it('updatePredefinedQueries (single)', () => { + const query = { + id: 1, + name: 'foo', + query: 'SELECT * FROM foo', + chart: {}, + createdAt: '2020-11-07T20:57:04.492Z' + } + + const state = { + predefinedQueries: [] + } + + updatePredefinedQueries(state, query) + expect(JSON.stringify(state.predefinedQueries)).to.equal(`[${JSON.stringify(query)}]`) + }) + + it('updatePredefinedQueries (array)', () => { + const queries = [{ + id: 1, + name: 'foo', + query: 'SELECT * FROM foo', + chart: {}, + createdAt: '2020-11-07T20:57:04.492Z' + }, + { + id: 2, + name: 'bar', + query: 'SELECT * FROM bar', + chart: {}, + createdAt: '2020-11-07T20:57:04.492Z' + }] + + const state = { + predefinedQueries: [] + } + + updatePredefinedQueries(state, queries) + expect(JSON.stringify(state.predefinedQueries)).to.equal(JSON.stringify(queries)) + }) +}) \ No newline at end of file