mirror of
https://github.com/lana-k/sqliteviz.git
synced 2025-12-06 18:18:53 +08:00
Compare commits
5 Commits
0a8c09b58d
...
0.27.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b59c21c14e | ||
|
|
4ed4b54a28 | ||
|
|
2c2bb7d6d3 | ||
|
|
efbd985b36 | ||
|
|
9cf7d0e5dc |
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "sqliteviz",
|
||||
"version": "0.26.0",
|
||||
"version": "0.27.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sqliteviz",
|
||||
"version": "0.26.0",
|
||||
"version": "0.27.1",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sqliteviz",
|
||||
"version": "0.27.0",
|
||||
"version": "0.27.1",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:clickToClose="false"
|
||||
:contentTransition="{ name: 'loading-dialog' }"
|
||||
:overlayTransition="{ name: 'loading-dialog' }"
|
||||
@update:modelValue="$emit('update:modelValue', $event)"
|
||||
@update:model-value="$emit('update:modelValue', $event)"
|
||||
>
|
||||
<div class="dialog-header">
|
||||
{{ title }}
|
||||
@@ -60,12 +60,12 @@ export default {
|
||||
title: String,
|
||||
loading: Boolean
|
||||
},
|
||||
emits: ['cancel', 'action', 'update:modelValue'],
|
||||
data() {
|
||||
return {
|
||||
show: this.modelValue
|
||||
}
|
||||
},
|
||||
emits: ['cancel', 'action', 'update:modelValue'],
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.show = this.modelValue
|
||||
|
||||
@@ -7,7 +7,7 @@ import LoadView from '@/views/LoadView'
|
||||
import store from '@/store'
|
||||
import database from '@/lib/database'
|
||||
|
||||
const routes = [
|
||||
export const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Welcome',
|
||||
|
||||
@@ -178,6 +178,7 @@ export default {
|
||||
this.openSaveModal()
|
||||
},
|
||||
openSaveModal() {
|
||||
this.$modal.hide('inquiry-conflict')
|
||||
this.errorMsg = null
|
||||
this.name = ''
|
||||
this.$modal.show('save')
|
||||
@@ -190,8 +191,6 @@ export default {
|
||||
this.saveInquiry()
|
||||
},
|
||||
async saveInquiry() {
|
||||
const dataSet = this.currentInquiryTab.result
|
||||
const tabView = this.currentInquiryTab.view
|
||||
const eventName =
|
||||
this.currentInquiryTab.name && this.name
|
||||
? 'inquiry.saveAs'
|
||||
@@ -217,16 +216,6 @@ export default {
|
||||
}
|
||||
})
|
||||
|
||||
// Restore data:
|
||||
// e.g. if we save predefined inquiry 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
|
||||
this.$nextTick(() => {
|
||||
this.currentInquiryTab.result = dataSet
|
||||
this.currentInquiryTab.view = tabView
|
||||
})
|
||||
|
||||
// Hide dialogs
|
||||
this.$modal.hide('save')
|
||||
this.$modal.hide('inquiry-conflict')
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import { expect } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import { shallowMount, mount } from '@vue/test-utils'
|
||||
import { createStore } from 'vuex'
|
||||
import App from '@/App.vue'
|
||||
import storedInquiries from '@/lib/storedInquiries'
|
||||
import actions from '@/store/actions'
|
||||
import mutations from '@/store/mutations'
|
||||
import { nextTick } from 'vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { routes } from '@/router'
|
||||
|
||||
describe('App.vue', () => {
|
||||
let clock
|
||||
|
||||
beforeEach(() => {
|
||||
clock = sinon.useFakeTimers()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore()
|
||||
})
|
||||
@@ -92,4 +101,134 @@ describe('App.vue', () => {
|
||||
{ id: 3, name: 'bar' }
|
||||
])
|
||||
})
|
||||
|
||||
it('Closes with saving and does not change the next tab', async () => {
|
||||
const inquiries = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'foo',
|
||||
query: 'SELECT * FROM foo',
|
||||
viewType: 'chart',
|
||||
viewOptions: {},
|
||||
createdAt: '2020-11-07T20:57:04.492Z'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'bar',
|
||||
query: 'SELECT * FROM bar',
|
||||
viewType: 'chart',
|
||||
viewOptions: {},
|
||||
createdAt: '2020-11-07T20:57:04.492Z'
|
||||
}
|
||||
]
|
||||
sinon.stub(storedInquiries, 'getStoredInquiries').returns(inquiries)
|
||||
const tab1 = {
|
||||
id: 1,
|
||||
name: 'foo',
|
||||
query: 'select * from foo',
|
||||
viewType: 'chart',
|
||||
viewOptions: {},
|
||||
layout: {
|
||||
sqlEditor: 'above',
|
||||
table: 'bottom',
|
||||
dataView: 'hidden'
|
||||
},
|
||||
result: {
|
||||
columns: ['name', 'points'],
|
||||
values: {
|
||||
name: ['Gryffindor', 'Hufflepuff', 'Ravenclaw', 'Slytherin'],
|
||||
points: [100, 90, 95, 80]
|
||||
}
|
||||
},
|
||||
isSaved: false
|
||||
}
|
||||
const tab2 = {
|
||||
id: 2,
|
||||
name: 'bar',
|
||||
query: 'SELECT * FROM bar',
|
||||
viewType: 'chart',
|
||||
viewOptions: {},
|
||||
layout: {
|
||||
sqlEditor: 'above',
|
||||
table: 'hidden',
|
||||
dataView: 'bottom'
|
||||
},
|
||||
result: {
|
||||
columns: ['id'],
|
||||
values: {
|
||||
id: [1, 2, 3]
|
||||
}
|
||||
},
|
||||
isSaved: true
|
||||
}
|
||||
// mock store state
|
||||
const state = {
|
||||
tabs: [tab1, tab2],
|
||||
currentTabId: 1,
|
||||
currentTab: tab1,
|
||||
db: {},
|
||||
inquiries
|
||||
}
|
||||
|
||||
const store = createStore({ state, mutations, actions })
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: routes
|
||||
})
|
||||
router.push('/workspace')
|
||||
|
||||
// After this line, router is ready
|
||||
await router.isReady()
|
||||
|
||||
const wrapper = mount(App, {
|
||||
attachTo: document.body,
|
||||
global: {
|
||||
stubs: {
|
||||
'router-link': true,
|
||||
teleport: true,
|
||||
transition: false,
|
||||
schema: true,
|
||||
AppDiagnosticInfo: true,
|
||||
DataView: {
|
||||
template: '<div></div>',
|
||||
methods: { getOptionsForSave: sinon.stub() }
|
||||
}
|
||||
},
|
||||
plugins: [store, router]
|
||||
}
|
||||
})
|
||||
// click on the close icon of the first tab
|
||||
const firstTabCloseIcon = wrapper.findAll('.tab')[0].find('.close-icon')
|
||||
await firstTabCloseIcon.trigger('click')
|
||||
|
||||
// find 'Save and close' in the dialog
|
||||
const closeBtn = wrapper
|
||||
.findAll('.dialog-buttons-container button')
|
||||
.find(button => button.text() === 'Save and close')
|
||||
|
||||
// click 'Save and close' in the dialog
|
||||
await closeBtn.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
|
||||
// check that tab is closed
|
||||
expect(wrapper.findAllComponents({ name: 'Tab' })).to.have.lengthOf(1)
|
||||
// check that the open tab didn't change
|
||||
const firstTab = wrapper.findComponent({ name: 'Tab' })
|
||||
expect(firstTab.props('tab').name).to.equal('bar')
|
||||
expect(firstTab.props('tab').result).to.eql({
|
||||
columns: ['id'],
|
||||
values: {
|
||||
id: [1, 2, 3]
|
||||
}
|
||||
})
|
||||
expect(firstTab.props('tab')).to.eql(tab2)
|
||||
|
||||
// check that the dialog is closed
|
||||
await clock.tick(100)
|
||||
await nextTick()
|
||||
expect(wrapper.find('.dialog.vfm .vfm__content').exists()).to.equal(false)
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -608,8 +608,6 @@ describe('MainMenu.vue', () => {
|
||||
.find(button => button.text() === 'Overwrite')
|
||||
.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
|
||||
// check that the dialog is closed
|
||||
await clock.tick(100)
|
||||
expect(wrapper.find('.dialog.vfm').exists()).to.equal(false)
|
||||
@@ -694,8 +692,6 @@ describe('MainMenu.vue', () => {
|
||||
.find(button => button.text() === 'Save')
|
||||
.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
|
||||
// check that the dialog is closed
|
||||
await clock.tick(100)
|
||||
expect(wrapper.find('.dialog.vfm').exists()).to.equal(false)
|
||||
@@ -725,8 +721,6 @@ describe('MainMenu.vue', () => {
|
||||
.find(button => button.text() === 'Overwrite')
|
||||
.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
|
||||
// check that the dialog is closed
|
||||
await clock.tick(100)
|
||||
expect(wrapper.find('.dialog.vfm').exists()).to.equal(false)
|
||||
@@ -759,8 +753,7 @@ describe('MainMenu.vue', () => {
|
||||
createdAt: '2025-05-14T15:30:00Z'
|
||||
}
|
||||
],
|
||||
tabs: [tab],
|
||||
db: {}
|
||||
tabs: [tab]
|
||||
}
|
||||
const mutations = {
|
||||
updateTab: sinon.stub()
|
||||
@@ -795,22 +788,29 @@ describe('MainMenu.vue', () => {
|
||||
})
|
||||
|
||||
await wrapper.find('#save-btn').trigger('click')
|
||||
|
||||
// check that the conflict dialog is open
|
||||
expect(wrapper.find('.dialog.vfm').exists()).to.equal(true)
|
||||
expect(wrapper.find('.dialog.vfm .dialog-header').text()).to.contain(
|
||||
'Inquiry saving conflict'
|
||||
)
|
||||
|
||||
await clock.tick(100)
|
||||
|
||||
// find "Save as new" in the dialog and click
|
||||
|
||||
await wrapper
|
||||
.findAll('.dialog-buttons-container button')
|
||||
.find(button => button.text() === 'Save as new')
|
||||
.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
// Hiding any dialog is done with tiny animation. Give time to finish it:
|
||||
await clock.tick(100)
|
||||
// Note: don't call nextTick before clock.tick. That leads to extra trap in
|
||||
// trapStack and the test fails with focus-trap error in afterEach hook
|
||||
// when unmount the component
|
||||
|
||||
// check that only one dialog open
|
||||
expect(wrapper.findAll('.dialog.vfm').length).to.equal(1)
|
||||
// enter the new name
|
||||
await wrapper.find('.dialog-body input').setValue('foo_new')
|
||||
|
||||
@@ -820,8 +820,6 @@ describe('MainMenu.vue', () => {
|
||||
.find(button => button.text() === 'Save')
|
||||
.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
|
||||
// check that the dialog is closed
|
||||
await clock.tick(100)
|
||||
expect(wrapper.find('.dialog.vfm').exists()).to.equal(false)
|
||||
@@ -1062,8 +1060,6 @@ describe('MainMenu.vue', () => {
|
||||
.find(button => button.text() === 'Save')
|
||||
.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
|
||||
// check that the dialog is closed
|
||||
await clock.tick(100)
|
||||
expect(wrapper.find('.dialog.vfm').exists()).to.equal(false)
|
||||
@@ -1172,8 +1168,6 @@ describe('MainMenu.vue', () => {
|
||||
.find(button => button.text() === 'Save')
|
||||
.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
|
||||
// check that the dialog is closed
|
||||
await clock.tick(100)
|
||||
expect(wrapper.find('.dialog.vfm').exists()).to.equal(false)
|
||||
@@ -1206,19 +1200,6 @@ describe('MainMenu.vue', () => {
|
||||
|
||||
// check that 'inquirySaved' event was triggered on eventBus
|
||||
expect(eventBus.$emit.calledOnceWith('inquirySaved')).to.equal(true)
|
||||
|
||||
// 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 () => {
|
||||
@@ -1364,8 +1345,6 @@ describe('MainMenu.vue', () => {
|
||||
.find(button => button.text() === 'Save')
|
||||
.trigger('click')
|
||||
|
||||
await nextTick()
|
||||
|
||||
// check that the dialog is closed
|
||||
await clock.tick(100)
|
||||
expect(wrapper.find('.dialog.vfm').exists()).to.equal(false)
|
||||
|
||||
@@ -228,7 +228,6 @@ describe('DataView.vue', () => {
|
||||
// Wait untill prepareCopy is finished
|
||||
await wrapper.vm.$refs.viewComponent.prepareCopy.returnValues[0]
|
||||
|
||||
await nextTick()
|
||||
// The dialog is not shown...
|
||||
await clock.tick(100)
|
||||
expect(wrapper.find('.dialog.vfm .vfm__content').exists()).to.equal(false)
|
||||
|
||||
@@ -139,7 +139,6 @@ describe('RunResult.vue', () => {
|
||||
|
||||
// Switch to microtasks (let serialize run)
|
||||
await clock.tick(0)
|
||||
await nextTick()
|
||||
|
||||
// The dialog is not shown...
|
||||
await clock.tick(100)
|
||||
|
||||
Reference in New Issue
Block a user