@vue/test-utils#createWrapper JavaScript Examples

The following examples show how to use @vue/test-utils#createWrapper. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: MainMenu.spec.js    From sqliteviz with Apache License 2.0 4 votes vote down vote up
describe('MainMenu.vue', () => {
  afterEach(() => {
    sinon.restore()

    // We need explicitly destroy the component, so that beforeDestroy hook was called
    // It's important because in this hook MainMenu component removes keydown event listener.
    wrapper.destroy()
  })

  it('Create and Save are visible only on /workspace page', async () => {
    const state = {
      currentTab: { query: '', execute: sinon.stub() },
      tabs: [{}],
      db: {}
    }
    const store = new Vuex.Store({ state })
    const $route = { path: '/workspace' }
    // mount the component
    wrapper = shallowMount(MainMenu, {
      store,
      mocks: { $route },
      stubs: ['router-link']
    })
    expect(wrapper.find('#save-btn').exists()).to.equal(true)
    expect(wrapper.find('#save-btn').isVisible()).to.equal(true)
    expect(wrapper.find('#create-btn').exists()).to.equal(true)
    expect(wrapper.find('#create-btn').isVisible()).to.equal(true)

    await wrapper.vm.$set(wrapper.vm.$route, 'path', '/inquiries')
    expect(wrapper.find('#save-btn').exists()).to.equal(true)
    expect(wrapper.find('#save-btn').isVisible()).to.equal(false)
    expect(wrapper.find('#create-btn').exists()).to.equal(true)
    expect(wrapper.find('#create-btn').isVisible()).to.equal(true)
  })

  it('Save is not visible if there is no tabs', () => {
    const state = {
      currentTab: null,
      tabs: [{}],
      db: {}
    }
    const store = new Vuex.Store({ state })
    const $route = { path: '/workspace' }
    wrapper = shallowMount(MainMenu, {
      store,
      mocks: { $route },
      stubs: ['router-link']
    })
    expect(wrapper.find('#save-btn').exists()).to.equal(true)
    expect(wrapper.find('#save-btn').isVisible()).to.equal(false)
    expect(wrapper.find('#create-btn').exists()).to.equal(true)
    expect(wrapper.find('#create-btn').isVisible()).to.equal(true)
  })

  it('Save is disabled if current tab.isSaved is true', async () => {
    const state = {
      currentTab: {
        query: 'SELECT * FROM foo',
        execute: sinon.stub(),
        tabIndex: 0
      },
      tabs: [{ isSaved: false }],
      db: {}
    }
    const store = new Vuex.Store({ state })
    const $route = { path: '/workspace' }

    wrapper = shallowMount(MainMenu, {
      store,
      mocks: { $route },
      stubs: ['router-link']
    })
    const vm = wrapper.vm
    expect(wrapper.find('#save-btn').element.disabled).to.equal(false)

    await vm.$set(state.tabs[0], 'isSaved', true)
    expect(wrapper.find('#save-btn').element.disabled).to.equal(true)
  })

  it('Creates a tab', async () => {
    const state = {
      currentTab: {
        query: 'SELECT * FROM foo',
        execute: sinon.stub(),
        tabIndex: 0
      },
      tabs: [{ isSaved: false }],
      db: {}
    }
    const newInquiryId = 1
    const actions = {
      addTab: sinon.stub().resolves(newInquiryId)
    }
    const mutations = {
      setCurrentTabId: sinon.stub()
    }
    const store = new Vuex.Store({ state, mutations, actions })
    const $route = { path: '/workspace' }
    const $router = { push: sinon.stub() }

    wrapper = shallowMount(MainMenu, {
      store,
      mocks: { $route, $router },
      stubs: ['router-link']
    })

    await wrapper.find('#create-btn').trigger('click')
    expect(actions.addTab.calledOnce).to.equal(true)
    await actions.addTab.returnValues[0]
    expect(mutations.setCurrentTabId.calledOnceWith(state, newInquiryId)).to.equal(true)
    expect($router.push.calledOnce).to.equal(false)
  })

  it('Creates a tab and redirects to workspace', async () => {
    const state = {
      currentTab: {
        query: 'SELECT * FROM foo',
        execute: sinon.stub(),
        tabIndex: 0
      },
      tabs: [{ isSaved: false }],
      db: {}
    }
    const newInquiryId = 1
    const actions = {
      addTab: sinon.stub().resolves(newInquiryId)
    }
    const mutations = {
      setCurrentTabId: sinon.stub()
    }
    const store = new Vuex.Store({ state, mutations, actions })
    const $route = { path: '/inquiries' }
    const $router = { push: sinon.stub() }

    wrapper = shallowMount(MainMenu, {
      store,
      mocks: { $route, $router },
      stubs: ['router-link']
    })

    await wrapper.find('#create-btn').trigger('click')
    expect(actions.addTab.calledOnce).to.equal(true)
    await actions.addTab.returnValues[0]
    expect(mutations.setCurrentTabId.calledOnceWith(state, newInquiryId)).to.equal(true)
    expect($router.push.calledOnce).to.equal(true)
  })

  it('Ctrl R calls currentTab.execute if running is enabled and route.path is "/workspace"',
    async () => {
      const state = {
        currentTab: {
          query: 'SELECT * FROM foo',
          execute: sinon.stub(),
          tabIndex: 0
        },
        tabs: [{ isSaved: false }],
        db: {}
      }
      const store = new Vuex.Store({ state })
      const $route = { path: '/workspace' }
      const $router = { push: sinon.stub() }

      wrapper = shallowMount(MainMenu, {
        store,
        mocks: { $route, $router },
        stubs: ['router-link']
      })

      const ctrlR = new KeyboardEvent('keydown', { key: 'r', ctrlKey: true })
      const metaR = new KeyboardEvent('keydown', { key: 'r', metaKey: true })
      // Running is enabled and route path is workspace
      document.dispatchEvent(ctrlR)
      expect(state.currentTab.execute.calledOnce).to.equal(true)
      document.dispatchEvent(metaR)
      expect(state.currentTab.execute.calledTwice).to.equal(true)

      // Running is disabled and route path is workspace
      await wrapper.vm.$set(state, 'db', null)
      document.dispatchEvent(ctrlR)
      expect(state.currentTab.execute.calledTwice).to.equal(true)
      document.dispatchEvent(metaR)
      expect(state.currentTab.execute.calledTwice).to.equal(true)

      // Running is enabled and route path is not workspace
      await wrapper.vm.$set(state, 'db', {})
      await wrapper.vm.$set($route, 'path', '/inquiries')
      document.dispatchEvent(ctrlR)
      expect(state.currentTab.execute.calledTwice).to.equal(true)
      document.dispatchEvent(metaR)
      expect(state.currentTab.execute.calledTwice).to.equal(true)
    })

  it('Ctrl Enter calls currentTab.execute if running is enabled and route.path is "/workspace"',
    async () => {
      const state = {
        currentTab: {
          query: 'SELECT * FROM foo',
          execute: sinon.stub(),
          tabIndex: 0
        },
        tabs: [{ isSaved: false }],
        db: {}
      }
      const store = new Vuex.Store({ state })
      const $route = { path: '/workspace' }
      const $router = { push: sinon.stub() }

      wrapper = shallowMount(MainMenu, {
        store,
        mocks: { $route, $router },
        stubs: ['router-link']
      })

      const ctrlEnter = new KeyboardEvent('keydown', { key: 'Enter', ctrlKey: true })
      const metaEnter = new KeyboardEvent('keydown', { key: 'Enter', metaKey: true })
      // Running is enabled and route path is workspace
      document.dispatchEvent(ctrlEnter)
      expect(state.currentTab.execute.calledOnce).to.equal(true)
      document.dispatchEvent(metaEnter)
      expect(state.currentTab.execute.calledTwice).to.equal(true)

      // Running is disabled and route path is workspace
      await wrapper.vm.$set(state, 'db', null)
      document.dispatchEvent(ctrlEnter)
      expect(state.currentTab.execute.calledTwice).to.equal(true)
      document.dispatchEvent(metaEnter)
      expect(state.currentTab.execute.calledTwice).to.equal(true)

      // Running is enabled and route path is not workspace
      await wrapper.vm.$set(state, 'db', {})
      await wrapper.vm.$set($route, 'path', '/inquiries')
      document.dispatchEvent(ctrlEnter)
      expect(state.currentTab.execute.calledTwice).to.equal(true)
      document.dispatchEvent(metaEnter)
      expect(state.currentTab.execute.calledTwice).to.equal(true)
    })

  it('Ctrl B calls createNewInquiry', async () => {
    const state = {
      currentTab: {
        query: 'SELECT * FROM foo',
        execute: sinon.stub(),
        tabIndex: 0
      },
      tabs: [{ isSaved: false }],
      db: {}
    }
    const store = new Vuex.Store({ state })
    const $route = { path: '/workspace' }

    wrapper = shallowMount(MainMenu, {
      store,
      mocks: { $route },
      stubs: ['router-link']
    })
    sinon.stub(wrapper.vm, 'createNewInquiry')

    const ctrlB = new KeyboardEvent('keydown', { key: 'b', ctrlKey: true })
    const metaB = new KeyboardEvent('keydown', { key: 'b', metaKey: true })
    document.dispatchEvent(ctrlB)
    expect(wrapper.vm.createNewInquiry.calledOnce).to.equal(true)
    document.dispatchEvent(metaB)
    expect(wrapper.vm.createNewInquiry.calledTwice).to.equal(true)

    await wrapper.vm.$set($route, 'path', '/inquiries')
    document.dispatchEvent(ctrlB)
    expect(wrapper.vm.createNewInquiry.calledThrice).to.equal(true)
    document.dispatchEvent(metaB)
    expect(wrapper.vm.createNewInquiry.callCount).to.equal(4)
  })

  it('Ctrl S calls checkInquiryBeforeSave if the tab is unsaved and route path is /workspace',
    async () => {
      const state = {
        currentTab: {
          query: 'SELECT * FROM foo',
          execute: sinon.stub(),
          tabIndex: 0
        },
        tabs: [{ isSaved: false }],
        db: {}
      }
      const store = new Vuex.Store({ state })
      const $route = { path: '/workspace' }

      wrapper = shallowMount(MainMenu, {
        store,
        mocks: { $route },
        stubs: ['router-link']
      })
      sinon.stub(wrapper.vm, 'checkInquiryBeforeSave')

      const ctrlS = new KeyboardEvent('keydown', { key: 's', ctrlKey: true })
      const metaS = new KeyboardEvent('keydown', { key: 's', metaKey: true })
      // tab is unsaved and route is /workspace
      document.dispatchEvent(ctrlS)
      expect(wrapper.vm.checkInquiryBeforeSave.calledOnce).to.equal(true)
      document.dispatchEvent(metaS)
      expect(wrapper.vm.checkInquiryBeforeSave.calledTwice).to.equal(true)

      // tab is saved and route is /workspace
      await wrapper.vm.$set(state.tabs[0], 'isSaved', true)
      document.dispatchEvent(ctrlS)
      expect(wrapper.vm.checkInquiryBeforeSave.calledTwice).to.equal(true)
      document.dispatchEvent(metaS)
      expect(wrapper.vm.checkInquiryBeforeSave.calledTwice).to.equal(true)

      // tab is unsaved and route is not /workspace
      await wrapper.vm.$set($route, 'path', '/inquiries')
      await wrapper.vm.$set(state.tabs[0], 'isSaved', false)
      document.dispatchEvent(ctrlS)
      expect(wrapper.vm.checkInquiryBeforeSave.calledTwice).to.equal(true)
      document.dispatchEvent(metaS)
      expect(wrapper.vm.checkInquiryBeforeSave.calledTwice).to.equal(true)
    })

  it('Saves the inquiry when no need the new name',
    async () => {
      const state = {
        currentTab: {
          query: 'SELECT * FROM foo',
          execute: sinon.stub(),
          tabIndex: 0
        },
        tabs: [{ id: 1, name: 'foo', isSaved: false }],
        db: {}
      }
      const mutations = {
        updateTab: sinon.stub()
      }
      const store = new Vuex.Store({ state, mutations })
      const $route = { path: '/workspace' }
      sinon.stub(storedInquiries, 'isTabNeedName').returns(false)
      sinon.stub(storedInquiries, 'save').returns({
        name: 'foo',
        id: 1,
        query: 'SELECT * FROM foo',
        viewType: 'chart',
        viewOptions: []
      })

      wrapper = mount(MainMenu, {
        store,
        mocks: { $route },
        stubs: ['router-link', 'app-diagnostic-info']
      })

      await wrapper.find('#save-btn').trigger('click')

      // check that the dialog is closed
      expect(wrapper.find('[data-modal="save"]').exists()).to.equal(false)

      // check that the inquiry was saved via storedInquiries.save (newName='')
      expect(storedInquiries.save.calledOnceWith(state.currentTab, '')).to.equal(true)

      // check that the tab was updated
      expect(mutations.updateTab.calledOnceWith(state, sinon.match({
        index: 0,
        name: 'foo',
        id: 1,
        query: 'SELECT * FROM foo',
        viewType: 'chart',
        viewOptions: [],
        isSaved: true
      }))).to.equal(true)

      // check that 'inquirySaved' event was triggered on $root
      expect(createWrapper(wrapper.vm.$root).emitted('inquirySaved')).to.have.lengthOf(1)
    })

  it('Shows en error when the new name is needed but not specifyied', async () => {
    const state = {
      currentTab: {
        query: 'SELECT * FROM foo',
        execute: sinon.stub(),
        tabIndex: 0
      },
      tabs: [{ id: 1, name: null, tempName: 'Untitled', isSaved: false }],
      db: {}
    }
    const mutations = {
      updateTab: sinon.stub()
    }
    const store = new Vuex.Store({ state, mutations })
    const $route = { path: '/workspace' }
    sinon.stub(storedInquiries, 'isTabNeedName').returns(true)
    sinon.stub(storedInquiries, 'save').returns({
      name: 'foo',
      id: 1,
      query: 'SELECT * FROM foo',
      viewType: 'chart',
      viewOptions: []
    })

    wrapper = mount(MainMenu, {
      store,
      mocks: { $route },
      stubs: ['router-link', 'app-diagnostic-info']
    })

    await wrapper.find('#save-btn').trigger('click')

    // check that the dialog is open
    expect(wrapper.find('[data-modal="save"]').exists()).to.equal(true)

    // find Save in the dialog and click
    await wrapper
      .findAll('.dialog-buttons-container button').wrappers
      .find(button => button.text() === 'Save')
      .trigger('click')

    // check that we have an error message and dialog is still open
    expect(wrapper.find('.text-field-error').text()).to.equal('Inquiry name can\'t be empty')
    expect(wrapper.find('[data-modal="save"]').exists()).to.equal(true)
  })

  it('Saves the inquiry with a new name', async () => {
    const state = {
      currentTab: {
        query: 'SELECT * FROM foo',
        execute: sinon.stub(),
        tabIndex: 0
      },
      tabs: [{ id: 1, name: null, tempName: 'Untitled', isSaved: false }],
      db: {}
    }
    const mutations = {
      updateTab: sinon.stub()
    }
    const store = new Vuex.Store({ state, mutations })
    const $route = { path: '/workspace' }
    sinon.stub(storedInquiries, 'isTabNeedName').returns(true)
    sinon.stub(storedInquiries, 'save').returns({
      name: 'foo',
      id: 1,
      query: 'SELECT * FROM foo',
      viewType: 'chart',
      viewOptions: []
    })

    wrapper = mount(MainMenu, {
      store,
      mocks: { $route },
      stubs: ['router-link', 'app-diagnostic-info']
    })

    await wrapper.find('#save-btn').trigger('click')

    // check that the dialog is open
    expect(wrapper.find('[data-modal="save"]').exists()).to.equal(true)

    // enter the new name
    await wrapper.find('.dialog-body input').setValue('foo')

    // find Save in the dialog and click
    await wrapper
      .findAll('.dialog-buttons-container button').wrappers
      .find(button => button.text() === 'Save')
      .trigger('click')

    // check that the dialog is closed
    expect(wrapper.find('[data-modal="save"]').exists()).to.equal(false)

    // check that the inquiry was saved via storedInquiries.save (newName='foo')
    expect(storedInquiries.save.calledOnceWith(state.currentTab, 'foo')).to.equal(true)

    // check that the tab was updated
    expect(mutations.updateTab.calledOnceWith(state, sinon.match({
      index: 0,
      name: 'foo',
      id: 1,
      query: 'SELECT * FROM foo',
      viewType: 'chart',
      viewOptions: [],
      isSaved: true
    }))).to.equal(true)

    // check that 'inquirySaved' event was triggered on $root
    expect(createWrapper(wrapper.vm.$root).emitted('inquirySaved')).to.have.lengthOf(1)
  })

  it('Saves a predefined inquiry with a new name', async () => {
    const state = {
      currentTab: {
        query: 'SELECT * FROM foo',
        execute: sinon.stub(),
        tabIndex: 0,
        isPredefined: true,
        result: {
          columns: ['id', 'name'],
          values: [
            [1, 'Harry Potter'],
            [2, 'Drako Malfoy']
          ]
        },
        viewType: 'chart',
        viewOptions: []
      },
      tabs: [{ id: 1, name: 'foo', isSaved: false, isPredefined: true }],
      db: {}
    }
    const mutations = {
      updateTab: sinon.stub()
    }
    const store = new Vuex.Store({ state, mutations })
    const $route = { path: '/workspace' }
    sinon.stub(storedInquiries, 'isTabNeedName').returns(true)
    sinon.stub(storedInquiries, 'save').returns({
      name: 'bar',
      id: 2,
      query: 'SELECT * FROM foo',
      viewType: 'chart',
      viewOptions: []
    })

    wrapper = mount(MainMenu, {
      store,
      mocks: { $route },
      stubs: ['router-link', 'app-diagnostic-info']
    })

    await wrapper.find('#save-btn').trigger('click')

    // check that the dialog is open
    expect(wrapper.find('[data-modal="save"]').exists()).to.equal(true)

    // check that save-note is visible (save-note is an explanation why do we need a new name)
    expect(wrapper.find('#save-note').isVisible()).to.equal(true)

    // enter the new name
    await wrapper.find('.dialog-body input').setValue('bar')

    // find Save in the dialog and click
    await wrapper
      .findAll('.dialog-buttons-container button').wrappers
      .find(button => button.text() === 'Save')
      .trigger('click')

    // check that the dialog is closed
    expect(wrapper.find('[data-modal="save"]').exists()).to.equal(false)

    // check that the inquiry was saved via storedInquiries.save (newName='bar')
    expect(storedInquiries.save.calledOnceWith(state.currentTab, 'bar')).to.equal(true)

    // check that the tab was updated
    expect(mutations.updateTab.calledOnceWith(state, sinon.match({
      index: 0,
      name: 'bar',
      id: 2,
      query: 'SELECT * FROM foo',
      viewType: 'chart',
      viewOptions: [],
      isSaved: true
    }))).to.equal(true)

    // check that 'inquirySaved' event was triggered on $root
    expect(createWrapper(wrapper.vm.$root).emitted('inquirySaved')).to.have.lengthOf(1)

    // We saved predefined inquiry, so the tab will be created again
    // (because of new id) and it will be without sql result and has default view - table.
    // That's why we need to restore data and view.
    // Check that result and view are preserved in the currentTab:
    expect(state.currentTab.viewType).to.equal('chart')
    expect(state.currentTab.result).to.eql({
      columns: ['id', 'name'],
      values: [
        [1, 'Harry Potter'],
        [2, 'Drako Malfoy']
      ]
    })
  })

  it('Cancel saving', async () => {
    const state = {
      currentTab: {
        query: 'SELECT * FROM foo',
        execute: sinon.stub(),
        tabIndex: 0
      },
      tabs: [{ id: 1, name: null, tempName: 'Untitled', isSaved: false }],
      db: {}
    }
    const mutations = {
      updateTab: sinon.stub()
    }
    const store = new Vuex.Store({ state, mutations })
    const $route = { path: '/workspace' }
    sinon.stub(storedInquiries, 'isTabNeedName').returns(true)
    sinon.stub(storedInquiries, 'save').returns({
      name: 'bar',
      id: 2,
      query: 'SELECT * FROM foo',
      chart: []
    })

    wrapper = mount(MainMenu, {
      store,
      mocks: { $route },
      stubs: ['router-link', 'app-diagnostic-info']
    })

    await wrapper.find('#save-btn').trigger('click')

    // check that the dialog is open
    expect(wrapper.find('[data-modal="save"]').exists()).to.equal(true)

    // find Cancel in the dialog and click
    await wrapper
      .findAll('.dialog-buttons-container button').wrappers
      .find(button => button.text() === 'Cancel')
      .trigger('click')

    // check that the dialog is closed
    expect(wrapper.find('[data-modal="save"]').exists()).to.equal(false)

    // check that the inquiry was not saved via storedInquiries.save
    expect(storedInquiries.save.called).to.equal(false)

    // check that the tab was not updated
    expect(mutations.updateTab.called).to.equal(false)

    // check that 'inquirySaved' event is not listened on $root
    expect(wrapper.vm.$root.$listeners).to.not.have.property('inquirySaved')
  })
})
Example #2
Source File: DataView.spec.js    From sqliteviz with Apache License 2.0 4 votes vote down vote up
describe('DataView.vue', () => {
  afterEach(() => {
    sinon.restore()
  })

  it('emits update on mode changing', async () => {
    const wrapper = mount(DataView)

    const pivotBtn = createWrapper(wrapper.findComponent({ name: 'pivotIcon' }).vm.$parent)
    await pivotBtn.trigger('click')

    expect(wrapper.emitted('update')).to.have.lengthOf(1)
  })

  it('method getOptionsForSave calls the same method of the current view component', async () => {
    const wrapper = mount(DataView)

    const chart = wrapper.findComponent({ name: 'Chart' }).vm
    sinon.stub(chart, 'getOptionsForSave').returns({ here_are: 'chart_settings' })

    expect(wrapper.vm.getOptionsForSave()).to.eql({ here_are: 'chart_settings' })

    const pivotBtn = createWrapper(wrapper.findComponent({ name: 'pivotIcon' }).vm.$parent)
    await pivotBtn.trigger('click')

    const pivot = wrapper.findComponent({ name: 'pivot' }).vm
    sinon.stub(pivot, 'getOptionsForSave').returns({ here_are: 'pivot_settings' })

    expect(wrapper.vm.getOptionsForSave()).to.eql({ here_are: 'pivot_settings' })
  })

  it('method saveAsSvg calls the same method of the current view component', async () => {
    const wrapper = mount(DataView)

    // Find chart and spy the method
    const chart = wrapper.findComponent({ name: 'Chart' }).vm
    sinon.spy(chart, 'saveAsSvg')

    // Export to svg
    const svgBtn = createWrapper(wrapper.findComponent({ name: 'exportToSvgIcon' }).vm.$parent)
    await svgBtn.trigger('click')
    expect(chart.saveAsSvg.calledOnce).to.equal(true)

    // Switch to pivot
    const pivotBtn = createWrapper(wrapper.findComponent({ name: 'pivotIcon' }).vm.$parent)
    await pivotBtn.trigger('click')

    // Find pivot and spy the method
    const pivot = wrapper.findComponent({ name: 'pivot' }).vm
    sinon.spy(pivot, 'saveAsSvg')

    // Export to svg
    await svgBtn.trigger('click')
    expect(pivot.saveAsSvg.calledOnce).to.equal(true)
  })

  it('method saveAsHtml calls the same method of the current view component', async () => {
    const wrapper = mount(DataView)

    // Find chart and spy the method
    const chart = wrapper.findComponent({ name: 'Chart' }).vm
    sinon.spy(chart, 'saveAsHtml')

    // Export to html
    const htmlBtn = createWrapper(wrapper.findComponent({ name: 'htmlIcon' }).vm.$parent)
    await htmlBtn.trigger('click')
    expect(chart.saveAsHtml.calledOnce).to.equal(true)

    // Switch to pivot
    const pivotBtn = createWrapper(wrapper.findComponent({ name: 'pivotIcon' }).vm.$parent)
    await pivotBtn.trigger('click')

    // Find pivot and spy the method
    const pivot = wrapper.findComponent({ name: 'pivot' }).vm
    sinon.spy(pivot, 'saveAsHtml')

    // Export to svg
    await htmlBtn.trigger('click')
    expect(pivot.saveAsHtml.calledOnce).to.equal(true)
  })

  it('shows alert when ClipboardItem is not supported', async () => {
    const ClipboardItem = window.ClipboardItem
    delete window.ClipboardItem
    sinon.spy(window, 'alert')
    const wrapper = mount(DataView)

    const copyBtn = createWrapper(wrapper.findComponent({ name: 'clipboardIcon' }).vm.$parent)
    await copyBtn.trigger('click')

    expect(
      window.alert.calledOnceWith(
        "Your browser doesn't support copying images into the clipboard. " +
        'If you use Firefox you can enable it ' +
        'by setting dom.events.asyncClipboard.clipboardItem to true.'
      )
    ).to.equal(true)

    window.ClipboardItem = ClipboardItem
  })

  it('copy to clipboard more than 1 sec', async () => {
    sinon.stub(window.navigator.clipboard, 'write').resolves()
    const clock = sinon.useFakeTimers()
    const wrapper = mount(DataView)
    sinon.stub(wrapper.vm.$refs.viewComponent, 'prepareCopy').callsFake(() => {
      clock.tick(5000)
    })

    // Click copy to clipboard
    const copyBtn = createWrapper(wrapper.findComponent({ name: 'clipboardIcon' }).vm.$parent)
    await copyBtn.trigger('click')

    // The dialog is shown...
    expect(wrapper.find('[data-modal="prepareCopy"]').exists()).to.equal(true)

    // ... with Rendering message...
    expect(wrapper.find('.dialog-body').text()).to.equal('Rendering the visualisation...')

    // Switch to microtasks (let prepareCopy run)
    clock.tick(0)
    // Wait untill prepareCopy is finished
    await wrapper.vm.$refs.viewComponent.prepareCopy.returnValues[0]

    await wrapper.vm.$nextTick()

    // The dialog is shown...
    expect(wrapper.find('[data-modal="prepareCopy"]').exists()).to.equal(true)

    // ... with Ready message...
    expect(wrapper.find('.dialog-body').text()).to.equal('Image is ready')

    // Click copy
    await wrapper.find('.dialog-buttons-container button.primary').trigger('click')

    // The dialog is not shown...
    expect(wrapper.find('[data-modal="prepareCopy"]').exists()).to.equal(false)
  })

  it('copy to clipboard less than 1 sec', async () => {
    sinon.stub(window.navigator.clipboard, 'write').resolves()
    const clock = sinon.useFakeTimers()
    const wrapper = mount(DataView)
    sinon.spy(wrapper.vm, 'copyToClipboard')
    sinon.stub(wrapper.vm.$refs.viewComponent, 'prepareCopy').callsFake(() => {
      clock.tick(500)
    })

    // Click copy to clipboard
    const copyBtn = createWrapper(wrapper.findComponent({ name: 'clipboardIcon' }).vm.$parent)
    await copyBtn.trigger('click')

    // Switch to microtasks (let prepareCopy run)
    clock.tick(0)
    // Wait untill prepareCopy is finished
    await wrapper.vm.$refs.viewComponent.prepareCopy.returnValues[0]

    await wrapper.vm.$nextTick()
    // The dialog is not shown...
    expect(wrapper.find('[data-modal="prepareCopy"]').exists()).to.equal(false)
    // copyToClipboard is called
    expect(wrapper.vm.copyToClipboard.calledOnce).to.equal(true)
  })

  it('cancel long copy', async () => {
    sinon.stub(window.navigator.clipboard, 'write').resolves()
    const clock = sinon.useFakeTimers()
    const wrapper = mount(DataView)
    sinon.spy(wrapper.vm, 'copyToClipboard')
    sinon.stub(wrapper.vm.$refs.viewComponent, 'prepareCopy').callsFake(() => {
      clock.tick(5000)
    })

    // Click copy to clipboard
    const copyBtn = createWrapper(wrapper.findComponent({ name: 'clipboardIcon' }).vm.$parent)
    await copyBtn.trigger('click')

    // Switch to microtasks (let prepareCopy run)
    clock.tick(0)
    // Wait untill prepareCopy is finished
    await wrapper.vm.$refs.viewComponent.prepareCopy.returnValues[0]

    await wrapper.vm.$nextTick()

    // Click cancel
    await wrapper.find('.dialog-buttons-container button.secondary').trigger('click')

    // The dialog is not shown...
    expect(wrapper.find('[data-modal="prepareCopy"]').exists()).to.equal(false)
    // copyToClipboard is not called
    expect(wrapper.vm.copyToClipboard.calledOnce).to.equal(false)
  })
})
Example #3
Source File: RunResult.spec.js    From sqliteviz with Apache License 2.0 4 votes vote down vote up
describe('RunResult.vue', () => {
  afterEach(() => {
    sinon.restore()
  })

  it('shows alert when ClipboardItem is not supported', async () => {
    const ClipboardItem = window.ClipboardItem
    delete window.ClipboardItem
    sinon.spy(window, 'alert')
    const wrapper = mount(RunResult, {
      propsData: {
        result: {
          columns: ['id', 'name'],
          values: {
            id: [1],
            name: ['foo']
          }
        }
      }
    })

    const copyBtn = createWrapper(wrapper.findComponent({ name: 'clipboardIcon' }).vm.$parent)
    await copyBtn.trigger('click')

    expect(
      window.alert.calledOnceWith(
        "Your browser doesn't support copying into the clipboard. " +
        'If you use Firefox you can enable it ' +
        'by setting dom.events.asyncClipboard.clipboardItem to true.'
      )
    ).to.equal(true)

    window.ClipboardItem = ClipboardItem
  })

  it('copy to clipboard more than 1 sec', async () => {
    sinon.stub(window.navigator.clipboard, 'writeText').resolves()
    const clock = sinon.useFakeTimers()
    const wrapper = mount(RunResult, {
      propsData: {
        result: {
          columns: ['id', 'name'],
          values: {
            id: [1],
            name: ['foo']
          }
        }
      }
    })
    sinon.stub(csv, 'serialize').callsFake(() => {
      clock.tick(5000)
    })

    // Click copy to clipboard
    const copyBtn = createWrapper(wrapper.findComponent({ name: 'clipboardIcon' }).vm.$parent)
    await copyBtn.trigger('click')

    // The dialog is shown...
    expect(wrapper.find('[data-modal="prepareCSVCopy"]').exists()).to.equal(true)

    // ... with Building message...
    expect(wrapper.find('.dialog-body').text()).to.equal('Building CSV...')

    // Switch to microtasks (let serialize run)
    clock.tick(0)
    await wrapper.vm.$nextTick()

    // The dialog is shown...
    expect(wrapper.find('[data-modal="prepareCSVCopy"]').exists()).to.equal(true)

    // ... with Ready message...
    expect(wrapper.find('.dialog-body').text()).to.equal('CSV is ready')

    // Click copy
    await wrapper.find('.dialog-buttons-container button.primary').trigger('click')

    // The dialog is not shown...
    expect(wrapper.find('[data-modal="prepareCSVCopy"]').exists()).to.equal(false)
  })

  it('copy to clipboard less than 1 sec', async () => {
    sinon.stub(window.navigator.clipboard, 'writeText').resolves()
    const clock = sinon.useFakeTimers()
    const wrapper = mount(RunResult, {
      propsData: {
        result: {
          columns: ['id', 'name'],
          values: {
            id: [1],
            name: ['foo']
          }
        }
      }
    })
    sinon.spy(wrapper.vm, 'copyToClipboard')
    sinon.stub(csv, 'serialize').callsFake(() => {
      clock.tick(500)
    })

    // Click copy to clipboard
    const copyBtn = createWrapper(wrapper.findComponent({ name: 'clipboardIcon' }).vm.$parent)
    await copyBtn.trigger('click')

    // Switch to microtasks (let serialize run)
    clock.tick(0)
    await wrapper.vm.$nextTick()

    // The dialog is not shown...
    expect(wrapper.find('[data-modal="prepareCSVCopy"]').exists()).to.equal(false)
    // copyToClipboard is called
    expect(wrapper.vm.copyToClipboard.calledOnce).to.equal(true)
  })

  it('cancel long copy', async () => {
    sinon.stub(window.navigator.clipboard, 'writeText').resolves()
    const clock = sinon.useFakeTimers()
    const wrapper = mount(RunResult, {
      propsData: {
        result: {
          columns: ['id', 'name'],
          values: {
            id: [1],
            name: ['foo']
          }
        }
      }
    })
    sinon.spy(wrapper.vm, 'copyToClipboard')
    sinon.stub(csv, 'serialize').callsFake(() => {
      clock.tick(5000)
    })

    // Click copy to clipboard
    const copyBtn = createWrapper(wrapper.findComponent({ name: 'clipboardIcon' }).vm.$parent)
    await copyBtn.trigger('click')

    // Switch to microtasks (let serialize run)
    clock.tick(0)
    await wrapper.vm.$nextTick()

    // Click cancel
    await wrapper.find('.dialog-buttons-container button.secondary').trigger('click')

    // The dialog is not shown...
    expect(wrapper.find('[data-modal="prepareCSVCopy"]').exists()).to.equal(false)
    // copyToClipboard is not called
    expect(wrapper.vm.copyToClipboard.calledOnce).to.equal(false)
  })
})
Example #4
Source File: Tab.spec.js    From sqliteviz with Apache License 2.0 4 votes vote down vote up
describe('Tab.vue', () => {
  beforeEach(() => {
    place = document.createElement('div')
    document.body.appendChild(place)
  })

  afterEach(() => {
    sinon.restore()
    place.remove()
  })

  it('Renders passed query', () => {
    // mock store state
    const state = {
      currentTabId: 1
    }
    const store = new Vuex.Store({ state, mutations })

    // mount the component
    const wrapper = mount(Tab, {
      attachTo: place,
      store,
      stubs: ['chart'],
      propsData: {
        id: 1,
        initName: 'foo',
        initQuery: 'SELECT * FROM foo',
        initViewType: 'chart',
        initViewOptions: [],
        tabIndex: 0,
        isPredefined: false
      }
    })

    expect(wrapper.find('.tab-content-container').isVisible()).to.equal(true)
    expect(wrapper.find('.bottomPane .run-result-panel').exists()).to.equal(true)
    expect(wrapper.find('.run-result-panel .result-before').isVisible()).to.equal(true)
    expect(wrapper.find('.above .sql-editor-panel .codemirror-container').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, mutations })

    // mount the component
    const wrapper = mount(Tab, {
      store,
      stubs: ['chart'],
      propsData: {
        id: 1
      }
    })
    expect(wrapper.find('.tab-content-container').isVisible()).to.equal(false)
  })

  it('Is not visible when not active', async () => {
    // mock store state
    const state = {
      currentTabId: 0
    }

    const store = new Vuex.Store({ state, mutations })

    // 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
    await wrapper.vm.$nextTick()
    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: [], isSaved: true }
      ],
      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',
        initViewOptions: [],
        initViewType: 'chart',
        tabIndex: 0,
        isPredefined: false
      }
    })
    await wrapper.findComponent({ name: 'SqlEditor' }).vm.$emit('input', ' limit 100')
    expect(state.tabs[0].isSaved).to.equal(false)
  })

  it('Update tab state when data view settings are changed', async () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'SELECT * FROM foo', chart: [], isSaved: true }
      ],
      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',
        initViewOptions: [],
        initViewType: 'chart',
        tabIndex: 0,
        isPredefined: false
      }
    })
    await wrapper.findComponent({ name: 'DataView' }).vm.$emit('update')
    expect(state.tabs[0].isSaved).to.equal(false)
  })

  it('Shows .result-in-progress message when executing query', async () => {
    // mock store state
    const state = {
      currentTabId: 1,
      db: {
        execute () { return new Promise(() => {}) }
      }
    }

    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',
        initViewOptions: [],
        initViewType: 'chart',
        tabIndex: 0,
        isPredefined: false
      }
    })

    wrapper.vm.execute()
    await wrapper.vm.$nextTick()
    expect(wrapper.find('.run-result-panel .result-in-progress').isVisible()).to.equal(true)
  })

  it('Shows error when executing query ends with error', async () => {
    // mock store state
    const state = {
      currentTabId: 1,
      db: {
        execute: sinon.stub().rejects(new Error('There is no table foo')),
        refreshSchema: sinon.stub().resolves()
      }
    }

    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',
        initViewOptions: [],
        initViewType: 'chart',
        tabIndex: 0,
        isPredefined: false
      }
    })

    await wrapper.vm.execute()
    expect(wrapper.find('.run-result-panel .result-before').isVisible()).to.equal(false)
    expect(wrapper.find('.run-result-panel .result-in-progress').exists()).to.equal(false)
    expect(wrapper.findComponent({ name: 'logs' }).isVisible()).to.equal(true)
    expect(wrapper.findComponent({ name: 'logs' }).text()).to.include('There is no table foo')
  })

  it('Passes result to sql-table component', async () => {
    const result = {
      columns: ['id', 'name'],
      values: {
        id: [1, 2],
        name: ['foo', 'bar']
      }
    }
    // mock store state
    const state = {
      currentTabId: 1,
      db: {
        execute: sinon.stub().resolves(result),
        refreshSchema: sinon.stub().resolves()
      }
    }

    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',
        initViewOptions: [],
        initViewType: 'chart',
        tabIndex: 0,
        isPredefined: false
      }
    })

    await wrapper.vm.execute()
    expect(wrapper.find('.run-result-panel .result-before').isVisible()).to.equal(false)
    expect(wrapper.find('.run-result-panel .result-in-progress').exists()).to.equal(false)
    expect(wrapper.findComponent({ name: 'logs' }).exists()).to.equal(false)
    expect(wrapper.findComponent({ name: 'SqlTable' }).vm.dataSet).to.eql(result)
  })

  it('Updates schema after query execution', async () => {
    const result = {
      columns: ['id', 'name'],
      values: {
        id: [],
        name: []
      }
    }

    // mock store state
    const state = {
      currentTabId: 1,
      dbName: 'fooDb',
      db: {
        execute: sinon.stub().resolves(result),
        refreshSchema: sinon.stub().resolves()
      }
    }

    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; CREATE TABLE bar(a,b);',
        initViewOptions: [],
        initViewType: 'chart',
        tabIndex: 0,
        isPredefined: false
      }
    })

    await wrapper.vm.execute()
    expect(state.db.refreshSchema.calledOnce).to.equal(true)
  })

  it('Switches views', async () => {
    const state = {
      currentTabId: 1,
      db: {}
    }

    const store = new Vuex.Store({ state, mutations })

    const wrapper = mount(Tab, {
      attachTo: place,
      store,
      stubs: ['chart'],
      propsData: {
        id: 1,
        initName: 'foo',
        initQuery: 'SELECT * FROM foo; CREATE TABLE bar(a,b);',
        initViewOptions: [],
        initViewType: 'chart',
        tabIndex: 0,
        isPredefined: false
      }
    })

    let tableBtn = createWrapper(wrapper.find('.above .side-tool-bar')
      .findComponent({ name: 'tableIcon' }).vm.$parent)
    await tableBtn.trigger('click')

    expect(wrapper.find('.bottomPane .sql-editor-panel').exists()).to.equal(true)
    expect(wrapper.find('.above .run-result-panel').exists()).to.equal(true)

    const dataViewBtn = createWrapper(wrapper.find('.above .side-tool-bar')
      .findComponent({ name: 'dataViewIcon' }).vm.$parent)
    await dataViewBtn.trigger('click')

    expect(wrapper.find('.bottomPane .sql-editor-panel').exists()).to.equal(true)
    expect(wrapper.find('.above .data-view-panel').exists()).to.equal(true)

    const sqlEditorBtn = createWrapper(wrapper.find('.above .side-tool-bar')
      .findComponent({ name: 'sqlEditorIcon' }).vm.$parent)
    await sqlEditorBtn.trigger('click')

    expect(wrapper.find('.above .sql-editor-panel').exists()).to.equal(true)
    expect(wrapper.find('.bottomPane .data-view-panel').exists()).to.equal(true)

    tableBtn = createWrapper(wrapper.find('.bottomPane .side-tool-bar')
      .findComponent({ name: 'tableIcon' }).vm.$parent)
    await tableBtn.trigger('click')

    expect(wrapper.find('.above .sql-editor-panel').exists()).to.equal(true)
    expect(wrapper.find('.bottomPane .run-result-panel').exists()).to.equal(true)
  })
})
Example #5
Source File: Tabs.spec.js    From sqliteviz with Apache License 2.0 4 votes vote down vote up
describe('Tabs.vue', () => {
  afterEach(() => {
    sinon.restore()
  })

  it('Renders start guide when there is no opened tabs', () => {
    // mock store state
    const state = {
      tabs: []
    }
    const store = new Vuex.Store({ state })

    // mount the component
    const wrapper = shallowMount(Tabs, {
      store,
      stubs: ['router-link']
    })

    // check start-guide visibility
    expect(wrapper.find('#start-guide').isVisible()).to.equal(true)
  })

  it('Renders tabs', () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'select * from foo', chart: [], isSaved: true },
        { id: 2, name: null, tempName: 'Untitled', query: '', chart: [], isSaved: false }
      ],
      currentTabId: 2
    }
    const store = new Vuex.Store({ state })

    // mount the component
    const wrapper = shallowMount(Tabs, {
      store,
      stubs: ['router-link']
    })

    // check start-guide visibility
    expect(wrapper.find('#start-guide').isVisible()).to.equal(false)

    // check tabs
    expect(wrapper.findAllComponents({ name: 'Tab' })).to.have.lengthOf(2)

    const firstTab = wrapper.findAll('.tab').at(0)
    expect(firstTab.text()).to.include('foo')
    expect(firstTab.find('.star').isVisible()).to.equal(false)
    expect(firstTab.classes()).to.not.include('tab-selected')

    const secondTab = wrapper.findAll('.tab').at(1)
    expect(secondTab.text()).to.include('Untitled')
    expect(secondTab.find('.star').isVisible()).to.equal(true)
    expect(secondTab.classes()).to.include('tab-selected')
  })

  it('Selects the tab on click', async () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'select * from foo', chart: [], isSaved: true },
        { id: 2, name: null, tempName: 'Untitled', query: '', chart: [], isSaved: false }
      ],
      currentTabId: 2
    }

    const store = new Vuex.Store({ state, mutations })

    // mount the component
    const wrapper = shallowMount(Tabs, {
      store,
      stubs: ['router-link']
    })

    // click on the first tab
    const firstTab = wrapper.findAll('.tab').at(0)
    await firstTab.trigger('click')

    // check that first tab is the current now
    expect(firstTab.classes()).to.include('tab-selected')
    const secondTab = wrapper.findAll('.tab').at(1)
    expect(secondTab.classes()).to.not.include('tab-selected')
    expect(state.currentTabId).to.equal(1)
  })

  it("Deletes the tab on close if it's saved", async () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'select * from foo', chart: [], isSaved: true },
        { id: 2, name: null, tempName: 'Untitled', query: '', chart: [], isSaved: false }
      ],
      currentTabId: 2
    }

    const store = new Vuex.Store({ state, mutations })

    // mount the component
    const wrapper = mount(Tabs, {
      store,
      stubs: ['router-link']
    })

    // click on the close icon of the first tab
    const firstTabCloseIcon = wrapper.findAll('.tab').at(0).find('.close-icon')
    await firstTabCloseIcon.trigger('click')

    // check that the only one tab left and it's opened
    expect(wrapper.findAllComponents({ name: 'Tab' })).to.have.lengthOf(1)

    const firstTab = wrapper.findAll('.tab').at(0)
    expect(firstTab.text()).to.include('Untitled')
    expect(firstTab.find('.star').isVisible()).to.equal(true)
    expect(firstTab.classes()).to.include('tab-selected')
  })

  it("Doesn't delete tab on close if user cancel closing", async () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'select * from foo', chart: [], isSaved: true },
        { id: 2, name: null, tempName: 'Untitled', query: '', chart: [], isSaved: false }
      ],
      currentTabId: 2
    }

    const store = new Vuex.Store({ state, mutations })

    // mount the component
    const wrapper = mount(Tabs, {
      store,
      stubs: ['router-link']
    })

    // click on the close icon of the second tab
    const secondTabCloseIcon = wrapper.findAll('.tab').at(1).find('.close-icon')
    await secondTabCloseIcon.trigger('click')

    // check that Close Tab dialog is visible
    const modal = wrapper.find('[data-modal="close-warn"]')
    expect(modal.exists()).to.equal(true)

    // find Cancel in the dialog
    const cancelBtn = wrapper
      .findAll('.dialog-buttons-container button').wrappers
      .find(button => button.text() === 'Cancel')

    // click Cancel in the dialog
    await cancelBtn.trigger('click')

    // check that tab is still opened
    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)
  })

  it('Closes without saving', async () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'select * from foo', chart: [], isSaved: true },
        { id: 2, name: null, tempName: 'Untitled', query: '', chart: [], isSaved: false }
      ],
      currentTabId: 2
    }

    const store = new Vuex.Store({ state, mutations })

    // mount the component
    const wrapper = mount(Tabs, {
      store,
      stubs: ['router-link']
    })

    // click on the close icon of the second tab
    const secondTabCloseIcon = wrapper.findAll('.tab').at(1).find('.close-icon')
    await secondTabCloseIcon.trigger('click')

    // find 'Close without saving' in the dialog
    const closeBtn = wrapper
      .findAll('.dialog-buttons-container button').wrappers
      .find(button => button.text() === 'Close without saving')

    // click 'Close without saving' in the dialog
    await closeBtn.trigger('click')

    // check that tab is closed
    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)
    expect(firstTab.classes()).to.include('tab-selected')

    // check that 'saveInquiry' event was not emited
    const rootWrapper = createWrapper(wrapper.vm.$root)
    expect(rootWrapper.emitted('saveInquiry')).to.equal(undefined)

    // check that the dialog is closed
    expect(wrapper.find('[data-modal="close-warn"]').exists()).to.equal(false)
  })

  it('Closes with saving', async () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'select * from foo', chart: [], isSaved: true },
        { id: 2, name: null, tempName: 'Untitled', query: '', chart: [], isSaved: false }
      ],
      currentTabId: 2
    }

    const store = new Vuex.Store({ state, mutations })

    // mount the component
    const wrapper = mount(Tabs, {
      store,
      stubs: ['router-link']
    })

    // click on the close icon of the second tab
    const secondTabCloseIcon = wrapper.findAll('.tab').at(1).find('.close-icon')
    await secondTabCloseIcon.trigger('click')

    // find 'Save and close' in the dialog
    const closeBtn = wrapper
      .findAll('.dialog-buttons-container button').wrappers
      .find(button => button.text() === 'Save and close')

    // click 'Save and close' in the dialog
    await closeBtn.trigger('click')

    // pretend like saving is completed - trigger 'inquirySaved' on $root
    await wrapper.vm.$root.$emit('inquirySaved')

    // check that tab is closed
    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)
    expect(firstTab.classes()).to.include('tab-selected')

    // check that 'saveInquiry' event was emited
    const rootWrapper = createWrapper(wrapper.vm.$root)
    expect(rootWrapper.emitted('saveInquiry')).to.have.lengthOf(1)

    // check that the dialog is closed
    expect(wrapper.find('[data-modal="close-warn"]').exists()).to.equal(false)
  })

  it('Prevents closing a tab of a browser if there is unsaved inquiry', () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'select * from foo', chart: [], isSaved: true },
        { id: 2, name: null, tempName: 'Untitled', query: '', chart: [], isSaved: false }
      ],
      currentTabId: 2
    }

    const store = new Vuex.Store({ state, mutations })

    // mount the component
    const wrapper = shallowMount(Tabs, {
      store,
      stubs: ['router-link']
    })

    const event = new Event('beforeunload')
    sinon.spy(event, 'preventDefault')
    wrapper.vm.leavingSqliteviz(event)

    expect(event.preventDefault.calledOnce).to.equal(true)
  })

  it("Doesn't prevent closing a tab of a browser if there is unsaved inquiry", () => {
    // mock store state
    const state = {
      tabs: [
        { id: 1, name: 'foo', query: 'select * from foo', chart: [], isSaved: true }
      ],
      currentTabId: 1
    }

    const store = new Vuex.Store({ state, mutations })

    // mount the component
    const wrapper = shallowMount(Tabs, {
      store,
      stubs: ['router-link']
    })

    const event = new Event('beforeunload')
    sinon.spy(event, 'preventDefault')
    wrapper.vm.leavingSqliteviz(event)

    expect(event.preventDefault.calledOnce).to.equal(false)
  })
})