mirror of
https://github.com/lana-k/sqliteviz.git
synced 2025-12-06 18:18:53 +08:00
Loading remote database and inquiries #109
This commit is contained in:
13
package-lock.json
generated
13
package-lock.json
generated
@@ -50,6 +50,7 @@
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"flush-promises": "^1.0.2",
|
||||
"karma": "^3.1.4",
|
||||
"karma-firefox-launcher": "^2.1.0",
|
||||
"karma-webpack": "^4.0.2",
|
||||
@@ -10090,6 +10091,12 @@
|
||||
"resolved": "https://registry.npmjs.org/flip-pixels/-/flip-pixels-1.0.2.tgz",
|
||||
"integrity": "sha512-oXbJGbjDnfJRWPC7Va38EFhd+A8JWE5/hCiKcK8qjCdbLj9DTpsq6MEudwpRTH+V4qq+Jw7d3pUgQdSr3x3mTA=="
|
||||
},
|
||||
"node_modules/flush-promises": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flush-promises/-/flush-promises-1.0.2.tgz",
|
||||
"integrity": "sha512-G0sYfLQERwKz4+4iOZYQEZVpOt9zQrlItIxQAAYAWpfby3gbHrx0osCHz5RLl/XoXevXk0xoN4hDFky/VV9TrA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/flush-write-stream": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
|
||||
@@ -33658,6 +33665,12 @@
|
||||
"resolved": "https://registry.npmjs.org/flip-pixels/-/flip-pixels-1.0.2.tgz",
|
||||
"integrity": "sha512-oXbJGbjDnfJRWPC7Va38EFhd+A8JWE5/hCiKcK8qjCdbLj9DTpsq6MEudwpRTH+V4qq+Jw7d3pUgQdSr3x3mTA=="
|
||||
},
|
||||
"flush-promises": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flush-promises/-/flush-promises-1.0.2.tgz",
|
||||
"integrity": "sha512-G0sYfLQERwKz4+4iOZYQEZVpOt9zQrlItIxQAAYAWpfby3gbHrx0osCHz5RLl/XoXevXk0xoN4hDFky/VV9TrA==",
|
||||
"dev": true
|
||||
},
|
||||
"flush-write-stream": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"flush-promises": "^1.0.2",
|
||||
"karma": "^3.1.4",
|
||||
"karma-firefox-launcher": "^2.1.0",
|
||||
"karma-webpack": "^4.0.2",
|
||||
|
||||
@@ -75,14 +75,23 @@ export default {
|
||||
props: {
|
||||
horizontal: { type: Boolean, default: false },
|
||||
before: { type: Object },
|
||||
after: { type: Object }
|
||||
after: { type: Object },
|
||||
default: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
before: 50,
|
||||
after: 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
container: null,
|
||||
paneBefore: this.before,
|
||||
paneAfter: this.after,
|
||||
beforeMinimising: {
|
||||
beforeMinimising: !this.after.size || !this.before.size ? this.default : {
|
||||
before: this.before.size,
|
||||
after: this.after.size
|
||||
},
|
||||
|
||||
@@ -77,7 +77,7 @@ class Database {
|
||||
}
|
||||
|
||||
this.dbName = file ? fu.getFileName(file) : 'database'
|
||||
this.refreshSchema()
|
||||
await this.refreshSchema()
|
||||
|
||||
events.send('database.import', file ? file.size : 0, {
|
||||
from: file ? 'sqlite' : 'none',
|
||||
|
||||
@@ -22,6 +22,7 @@ export default class Tab {
|
||||
table: 'bottom',
|
||||
dataView: 'hidden'
|
||||
}
|
||||
this.maximize = inquiry.maximize
|
||||
|
||||
this.isSaved = !!inquiry.id
|
||||
this.state = state
|
||||
|
||||
@@ -4,6 +4,7 @@ import Workspace from '@/views/Main/Workspace'
|
||||
import Inquiries from '@/views/Main/Inquiries'
|
||||
import Welcome from '@/views/Welcome'
|
||||
import Main from '@/views/Main'
|
||||
import LoadView from '@/views/LoadView'
|
||||
import store from '@/store'
|
||||
import database from '@/lib/database'
|
||||
|
||||
@@ -31,6 +32,11 @@ const routes = [
|
||||
component: Inquiries
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/load',
|
||||
name: 'Load',
|
||||
component: LoadView
|
||||
}
|
||||
]
|
||||
|
||||
@@ -39,7 +45,7 @@ const router = new VueRouter({
|
||||
})
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
if (!store.state.db) {
|
||||
if (!store.state.db && to.name !== 'Load') {
|
||||
const newDb = database.getNewDatabase()
|
||||
await newDb.loadDb()
|
||||
store.commit('setDb', newDb)
|
||||
|
||||
188
src/views/LoadView.vue
Normal file
188
src/views/LoadView.vue
Normal file
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<div>
|
||||
<logs
|
||||
id="logs"
|
||||
:messages="messages"
|
||||
/>
|
||||
<button
|
||||
v-if="hasErrors"
|
||||
id="open-workspace-btn"
|
||||
class="secondary"
|
||||
@click="$router.push('/workspace?hide_schema=1')">
|
||||
Open workspace
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import fu from '@/lib/utils/fileIo'
|
||||
import database from '@/lib/database'
|
||||
import Logs from '@/components/Logs'
|
||||
|
||||
export default {
|
||||
name: 'LoadView',
|
||||
components: {
|
||||
Logs
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
newDb: null,
|
||||
messages: [],
|
||||
dataMsg: {},
|
||||
inquiryMsg: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasErrors () {
|
||||
return this.dataMsg.type === 'error' || this.inquiryMsg.type === 'error'
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
const {
|
||||
data_url: dataUrl,
|
||||
data_format: dataFormat,
|
||||
inquiry_url: inquiryUrl,
|
||||
inquiry_id: inquiryIds,
|
||||
maximize
|
||||
} = this.$route.query
|
||||
|
||||
await this.loadData(dataUrl, dataFormat)
|
||||
const inquiries = await this.loadInquiries(inquiryUrl, inquiryIds)
|
||||
if (inquiries && inquiries.length > 0) {
|
||||
await this.openInquiries(inquiries, maximize)
|
||||
}
|
||||
if (!this.hasErrors) {
|
||||
this.$router.push('/workspace?hide_schema=1')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadData (dataUrl, dataFormat) {
|
||||
this.newDb = database.getNewDatabase()
|
||||
if (dataUrl) {
|
||||
this.dataMsg = {
|
||||
message: 'Preparing data...',
|
||||
type: 'info'
|
||||
}
|
||||
this.messages.push(this.dataMsg)
|
||||
|
||||
// Show loading indicator after 1 second
|
||||
const loadingDataIndicator = setTimeout(() => {
|
||||
if (this.dataMsg.type === 'info') {
|
||||
this.dataMsg.type = 'loading'
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
if (dataFormat === 'sqlite') {
|
||||
await this.getSqliteDb(dataUrl)
|
||||
}
|
||||
|
||||
// Loading indicator is not needed anymore
|
||||
clearTimeout(loadingDataIndicator)
|
||||
} else {
|
||||
await this.newDb.loadDb()
|
||||
}
|
||||
this.$store.commit('setDb', this.newDb)
|
||||
},
|
||||
async getSqliteDb (dataUrl) {
|
||||
try {
|
||||
const filename = new URL(dataUrl).pathname.split('/').pop()
|
||||
const res = await fu.readFile(dataUrl)
|
||||
if (!res.ok) {
|
||||
throw new Error('Fetching DB failed')
|
||||
}
|
||||
const file = await res.blob()
|
||||
file.name = filename
|
||||
|
||||
await this.newDb.loadDb(file)
|
||||
this.dataMsg.message = 'Data is ready'
|
||||
this.dataMsg.type = 'success'
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
this.dataMsg.message = error
|
||||
this.dataMsg.type = 'error'
|
||||
}
|
||||
},
|
||||
async loadInquiries (inquiryUrl, inquiryIds = []) {
|
||||
if (!inquiryUrl) {
|
||||
return []
|
||||
}
|
||||
// Show loading indicator after 1 second
|
||||
const loadingInquiriesIndicator = setTimeout(() => {
|
||||
if (this.inquiryMsg.type === 'info') {
|
||||
this.inquiryMsg.type = 'loading'
|
||||
}
|
||||
}, 1000)
|
||||
try {
|
||||
this.inquiryMsg = {
|
||||
message: 'Preparing inquiries...',
|
||||
type: 'info'
|
||||
}
|
||||
this.messages.push(this.inquiryMsg)
|
||||
|
||||
const res = await fu.readFile(inquiryUrl)
|
||||
const file = await res.json()
|
||||
|
||||
this.inquiryMsg.message = 'Inquiries are ready'
|
||||
this.inquiryMsg.type = 'success'
|
||||
|
||||
return inquiryIds.length > 0
|
||||
? file.inquiries.filter(inquiry => inquiryIds.includes(inquiry.id))
|
||||
: file.inquiries
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
this.inquiryMsg.message = error
|
||||
this.inquiryMsg.type = 'error'
|
||||
}
|
||||
// Loading indicator is not needed anymore
|
||||
clearTimeout(loadingInquiriesIndicator)
|
||||
},
|
||||
async openInquiries (inquiries, maximize) {
|
||||
let tabToOpen = null
|
||||
const layout = maximize ? this.getLayout(maximize) : undefined
|
||||
for (const inquiry of inquiries) {
|
||||
const tabId = await this.$store.dispatch('addTab', {
|
||||
...inquiry,
|
||||
id: undefined,
|
||||
layout,
|
||||
maximize
|
||||
})
|
||||
if (!tabToOpen) {
|
||||
tabToOpen = tabId
|
||||
this.$store.commit('setCurrentTabId', tabToOpen)
|
||||
}
|
||||
}
|
||||
|
||||
this.$store.state.currentTab.execute()
|
||||
},
|
||||
|
||||
getLayout (panelToMaximize) {
|
||||
if (panelToMaximize === 'dataView') {
|
||||
return {
|
||||
sqlEditor: 'hidden',
|
||||
table: 'above',
|
||||
dataView: 'bottom'
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
sqlEditor: 'above',
|
||||
table: 'bottom',
|
||||
dataView: 'hidden'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#logs {
|
||||
margin: 8px auto;
|
||||
max-width: 800px;
|
||||
|
||||
}
|
||||
|
||||
#open-workspace-btn {
|
||||
margin: 16px auto;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
@@ -3,8 +3,9 @@
|
||||
<splitpanes
|
||||
class="query-results-splitter"
|
||||
horizontal
|
||||
:before="{ size: 50, max: 100 }"
|
||||
:after="{ size: 50, max: 100 }"
|
||||
:before="{ size: topPaneSize, max: 100 }"
|
||||
:after="{ size: 100 - topPaneSize, max: 100 }"
|
||||
:default="{ before: 50, after: 50 }"
|
||||
>
|
||||
<template #left-pane>
|
||||
<div :id="'above-' + tab.id" class="above" />
|
||||
@@ -70,6 +71,13 @@ export default {
|
||||
Splitpanes,
|
||||
Teleport
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
topPaneSize: this.tab.maximize
|
||||
? this.tab.layout[this.tab.maximize] === 'above' ? 100 : 0
|
||||
: 50
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isActive () {
|
||||
return this.tab.id === this.$store.state.currentTabId
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
<div>
|
||||
<splitpanes
|
||||
class="schema-tabs-splitter"
|
||||
:before="{ size: 20, max: 30 }"
|
||||
:after="{ size: 80, max: 100 }"
|
||||
:before="{ size: schemaWidth, max: 30 }"
|
||||
:after="{ size: 100 - schemaWidth, max: 100 }"
|
||||
:default="{ before: 20, after: 80 }"
|
||||
>
|
||||
<template #left-pane>
|
||||
<schema/>
|
||||
@@ -28,6 +29,11 @@ export default {
|
||||
Splitpanes,
|
||||
Tabs
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
schemaWidth: this.$route.query.hide_schema === '1' ? 0 : 20
|
||||
}
|
||||
},
|
||||
async beforeCreate () {
|
||||
const schema = this.$store.state.db.schema
|
||||
if (!schema || schema.length === 0) {
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('Splitpanes.vue', () => {
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.height).to.equal('40%')
|
||||
})
|
||||
|
||||
it('toggles correctly', async () => {
|
||||
it('toggles correctly - no maximized initially', async () => {
|
||||
// mount the component
|
||||
const wrapper = shallowMount(Splitpanes, {
|
||||
slots: {
|
||||
@@ -70,6 +70,64 @@ describe('Splitpanes.vue', () => {
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('40%')
|
||||
})
|
||||
|
||||
it('toggles correctly - with maximized initially', async () => {
|
||||
// mount the component
|
||||
let wrapper = shallowMount(Splitpanes, {
|
||||
slots: {
|
||||
leftPane: '<div />',
|
||||
rightPane: '<div />'
|
||||
},
|
||||
propsData: {
|
||||
before: { size: 0, max: 100 },
|
||||
after: { size: 100, max: 100 },
|
||||
default: { before: 20, after: 80 }
|
||||
}
|
||||
})
|
||||
|
||||
await wrapper.find('.toggle-btn').trigger('click')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(0).element.style.width).to.equal('20%')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('80%')
|
||||
|
||||
await wrapper.findAll('.toggle-btn').at(0).trigger('click')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(0).element.style.width).to.equal('0%')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('100%')
|
||||
|
||||
await wrapper.find('.toggle-btn').trigger('click')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(0).element.style.width).to.equal('20%')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('80%')
|
||||
|
||||
await wrapper.findAll('.toggle-btn').at(1).trigger('click')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(0).element.style.width).to.equal('100%')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('0%')
|
||||
|
||||
wrapper = shallowMount(Splitpanes, {
|
||||
slots: {
|
||||
leftPane: '<div />',
|
||||
rightPane: '<div />'
|
||||
},
|
||||
propsData: {
|
||||
before: { size: 100, max: 100 },
|
||||
after: { size: 0, max: 100 }
|
||||
}
|
||||
})
|
||||
|
||||
await wrapper.find('.toggle-btn').trigger('click')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(0).element.style.width).to.equal('50%')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('50%')
|
||||
|
||||
await wrapper.findAll('.toggle-btn').at(0).trigger('click')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(0).element.style.width).to.equal('0%')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('100%')
|
||||
|
||||
await wrapper.find('.toggle-btn').trigger('click')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(0).element.style.width).to.equal('50%')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('50%')
|
||||
|
||||
await wrapper.findAll('.toggle-btn').at(1).trigger('click')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(0).element.style.width).to.equal('100%')
|
||||
expect(wrapper.findAll('.splitpanes-pane').at(1).element.style.width).to.equal('0%')
|
||||
})
|
||||
|
||||
it('drag - vertical', async () => {
|
||||
const root = document.createElement('div')
|
||||
const place = document.createElement('div')
|
||||
|
||||
@@ -283,6 +283,7 @@ describe('mutations', () => {
|
||||
|
||||
it('setCurrentTabId', () => {
|
||||
const state = {
|
||||
tabs: [{ id: 1 }, { id: 2 }],
|
||||
currentTabId: 1
|
||||
}
|
||||
|
||||
|
||||
147
tests/views/LoadView.spec.js
Normal file
147
tests/views/LoadView.spec.js
Normal file
@@ -0,0 +1,147 @@
|
||||
import { expect } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Vuex from 'vuex'
|
||||
import LoadView from '@/views/LoadView'
|
||||
import fu from '@/lib/utils/fileIo'
|
||||
import database from '@/lib/database'
|
||||
import realMutations from '@/store/mutations'
|
||||
import realActions from '@/store/actions'
|
||||
import flushPromises from 'flush-promises'
|
||||
import Tab from '@/lib/tab'
|
||||
|
||||
describe('LoadView.vue', () => {
|
||||
afterEach(() => {
|
||||
sinon.restore()
|
||||
})
|
||||
|
||||
it('Loads db and inquiries and redirects to workspace if no errors', async () => {
|
||||
const state = {
|
||||
tabs: []
|
||||
}
|
||||
const mutations = {
|
||||
setCurrentTabId: sinon.stub().callsFake(realMutations.setCurrentTabId),
|
||||
setDb: sinon.stub().callsFake(realMutations.setDb)
|
||||
}
|
||||
const actions = {
|
||||
addTab: sinon.stub().callsFake(realActions.addTab)
|
||||
}
|
||||
const store = new Vuex.Store({ state, mutations, actions })
|
||||
const $route = {
|
||||
path: '/workspace',
|
||||
query: {
|
||||
data_url: 'https://my-url/test.db',
|
||||
data_format: 'sqlite',
|
||||
inquiry_url: 'https://my-url/test_inquiries.json',
|
||||
inquiry_id: [1],
|
||||
maximize: 'dataView'
|
||||
}
|
||||
}
|
||||
|
||||
const $router = { push: sinon.stub() }
|
||||
|
||||
const readFile = sinon.stub(fu, 'readFile')
|
||||
const dataRes = new Response()
|
||||
dataRes.blob = sinon.stub().resolves({})
|
||||
readFile.onCall(0).returns(Promise.resolve(dataRes))
|
||||
|
||||
const inquiriesRes = new Response()
|
||||
inquiriesRes.json = sinon.stub().resolves({
|
||||
version: 2,
|
||||
inquiries: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }]
|
||||
})
|
||||
readFile.onCall(1).returns(Promise.resolve(inquiriesRes))
|
||||
const db = {
|
||||
loadDb: sinon.stub().resolves()
|
||||
}
|
||||
sinon.stub(database, 'getNewDatabase').returns(db)
|
||||
Tab.prototype.execute = sinon.stub()
|
||||
|
||||
const wrapper = mount(LoadView, {
|
||||
store,
|
||||
mocks: { $route, $router },
|
||||
stubs: ['router-link']
|
||||
})
|
||||
|
||||
await flushPromises()
|
||||
|
||||
// DB file is read
|
||||
expect(fu.readFile.firstCall.args[0]).to.equal('https://my-url/test.db')
|
||||
|
||||
// Db is loaded
|
||||
expect(db.loadDb.firstCall.args[0]).to.equal(await dataRes.blob.returnValues[0])
|
||||
|
||||
// Inquiries file is read
|
||||
expect(fu.readFile.secondCall.args[0])
|
||||
.to.equal('https://my-url/test_inquiries.json')
|
||||
|
||||
// Tab for inquiry is created
|
||||
expect(actions.addTab.calledOnce).to.equal(true)
|
||||
expect(actions.addTab.firstCall.args[1]).eql({
|
||||
id: undefined,
|
||||
name: 'foo',
|
||||
layout: {
|
||||
dataView: 'bottom',
|
||||
sqlEditor: 'hidden',
|
||||
table: 'above'
|
||||
},
|
||||
maximize: 'dataView'
|
||||
})
|
||||
const executedTab = Tab.prototype.execute.firstCall.thisValue
|
||||
expect(executedTab.tempName).to.equal('foo')
|
||||
expect(wrapper.find('#open-workspace-btn').exists()).to.equal(false)
|
||||
expect($router.push.called).to.equal(true)
|
||||
})
|
||||
|
||||
it('Doesn\'t redirect and show the button if there is an error', async () => {
|
||||
const state = {
|
||||
tabs: []
|
||||
}
|
||||
const mutations = {
|
||||
setCurrentTabId: sinon.stub().callsFake(realMutations.setCurrentTabId),
|
||||
setDb: sinon.stub().callsFake(realMutations.setDb)
|
||||
}
|
||||
const actions = {
|
||||
addTab: sinon.stub().callsFake(realActions.addTab)
|
||||
}
|
||||
const store = new Vuex.Store({ state, mutations, actions })
|
||||
const $route = {
|
||||
path: '/workspace',
|
||||
query: {
|
||||
data_url: 'https://my-url/test.db',
|
||||
data_format: 'sqlite',
|
||||
inquiry_url: 'https://my-url/test_inquiries.json',
|
||||
inquiry_id: [1],
|
||||
maximize: 'dataView'
|
||||
}
|
||||
}
|
||||
|
||||
const $router = { push: sinon.stub() }
|
||||
|
||||
const readFile = sinon.stub(fu, 'readFile')
|
||||
const dataRes = new Response()
|
||||
dataRes.blob = sinon.stub().rejects(new Error('Something is wrong'))
|
||||
readFile.onCall(0).returns(Promise.resolve(dataRes))
|
||||
|
||||
const inquiriesRes = new Response()
|
||||
inquiriesRes.json = sinon.stub().resolves({
|
||||
version: 2,
|
||||
inquiries: [{ id: 1 }]
|
||||
})
|
||||
readFile.onCall(1).returns(Promise.resolve(inquiriesRes))
|
||||
sinon.stub(database, 'getNewDatabase').returns({
|
||||
loadDb: sinon.stub().resolves()
|
||||
})
|
||||
|
||||
const wrapper = mount(LoadView, {
|
||||
store,
|
||||
mocks: { $route, $router },
|
||||
stubs: ['router-link']
|
||||
})
|
||||
|
||||
await flushPromises()
|
||||
expect(wrapper.find('#open-workspace-btn').exists()).to.equal(true)
|
||||
expect($router.push.called).to.equal(false)
|
||||
expect(wrapper.find('#logs').text()).to.include('Something is wrong')
|
||||
})
|
||||
})
|
||||
@@ -19,7 +19,9 @@ describe('Inquiries.vue', () => {
|
||||
predefinedInquiries: []
|
||||
}
|
||||
const mutations = {
|
||||
updatePredefinedInquiries: sinon.stub()
|
||||
setPredefinedInquiriesLoaded: sinon.stub(),
|
||||
updatePredefinedInquiries: sinon.stub(),
|
||||
setLoadingPredefinedInquiries: sinon.stub()
|
||||
}
|
||||
const store = new Vuex.Store({ state, mutations })
|
||||
const wrapper = shallowMount(Inquiries, { store })
|
||||
@@ -327,6 +329,7 @@ describe('Inquiries.vue', () => {
|
||||
sinon.stub(storedInquiries, 'getStoredInquiries').returns([inquiryInStorage])
|
||||
|
||||
const state = {
|
||||
tabs: [],
|
||||
predefinedInquiries: []
|
||||
}
|
||||
const actions = { addTab: sinon.stub().resolves(1) }
|
||||
|
||||
@@ -406,4 +406,119 @@ describe('Tab.vue', () => {
|
||||
expect(wrapper.find('.above .sql-editor-panel').exists()).to.equal(true)
|
||||
expect(wrapper.find('.bottomPane .run-result-panel').exists()).to.equal(true)
|
||||
})
|
||||
|
||||
it('Maximize top panel if maximized panel is above', () => {
|
||||
const state = {
|
||||
currentTabId: 1
|
||||
}
|
||||
const store = new Vuex.Store({ state, mutations })
|
||||
const tab = {
|
||||
id: 1,
|
||||
name: 'foo',
|
||||
query: 'SELECT * FROM foo; CREATE TABLE bar(a,b);',
|
||||
viewType: 'chart',
|
||||
viewOptions: {},
|
||||
layout: {
|
||||
sqlEditor: 'above',
|
||||
table: 'bottom',
|
||||
dataView: 'hidden'
|
||||
},
|
||||
maximize: 'sqlEditor',
|
||||
isPredefined: false,
|
||||
result: null,
|
||||
isGettingResults: false,
|
||||
error: null,
|
||||
time: 0,
|
||||
isSaved: true
|
||||
}
|
||||
|
||||
const wrapper = mount(Tab, {
|
||||
attachTo: place,
|
||||
store,
|
||||
stubs: ['chart'],
|
||||
propsData: {
|
||||
tab
|
||||
}
|
||||
})
|
||||
|
||||
expect(wrapper.find('.above').element.parentElement.style.height)
|
||||
.to.equal('100%')
|
||||
})
|
||||
|
||||
it('Maximize bottom panel if maximized panel is below', () => {
|
||||
const state = {
|
||||
currentTabId: 1
|
||||
}
|
||||
const store = new Vuex.Store({ state, mutations })
|
||||
const tab = {
|
||||
id: 1,
|
||||
name: 'foo',
|
||||
query: 'SELECT * FROM foo; CREATE TABLE bar(a,b);',
|
||||
viewType: 'chart',
|
||||
viewOptions: {},
|
||||
layout: {
|
||||
sqlEditor: 'above',
|
||||
table: 'bottom',
|
||||
dataView: 'hidden'
|
||||
},
|
||||
maximize: 'table',
|
||||
isPredefined: false,
|
||||
result: null,
|
||||
isGettingResults: false,
|
||||
error: null,
|
||||
time: 0,
|
||||
isSaved: true
|
||||
}
|
||||
|
||||
const wrapper = mount(Tab, {
|
||||
attachTo: place,
|
||||
store,
|
||||
stubs: ['chart'],
|
||||
propsData: {
|
||||
tab
|
||||
}
|
||||
})
|
||||
|
||||
expect(wrapper.find('.bottomPane').element.parentElement.style.height)
|
||||
.to.equal('100%')
|
||||
})
|
||||
|
||||
it('Panel size is 50 is nothing to maximize', () => {
|
||||
const state = {
|
||||
currentTabId: 1
|
||||
}
|
||||
const store = new Vuex.Store({ state, mutations })
|
||||
const tab = {
|
||||
id: 1,
|
||||
name: 'foo',
|
||||
query: 'SELECT * FROM foo; CREATE TABLE bar(a,b);',
|
||||
viewType: 'chart',
|
||||
viewOptions: {},
|
||||
layout: {
|
||||
sqlEditor: 'above',
|
||||
table: 'bottom',
|
||||
dataView: 'hidden'
|
||||
},
|
||||
isPredefined: false,
|
||||
result: null,
|
||||
isGettingResults: false,
|
||||
error: null,
|
||||
time: 0,
|
||||
isSaved: true
|
||||
}
|
||||
|
||||
const wrapper = mount(Tab, {
|
||||
attachTo: place,
|
||||
store,
|
||||
stubs: ['chart'],
|
||||
propsData: {
|
||||
tab
|
||||
}
|
||||
})
|
||||
|
||||
expect(wrapper.find('.above').element.parentElement.style.height)
|
||||
.to.equal('50%')
|
||||
expect(wrapper.find('.bottomPane').element.parentElement.style.height)
|
||||
.to.equal('50%')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,9 +12,11 @@ describe('Workspace.vue', () => {
|
||||
tabs: []
|
||||
}
|
||||
const store = new Vuex.Store({ state, actions, mutations })
|
||||
const $route = { path: '/workspace', query: {} }
|
||||
mount(Workspace, {
|
||||
store,
|
||||
stubs: ['router-link']
|
||||
stubs: ['router-link'],
|
||||
mocks: { $route }
|
||||
})
|
||||
|
||||
expect(state.tabs[0].query).to.include('Your database is empty.')
|
||||
@@ -24,4 +26,20 @@ describe('Workspace.vue', () => {
|
||||
expect(state.tabs[0].viewOptions).to.equal(undefined)
|
||||
expect(state.tabs[0].isSaved).to.equal(false)
|
||||
})
|
||||
|
||||
it('Collapse schema if hide_schema is 1', () => {
|
||||
const state = {
|
||||
db: {},
|
||||
tabs: []
|
||||
}
|
||||
const store = new Vuex.Store({ state, actions, mutations })
|
||||
const $route = { path: '/workspace', query: { hide_schema: '1' } }
|
||||
const vm = mount(Workspace, {
|
||||
store,
|
||||
stubs: ['router-link'],
|
||||
mocks: { $route }
|
||||
})
|
||||
|
||||
expect(vm.find('#schema-container').element.offsetWidth).to.equal(0)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user