diff --git a/src/components/Tab.vue b/src/components/Tab.vue index 7209a19..4e6e360 100644 --- a/src/components/Tab.vue +++ b/src/components/Tab.vue @@ -15,13 +15,19 @@
-
+
Run your query and get results here
-
+
Fetching results...
-
+
No rows retrieved according to your query
@@ -103,7 +109,7 @@ export default { this.isGettingResults = true this.result = null this.error = null - this.$db.execute(this.query + ';') + return this.$db.execute(this.query + ';') .then(result => { this.result = result }) diff --git a/tests/unit/components/Tab.spec.js b/tests/unit/components/Tab.spec.js new file mode 100644 index 0000000..7c25867 --- /dev/null +++ b/tests/unit/components/Tab.spec.js @@ -0,0 +1,242 @@ +import { expect } from 'chai' +import sinon from 'sinon' +import { mount } from '@vue/test-utils' +import { mutations } from '@/store' +import Vuex from 'vuex' +import Tab from '@/components/Tab.vue' + +describe('Tab.vue', () => { + it('Renders passed query', () => { + // mock store state + const state = { + currentTabId: 1 + } + const store = new Vuex.Store({ state }) + + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + propsData: { + id: 1, + initName: 'foo', + initQuery: 'SELECT * FROM foo', + initChart: [], + tabIndex: 0, + isPredefined: false + } + }) + expect(wrapper.find('.tab-content-container').isVisible()).to.equal(true) + expect(wrapper.find('.table-view').isVisible()).to.equal(true) + expect(wrapper.find('.table-view .result-before').isVisible()).to.equal(true) + expect(wrapper.find('.query-editor').text()).to.equal('SELECT * FROM foo') + }) + + it("Doesn't render tab when it's not active", () => { + // mock store state + const state = { + currentTabId: 0 + } + const store = new Vuex.Store({ state }) + + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + propsData: { + id: 1 + } + }) + expect(wrapper.find('.tab-content-container').isVisible()).to.equal(false) + }) + + it("Shows chart when view equals 'chart'", async () => { + // mock store state + const state = { + currentTabId: 1 + } + + const store = new Vuex.Store({ state }) + + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + propsData: { + id: 1 + } + }) + + expect(wrapper.findComponent({ ref: 'chart' }).vm.visible).to.equal(false) + await wrapper.setData({ view: 'chart' }) + expect(wrapper.find('.table-view').isVisible()).to.equal(false) + expect(wrapper.findComponent({ ref: 'chart' }).vm.visible).to.equal(true) + }) + + it("Is not visible when not active", async () => { + // mock store state + const state = { + currentTabId: 0 + } + + const store = new Vuex.Store({ state }) + + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + propsData: { + id: 1 + } + }) + + expect(wrapper.find('.tab-content-container').isVisible()).to.equal(false) + }) + + it("Calls setCurrentTab when becomes active", async () => { + // mock store state + const state = { + currentTabId: 0 + } + sinon.spy(mutations, 'setCurrentTab') + const store = new Vuex.Store({ state, mutations }) + + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + propsData: { + id: 1 + } + }) + + state.currentTabId = 1 + expect(mutations.setCurrentTab.calledOnceWith(state, wrapper.vm)).to.equal(true) + }) + + it('Update tab state when a query is changed', async () => { + // mock store state + const state = { + tabs: [ + { id: 1, name: 'foo', query: 'SELECT * FROM foo', chart: [], isUnsaved: false } + ], + currentTabId: 1 + } + + const store = new Vuex.Store({ state, mutations }) + + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + propsData: { + id: 1, + initName: 'foo', + initQuery: 'SELECT * FROM foo', + initChart: [], + tabIndex: 0, + isPredefined: false + } + }) + await wrapper.findComponent({ name: 'SqlEditor' }).vm.$emit('input', ' limit 100') + expect(state.tabs[0].isUnsaved).to.equal(true) + }) + + it('Shows .result-in-progress message when executing query', (done) => { + // mock store state + const state = { + currentTabId: 1 + } + + const store = new Vuex.Store({ state, mutations }) + const $db = { + execute() { return new Promise(() => {}) } + } + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + mocks: { $db }, + propsData: { + id: 1, + initName: 'foo', + initQuery: 'SELECT * FROM foo', + initChart: [], + tabIndex: 0, + isPredefined: false + } + }) + + wrapper.vm.execute() + wrapper.vm.$nextTick(() => { + expect(wrapper.find('.table-view .result-before').isVisible()).to.equal(false) + expect(wrapper.find('.table-view .result-in-progress').isVisible()).to.equal(true) + }) + done() + }) + + it('Shows error when executing query ends with error', async () => { + // mock store state + const state = { + currentTabId: 1 + } + + const store = new Vuex.Store({ state, mutations }) + const $db = { + execute() { return Promise.reject('There is no table foo') } + } + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + mocks: { $db }, + propsData: { + id: 1, + initName: 'foo', + initQuery: 'SELECT * FROM foo', + initChart: [], + tabIndex: 0, + isPredefined: false + } + }) + + await wrapper.vm.execute() + expect(wrapper.find('.table-view .result-before').isVisible()).to.equal(false) + expect(wrapper.find('.table-view .result-in-progress').isVisible()).to.equal(false) + expect(wrapper.find('.table-preview.error').isVisible()).to.equal(true) + expect(wrapper.find('.table-preview.error').text()).to.equal('There is no table foo') + }) + + it('Passes result to sql-table component', async () => { + // mock store state + const state = { + currentTabId: 1 + } + + const store = new Vuex.Store({ state, mutations }) + const result = ['this is table result'] + const $db = { + execute() { return Promise.resolve(result) } + } + // mount the component + const wrapper = mount(Tab, { + store, + stubs: ['chart'], + mocks: { $db }, + propsData: { + id: 1, + initName: 'foo', + initQuery: 'SELECT * FROM foo', + initChart: [], + tabIndex: 0, + isPredefined: false + } + }) + + await wrapper.vm.execute() + expect(wrapper.find('.table-view .result-before').isVisible()).to.equal(false) + expect(wrapper.find('.table-view .result-in-progress').isVisible()).to.equal(false) + expect(wrapper.find('.table-preview.error').isVisible()).to.equal(false) + expect(wrapper.findComponent({ name: 'SqlTable' }).vm.dataSet).to.eql(result) + }) +}) diff --git a/tests/unit/components/Tabs.spec.js b/tests/unit/components/Tabs.spec.js index 9806189..560e89d 100644 --- a/tests/unit/components/Tabs.spec.js +++ b/tests/unit/components/Tabs.spec.js @@ -4,7 +4,6 @@ import { shallowMount, mount, createWrapper } from '@vue/test-utils' import { mutations } from '@/store' import Vuex from 'vuex' import Tabs from '@/components/Tabs.vue' -import Tab from '@/components/Tab.vue' describe('Tabs.vue', () => { it('Renders start guide when there is no opened tabs', () => { @@ -39,7 +38,7 @@ describe('Tabs.vue', () => { expect(wrapper.find('#start-guide').isVisible()).to.equal(false) // check tabs - expect(wrapper.findAllComponents(Tab)).to.have.lengthOf(2) + expect(wrapper.findAllComponents({ name: 'Tab' })).to.have.lengthOf(2) const firstTab = wrapper.findAll('.tab').at(0) expect(firstTab.text()).to.include('foo') @@ -98,7 +97,7 @@ describe('Tabs.vue', () => { await firstTabCloseIcon.trigger('click') // check that the only one tab left and it's opened - expect(wrapper.findAllComponents(Tab)).to.have.lengthOf(1) + expect(wrapper.findAllComponents({name: 'Tab'})).to.have.lengthOf(1) const firstTab = wrapper.findAll('.tab').at(0) expect(firstTab.text()).to.include('Untitled') @@ -138,7 +137,7 @@ describe('Tabs.vue', () => { await cancelBtn.trigger('click') // check that tab is still opened - expect(wrapper.findAllComponents(Tab)).to.have.lengthOf(2) + expect(wrapper.findAllComponents({ name: 'Tab' })).to.have.lengthOf(2) // check that the dialog is closed expect(wrapper.find('[data-modal="close-warn"]').exists()).to.equal(false) @@ -172,7 +171,7 @@ describe('Tabs.vue', () => { await closeBtn.trigger('click') // check that tab is closed - expect(wrapper.findAllComponents(Tab)).to.have.lengthOf(1) + expect(wrapper.findAllComponents({ name: 'Tab' })).to.have.lengthOf(1) const firstTab = wrapper.findAll('.tab').at(0) expect(firstTab.text()).to.include('foo') expect(firstTab.find('.star').isVisible()).to.equal(false) @@ -217,7 +216,7 @@ describe('Tabs.vue', () => { await wrapper.vm.$root.$emit('querySaved') // check that tab is closed - expect(wrapper.findAllComponents(Tab)).to.have.lengthOf(1) + expect(wrapper.findAllComponents({ name: 'Tab' })).to.have.lengthOf(1) const firstTab = wrapper.findAll('.tab').at(0) expect(firstTab.text()).to.include('foo') expect(firstTab.find('.star').isVisible()).to.equal(false)