mirror of
https://github.com/lana-k/sqliteviz.git
synced 2025-12-06 18:18:53 +08:00
move tests to tests folder
rename util modules rename DbUpload to DbUploader add tests for DbUploader component #27
This commit is contained in:
@@ -19,7 +19,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
files: [
|
files: [
|
||||||
'**/__tests__/*.{j,t}s?(x)',
|
'**/__tests__/*.{j,t}s?(x)',
|
||||||
'**/tests/unit/**/*.spec.{j,t}s?(x)'
|
'**/tests/**/*.spec.{j,t}s?(x)'
|
||||||
],
|
],
|
||||||
env: {
|
env: {
|
||||||
mocha: true
|
mocha: true
|
||||||
|
|||||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -27,4 +27,4 @@ jobs:
|
|||||||
run: npm run lint
|
run: npm run lint
|
||||||
|
|
||||||
- name: Run karma tests
|
- name: Run karma tests
|
||||||
run: npm run test:unit
|
run: npm run test
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Vue.use(VModal)
|
|||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
// require all test files (files that ends with .spec.js)
|
// require all test files (files that ends with .spec.js)
|
||||||
const testsContext = require.context('./tests/unit', true, /\.spec.js$/)
|
const testsContext = require.context('./tests', true, /\.spec.js$/)
|
||||||
|
|
||||||
// Read more about why we need to call testContext:
|
// Read more about why we need to call testContext:
|
||||||
// https://www.npmjs.com/package/require-context#context-api
|
// https://www.npmjs.com/package/require-context#context-api
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "NODE_OPTIONS=--max_old_space_size=4096 vue-cli-service build",
|
"build": "NODE_OPTIONS=--max_old_space_size=4096 vue-cli-service build",
|
||||||
"test:unit": "vue-cli-service karma",
|
"test": "vue-cli-service karma",
|
||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'checkBox',
|
name: 'CheckBox',
|
||||||
props: {
|
props: {
|
||||||
theme: {
|
theme: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="db-upload-container">
|
<div class="db-uploader-container">
|
||||||
<change-db-icon v-if="type === 'small'" @click.native="browse"/>
|
<change-db-icon v-if="type === 'small'" @click.native="browse"/>
|
||||||
<div v-if="['regular', 'illustrated'].includes(type)" class="drop-area-container">
|
<div v-if="['regular', 'illustrated'].includes(type)" class="drop-area-container">
|
||||||
<div
|
<div
|
||||||
@@ -62,6 +62,7 @@
|
|||||||
width="93px"
|
width="93px"
|
||||||
:disabled="disableDialog"
|
:disabled="disableDialog"
|
||||||
class="char-input"
|
class="char-input"
|
||||||
|
id="quote-char"
|
||||||
/>
|
/>
|
||||||
<text-field
|
<text-field
|
||||||
label="Escape char"
|
label="Escape char"
|
||||||
@@ -71,6 +72,7 @@
|
|||||||
width="93px"
|
width="93px"
|
||||||
:disabled="disableDialog"
|
:disabled="disableDialog"
|
||||||
class="char-input"
|
class="char-input"
|
||||||
|
id="escape-char"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<check-box
|
<check-box
|
||||||
@@ -122,7 +124,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import fu from '@/fileUtils'
|
import fu from '@/file.utils'
|
||||||
import csv from '@/csv'
|
import csv from '@/csv'
|
||||||
import CloseIcon from '@/components/svg/close'
|
import CloseIcon from '@/components/svg/close'
|
||||||
import TextField from '@/components/TextField'
|
import TextField from '@/components/TextField'
|
||||||
@@ -135,7 +137,7 @@ import time from '@/time'
|
|||||||
import database from '@/database'
|
import database from '@/database'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DbUpload',
|
name: 'DbUploader',
|
||||||
props: {
|
props: {
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -164,7 +166,7 @@ export default {
|
|||||||
delimiter: '',
|
delimiter: '',
|
||||||
quoteChar: '"',
|
quoteChar: '"',
|
||||||
escapeChar: '"',
|
escapeChar: '"',
|
||||||
header: false,
|
header: true,
|
||||||
previewData: null,
|
previewData: null,
|
||||||
importCsvMessages: [],
|
importCsvMessages: [],
|
||||||
disableDialog: false,
|
disableDialog: false,
|
||||||
@@ -237,9 +239,9 @@ export default {
|
|||||||
this.delimiter = parseResult.delimiter
|
this.delimiter = parseResult.delimiter
|
||||||
|
|
||||||
// In parseResult.messages we can get parse errors
|
// In parseResult.messages we can get parse errors
|
||||||
this.importCsvMessages = parseResult.messages
|
this.importCsvMessages = parseResult.messages || []
|
||||||
|
|
||||||
if (parseResult.messages.length === 0) {
|
if (!parseResult.hasErrors) {
|
||||||
this.importCsvMessages.push({
|
this.importCsvMessages.push({
|
||||||
message: `Preview parsing is completed in ${time.getPeriod(start, end)}.`,
|
message: `Preview parsing is completed in ${time.getPeriod(start, end)}.`,
|
||||||
type: 'success'
|
type: 'success'
|
||||||
@@ -390,7 +392,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.db-upload-container {
|
.db-uploader-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.drop-area-container {
|
.drop-area-container {
|
||||||
@@ -35,7 +35,11 @@ export default {
|
|||||||
serializeMessage (msg) {
|
serializeMessage (msg) {
|
||||||
let result = ''
|
let result = ''
|
||||||
if (msg.row !== null && msg.row !== undefined) {
|
if (msg.row !== null && msg.row !== undefined) {
|
||||||
result += `Error in row ${msg.row}. `
|
if (msg.type === 'error') {
|
||||||
|
result += `Error in row ${msg.row}. `
|
||||||
|
} else {
|
||||||
|
result += `Information about row ${msg.row}. `
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result += msg.message
|
result += msg.message
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<tree-chevron :expanded="schemaVisible"/>
|
<tree-chevron :expanded="schemaVisible"/>
|
||||||
{{ dbName }}
|
{{ dbName }}
|
||||||
</div>
|
</div>
|
||||||
<db-upload id="db-edit" type="small" />
|
<db-uploader id="db-edit" type="small" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="schemaVisible" class="schema">
|
<div v-show="schemaVisible" class="schema">
|
||||||
<table-description
|
<table-description
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
import TableDescription from '@/components/TableDescription'
|
import TableDescription from '@/components/TableDescription'
|
||||||
import TextField from '@/components/TextField'
|
import TextField from '@/components/TextField'
|
||||||
import TreeChevron from '@/components/svg/treeChevron'
|
import TreeChevron from '@/components/svg/treeChevron'
|
||||||
import dbUpload from '@/components/DbUpload'
|
import DbUploader from '@/components/DbUploader'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Schema',
|
name: 'Schema',
|
||||||
@@ -33,7 +33,7 @@ export default {
|
|||||||
TableDescription,
|
TableDescription,
|
||||||
TextField,
|
TextField,
|
||||||
TreeChevron,
|
TreeChevron,
|
||||||
dbUpload
|
DbUploader
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import sqliteParser from 'sqlite-parser'
|
import sqliteParser from 'sqlite-parser'
|
||||||
import fu from '@/fileUtils'
|
import fu from '@/file.utils'
|
||||||
// We can import workers like so because of worker-loader:
|
// We can import workers like so because of worker-loader:
|
||||||
// https://webpack.js.org/loaders/worker-loader/
|
// https://webpack.js.org/loaders/worker-loader/
|
||||||
import Worker from '@/db.worker.js'
|
import Worker from '@/db.worker.js'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import initSqlJs from 'sql.js/dist/sql-wasm.js'
|
import initSqlJs from 'sql.js/dist/sql-wasm.js'
|
||||||
import dbUtils from '@/dbUtils'
|
import dbUtils from '@/db.utils'
|
||||||
|
|
||||||
let SQL = null
|
let SQL = null
|
||||||
const sqlModuleReady = initSqlJs().then(sqlModule => { SQL = sqlModule })
|
const sqlModuleReady = initSqlJs().then(sqlModule => { SQL = sqlModule })
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { nanoid } from 'nanoid'
|
import { nanoid } from 'nanoid'
|
||||||
import fu from '@/fileUtils'
|
import fu from '@/file.utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getStoredQueries () {
|
getStoredQueries () {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<div class="warning">
|
<div class="warning">
|
||||||
Database is not loaded. Queries can’t be run without database.
|
Database is not loaded. Queries can’t be run without database.
|
||||||
</div>
|
</div>
|
||||||
<db-upload id="db-uploader"/>
|
<db-uploader id="db-uploader"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right-pane>
|
<template #right-pane>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
import Splitpanes from '@/components/Splitpanes'
|
import Splitpanes from '@/components/Splitpanes'
|
||||||
import Schema from '@/components/Schema'
|
import Schema from '@/components/Schema'
|
||||||
import Tabs from '@/components/Tabs'
|
import Tabs from '@/components/Tabs'
|
||||||
import dbUpload from '@/components/DbUpload'
|
import DbUploader from '@/components/DbUploader'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Editor',
|
name: 'Editor',
|
||||||
@@ -33,7 +33,7 @@ export default {
|
|||||||
Schema,
|
Schema,
|
||||||
Splitpanes,
|
Splitpanes,
|
||||||
Tabs,
|
Tabs,
|
||||||
dbUpload
|
DbUploader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -64,7 +64,7 @@ export default {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
>>> .db-upload-container {
|
>>> .db-uploader-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="dbloader-container">
|
<div id="dbloader-container">
|
||||||
<db-upload type="illustrated" />
|
<db-uploader type="illustrated" />
|
||||||
<div id="note">
|
<div id="note">
|
||||||
Sqliteviz is fully client-side. Your database never leaves your computer.
|
Sqliteviz is fully client-side. Your database never leaves your computer.
|
||||||
</div>
|
</div>
|
||||||
@@ -11,11 +11,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import dbUpload from '@/components/DbUpload'
|
import DbUploader from '@/components/DbUploader'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
components: { dbUpload }
|
components: { DbUploader }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ import TextField from '@/components/TextField'
|
|||||||
import CheckBox from '@/components/CheckBox'
|
import CheckBox from '@/components/CheckBox'
|
||||||
import tooltipMixin from '@/mixins/tooltips'
|
import tooltipMixin from '@/mixins/tooltips'
|
||||||
import storedQueries from '@/storedQueries'
|
import storedQueries from '@/storedQueries'
|
||||||
import fu from '@/fileUtils'
|
import fu from '@/file.utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MyQueries',
|
name: 'MyQueries',
|
||||||
|
|||||||
293
tests/components/DbUploader.spec.js
Normal file
293
tests/components/DbUploader.spec.js
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
import { expect } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import { shallowMount, mount } from '@vue/test-utils'
|
||||||
|
import DbUploader from '@/components/DbUploader.vue'
|
||||||
|
import fu from '@/file.utils'
|
||||||
|
import database from '@/database.js'
|
||||||
|
import csv from '@/csv'
|
||||||
|
|
||||||
|
let state = {}
|
||||||
|
let mutations = {}
|
||||||
|
let store = {}
|
||||||
|
|
||||||
|
describe('DbUploader.vue', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// mock store state and mutations
|
||||||
|
state = {}
|
||||||
|
mutations = {
|
||||||
|
saveSchema: sinon.stub()
|
||||||
|
}
|
||||||
|
store = new Vuex.Store({ state, mutations })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
sinon.restore()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('loads db on click and redirects to /editor', async () => {
|
||||||
|
// mock getting a file from user
|
||||||
|
const file = {}
|
||||||
|
sinon.stub(fu, 'getFileFromUser').resolves(file)
|
||||||
|
|
||||||
|
// mock db loading
|
||||||
|
const schema = {}
|
||||||
|
const db = {
|
||||||
|
loadDb: sinon.stub().resolves(schema)
|
||||||
|
}
|
||||||
|
sinon.stub(database, 'getNewDatabase').returns(db)
|
||||||
|
|
||||||
|
// mock router
|
||||||
|
const $router = { push: sinon.stub() }
|
||||||
|
const $route = { path: '/' }
|
||||||
|
|
||||||
|
// mount the component
|
||||||
|
const wrapper = shallowMount(DbUploader, {
|
||||||
|
store,
|
||||||
|
mocks: { $router, $route }
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.find('.drop-area').trigger('click')
|
||||||
|
expect(db.loadDb.calledOnceWith(file)).to.equal(true)
|
||||||
|
await db.loadDb.returnValues[0]
|
||||||
|
expect(mutations.saveSchema.calledOnceWith(state, schema)).to.equal(true)
|
||||||
|
expect($router.push.calledOnceWith('/editor')).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('loads db on drop and redirects to /editor', async () => {
|
||||||
|
// mock db loading
|
||||||
|
const schema = {}
|
||||||
|
const db = {
|
||||||
|
loadDb: sinon.stub().resolves(schema)
|
||||||
|
}
|
||||||
|
sinon.stub(database, 'getNewDatabase').returns(db)
|
||||||
|
|
||||||
|
// mock router
|
||||||
|
const $router = { push: sinon.stub() }
|
||||||
|
const $route = { path: '/' }
|
||||||
|
|
||||||
|
// mount the component
|
||||||
|
const wrapper = shallowMount(DbUploader, {
|
||||||
|
store,
|
||||||
|
mocks: { $router, $route }
|
||||||
|
})
|
||||||
|
|
||||||
|
// mock a file dropped by a user
|
||||||
|
const file = {}
|
||||||
|
const dropData = { dataTransfer: new DataTransfer() }
|
||||||
|
Object.defineProperty(dropData.dataTransfer, 'files', {
|
||||||
|
value: [file],
|
||||||
|
writable: false
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.find('.drop-area').trigger('drop', dropData)
|
||||||
|
expect(db.loadDb.calledOnceWith(file)).to.equal(true)
|
||||||
|
await db.loadDb.returnValues[0]
|
||||||
|
expect(mutations.saveSchema.calledOnceWith(state, schema)).to.equal(true)
|
||||||
|
expect($router.push.calledOnceWith('/editor')).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("doesn't redirect if already on /editor", async () => {
|
||||||
|
// mock getting a file from user
|
||||||
|
const file = {}
|
||||||
|
sinon.stub(fu, 'getFileFromUser').resolves(file)
|
||||||
|
|
||||||
|
// mock db loading
|
||||||
|
const schema = {}
|
||||||
|
const db = {
|
||||||
|
loadDb: sinon.stub().resolves(schema)
|
||||||
|
}
|
||||||
|
sinon.stub(database, 'getNewDatabase').returns(db)
|
||||||
|
|
||||||
|
// mock router
|
||||||
|
const $router = { push: sinon.stub() }
|
||||||
|
const $route = { path: '/editor' }
|
||||||
|
|
||||||
|
// mount the component
|
||||||
|
const wrapper = shallowMount(DbUploader, {
|
||||||
|
store,
|
||||||
|
mocks: { $router, $route }
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.find('.drop-area').trigger('click')
|
||||||
|
await db.loadDb.returnValues[0]
|
||||||
|
expect($router.push.called).to.equal(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows parse dialog if gets csv file', async () => {
|
||||||
|
// mock getting a file from user
|
||||||
|
const file = { type: 'text/csv' }
|
||||||
|
sinon.stub(fu, 'getFileFromUser').resolves(file)
|
||||||
|
|
||||||
|
// mock router
|
||||||
|
const $router = { push: sinon.stub() }
|
||||||
|
const $route = { path: '/editor' }
|
||||||
|
|
||||||
|
sinon.stub(csv, 'parse').resolves({
|
||||||
|
delimiter: '|',
|
||||||
|
data: {
|
||||||
|
columns: ['col1', 'col2'],
|
||||||
|
values: [
|
||||||
|
[1, 'foo'],
|
||||||
|
[2, 'bar']
|
||||||
|
]
|
||||||
|
},
|
||||||
|
messages: [{
|
||||||
|
code: 'UndetectableDelimiter',
|
||||||
|
message: 'Comma was used as a standart delimiter',
|
||||||
|
row: 0,
|
||||||
|
type: 'info',
|
||||||
|
hint: undefined
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
// mount the component
|
||||||
|
const wrapper = mount(DbUploader, {
|
||||||
|
store,
|
||||||
|
mocks: { $router, $route }
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.find('.drop-area').trigger('click')
|
||||||
|
await csv.parse.returnValues[0]
|
||||||
|
await wrapper.vm.animationPromise
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.find('[data-modal="parse"]').exists()).to.equal(true)
|
||||||
|
expect(wrapper.findComponent({ name: 'delimiter-selector' }).vm.value).to.equal('|')
|
||||||
|
expect(wrapper.find('#quote-char input').element.value).to.equal('"')
|
||||||
|
expect(wrapper.find('#escape-char input').element.value).to.equal('"')
|
||||||
|
expect(wrapper.findComponent({ name: 'check-box' }).vm.checked).to.equal(true)
|
||||||
|
const rows = wrapper.findAll('tbody tr')
|
||||||
|
expect(rows).to.have.lengthOf(2)
|
||||||
|
expect(rows.at(0).findAll('td').at(0).text()).to.equal('1')
|
||||||
|
expect(rows.at(0).findAll('td').at(1).text()).to.equal('foo')
|
||||||
|
expect(rows.at(1).findAll('td').at(0).text()).to.equal('2')
|
||||||
|
expect(rows.at(1).findAll('td').at(1).text()).to.equal('bar')
|
||||||
|
expect(wrapper.findComponent({ name: 'logs' }).text())
|
||||||
|
.to.include('Information about row 0. Comma was used as a standart delimiter.')
|
||||||
|
expect(wrapper.findComponent({ name: 'logs' }).text())
|
||||||
|
.to.include('Preview parsing is completed in')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('reparses when parameters changes', async () => {
|
||||||
|
// mock getting a file from user
|
||||||
|
const file = { type: 'text/csv' }
|
||||||
|
sinon.stub(fu, 'getFileFromUser').resolves(file)
|
||||||
|
|
||||||
|
// mock router
|
||||||
|
const $router = { push: sinon.stub() }
|
||||||
|
const $route = { path: '/editor' }
|
||||||
|
|
||||||
|
const parse = sinon.stub(csv, 'parse')
|
||||||
|
parse.onCall(0).resolves({
|
||||||
|
delimiter: '|',
|
||||||
|
data: {
|
||||||
|
columns: ['col1', 'col2'],
|
||||||
|
values: [
|
||||||
|
[1, 'foo']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// mount the component
|
||||||
|
const wrapper = mount(DbUploader, {
|
||||||
|
store,
|
||||||
|
mocks: { $router, $route }
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.find('.drop-area').trigger('click')
|
||||||
|
await csv.parse.returnValues[0]
|
||||||
|
await wrapper.vm.animationPromise
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
|
||||||
|
parse.onCall(1).resolves({
|
||||||
|
delimiter: ',',
|
||||||
|
data: {
|
||||||
|
columns: ['col1', 'col2'],
|
||||||
|
values: [
|
||||||
|
[2, 'bar']
|
||||||
|
]
|
||||||
|
},
|
||||||
|
hasErrors: false
|
||||||
|
})
|
||||||
|
await wrapper.find('.delimiter-selector-container input').setValue(',')
|
||||||
|
expect(parse.callCount).to.equal(2)
|
||||||
|
await csv.parse.returnValues[1]
|
||||||
|
|
||||||
|
let rows = wrapper.findAll('tbody tr')
|
||||||
|
expect(rows).to.have.lengthOf(1)
|
||||||
|
expect(rows.at(0).findAll('td').at(0).text()).to.equal('2')
|
||||||
|
expect(rows.at(0).findAll('td').at(1).text()).to.equal('bar')
|
||||||
|
expect(wrapper.findComponent({ name: 'logs' }).text())
|
||||||
|
.to.include('Preview parsing is completed in')
|
||||||
|
|
||||||
|
parse.onCall(2).resolves({
|
||||||
|
delimiter: ',',
|
||||||
|
data: {
|
||||||
|
columns: ['col1', 'col2'],
|
||||||
|
values: [
|
||||||
|
[3, 'baz']
|
||||||
|
]
|
||||||
|
},
|
||||||
|
hasErrors: true,
|
||||||
|
messages: [{
|
||||||
|
code: 'MissingQuotes',
|
||||||
|
message: 'Quote is missed',
|
||||||
|
row: 0,
|
||||||
|
type: 'error',
|
||||||
|
hint: 'Edit your CSV so that the field has a closing quote char.'
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.find('#quote-char input').setValue("'")
|
||||||
|
expect(parse.callCount).to.equal(3)
|
||||||
|
await csv.parse.returnValues[2]
|
||||||
|
rows = wrapper.findAll('tbody tr')
|
||||||
|
expect(rows).to.have.lengthOf(1)
|
||||||
|
expect(rows.at(0).findAll('td').at(0).text()).to.equal('3')
|
||||||
|
expect(rows.at(0).findAll('td').at(1).text()).to.equal('baz')
|
||||||
|
expect(wrapper.findComponent({ name: 'logs' }).text())
|
||||||
|
.to.contain('Error in row 0. Quote is missed. Edit your CSV so that the field has a closing quote char.')
|
||||||
|
expect(wrapper.findComponent({ name: 'logs' }).text())
|
||||||
|
.to.not.contain('Preview parsing is completed in')
|
||||||
|
|
||||||
|
parse.onCall(3).resolves({
|
||||||
|
delimiter: ',',
|
||||||
|
data: {
|
||||||
|
columns: ['col1', 'col2'],
|
||||||
|
values: [
|
||||||
|
[4, 'qux']
|
||||||
|
]
|
||||||
|
},
|
||||||
|
hasErrors: false
|
||||||
|
})
|
||||||
|
await wrapper.find('#escape-char input').setValue("'")
|
||||||
|
expect(parse.callCount).to.equal(4)
|
||||||
|
await csv.parse.returnValues[3]
|
||||||
|
rows = wrapper.findAll('tbody tr')
|
||||||
|
expect(rows).to.have.lengthOf(1)
|
||||||
|
expect(rows.at(0).findAll('td').at(0).text()).to.equal('4')
|
||||||
|
expect(rows.at(0).findAll('td').at(1).text()).to.equal('qux')
|
||||||
|
expect(wrapper.findComponent({ name: 'logs' }).text())
|
||||||
|
.to.contain('Preview parsing is completed in')
|
||||||
|
|
||||||
|
parse.onCall(4).resolves({
|
||||||
|
delimiter: ',',
|
||||||
|
data: {
|
||||||
|
columns: ['col1', 'col2'],
|
||||||
|
values: [
|
||||||
|
[5, 'corge']
|
||||||
|
]
|
||||||
|
},
|
||||||
|
hasErrors: false
|
||||||
|
})
|
||||||
|
await wrapper.findComponent({ name: 'check-box' }).trigger('click')
|
||||||
|
expect(parse.callCount).to.equal(5)
|
||||||
|
await csv.parse.returnValues[4]
|
||||||
|
rows = wrapper.findAll('tbody tr')
|
||||||
|
expect(rows).to.have.lengthOf(1)
|
||||||
|
expect(rows.at(0).findAll('td').at(0).text()).to.equal('5')
|
||||||
|
expect(rows.at(0).findAll('td').at(1).text()).to.equal('corge')
|
||||||
|
expect(wrapper.findComponent({ name: 'logs' }).text())
|
||||||
|
.to.include('Preview parsing is completed in')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import dbUtils from '@/dbUtils'
|
import dbUtils from '@/db.utils'
|
||||||
|
|
||||||
describe('dbUtils.js', () => {
|
describe('db.utils.js', () => {
|
||||||
it('generateChunks', () => {
|
it('generateChunks', () => {
|
||||||
const arr = ['1', '2', '3', '4', '5']
|
const arr = ['1', '2', '3', '4', '5']
|
||||||
const size = 2
|
const size = 2
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import fu from '@/fileUtils.js'
|
import fu from '@/file.utils'
|
||||||
import sinon from 'sinon'
|
import sinon from 'sinon'
|
||||||
|
|
||||||
describe('fileUtils.js', () => {
|
describe('file.utils.js', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
sinon.restore()
|
sinon.restore()
|
||||||
})
|
})
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import sinon from 'sinon'
|
import sinon from 'sinon'
|
||||||
import storedQueries from '@/storedQueries.js'
|
import storedQueries from '@/storedQueries.js'
|
||||||
import fu from '@/fileUtils'
|
import fu from '@/file.utils'
|
||||||
|
|
||||||
describe('storedQueries.js', () => {
|
describe('storedQueries.js', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
import { expect } from 'chai'
|
|
||||||
import sinon from 'sinon'
|
|
||||||
import Vuex from 'vuex'
|
|
||||||
import { shallowMount } from '@vue/test-utils'
|
|
||||||
import DbUpload from '@/components/DbUpload.vue'
|
|
||||||
import fu from '@/fileUtils'
|
|
||||||
import database from '@/database.js'
|
|
||||||
|
|
||||||
describe('DbUploader.vue', () => {
|
|
||||||
afterEach(() => {
|
|
||||||
sinon.restore()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('loads db on click and redirects to /editor', async () => {
|
|
||||||
// mock store state and mutations
|
|
||||||
const state = {}
|
|
||||||
const mutations = {
|
|
||||||
saveSchema: sinon.stub()
|
|
||||||
}
|
|
||||||
const store = new Vuex.Store({ state, mutations })
|
|
||||||
|
|
||||||
// mock getting a file from user
|
|
||||||
const file = {}
|
|
||||||
sinon.stub(fu, 'getFileFromUser').resolves(file)
|
|
||||||
|
|
||||||
// mock db loading
|
|
||||||
const schema = {}
|
|
||||||
const db = {
|
|
||||||
loadDb: sinon.stub().resolves(schema)
|
|
||||||
}
|
|
||||||
sinon.stub(database, 'getNewDatabase').returns(db)
|
|
||||||
|
|
||||||
// mock router
|
|
||||||
const $router = { push: sinon.stub() }
|
|
||||||
const $route = { path: '/' }
|
|
||||||
|
|
||||||
// mount the component
|
|
||||||
const wrapper = shallowMount(DbUpload, {
|
|
||||||
store,
|
|
||||||
mocks: { $router, $route }
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.find('.drop-area').trigger('click')
|
|
||||||
expect(db.loadDb.calledOnceWith(file)).to.equal(true)
|
|
||||||
await db.loadDb.returnValues[0]
|
|
||||||
expect(mutations.saveSchema.calledOnceWith(state, schema)).to.equal(true)
|
|
||||||
expect($router.push.calledOnceWith('/editor')).to.equal(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('loads db on drop and redirects to /editor', async () => {
|
|
||||||
// mock store state and mutations
|
|
||||||
const state = {}
|
|
||||||
const mutations = {
|
|
||||||
saveSchema: sinon.stub()
|
|
||||||
}
|
|
||||||
const store = new Vuex.Store({ state, mutations })
|
|
||||||
|
|
||||||
// mock db loading
|
|
||||||
const schema = {}
|
|
||||||
const db = {
|
|
||||||
loadDb: sinon.stub().resolves(schema)
|
|
||||||
}
|
|
||||||
sinon.stub(database, 'getNewDatabase').returns(db)
|
|
||||||
|
|
||||||
// mock router
|
|
||||||
const $router = { push: sinon.stub() }
|
|
||||||
const $route = { path: '/' }
|
|
||||||
|
|
||||||
// mount the component
|
|
||||||
const wrapper = shallowMount(DbUpload, {
|
|
||||||
store,
|
|
||||||
mocks: { $router, $route }
|
|
||||||
})
|
|
||||||
|
|
||||||
// mock a file dropped by a user
|
|
||||||
const file = {}
|
|
||||||
const dropData = { dataTransfer: new DataTransfer() }
|
|
||||||
Object.defineProperty(dropData.dataTransfer, 'files', {
|
|
||||||
value: [file],
|
|
||||||
writable: false
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.find('.drop-area').trigger('drop', dropData)
|
|
||||||
expect(db.loadDb.calledOnceWith(file)).to.equal(true)
|
|
||||||
await db.loadDb.returnValues[0]
|
|
||||||
expect(mutations.saveSchema.calledOnceWith(state, schema)).to.equal(true)
|
|
||||||
expect($router.push.calledOnceWith('/editor')).to.equal(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("doesn't redirect if already on /editor", async () => {
|
|
||||||
// mock store state and mutations
|
|
||||||
const state = {}
|
|
||||||
const mutations = {
|
|
||||||
saveSchema: sinon.stub()
|
|
||||||
}
|
|
||||||
const store = new Vuex.Store({ state, mutations })
|
|
||||||
|
|
||||||
// mock getting a file from user
|
|
||||||
const file = {}
|
|
||||||
sinon.stub(fu, 'getFileFromUser').resolves(file)
|
|
||||||
|
|
||||||
// mock db loading
|
|
||||||
const schema = {}
|
|
||||||
const db = {
|
|
||||||
loadDb: sinon.stub().resolves(schema)
|
|
||||||
}
|
|
||||||
sinon.stub(database, 'getNewDatabase').returns(db)
|
|
||||||
|
|
||||||
// mock router
|
|
||||||
const $router = { push: sinon.stub() }
|
|
||||||
const $route = { path: '/editor' }
|
|
||||||
|
|
||||||
// mount the component
|
|
||||||
const wrapper = shallowMount(DbUpload, {
|
|
||||||
store,
|
|
||||||
mocks: { $router, $route }
|
|
||||||
})
|
|
||||||
|
|
||||||
await wrapper.find('.drop-area').trigger('click')
|
|
||||||
await db.loadDb.returnValues[0]
|
|
||||||
expect($router.push.called).to.equal(false)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -3,9 +3,9 @@ import sinon from 'sinon'
|
|||||||
import { mount, shallowMount } from '@vue/test-utils'
|
import { mount, shallowMount } from '@vue/test-utils'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import MyQueries from '@/views/MyQueries.vue'
|
import MyQueries from '@/views/MyQueries.vue'
|
||||||
import storedQueries from '@/storedQueries.js'
|
import storedQueries from '@/storedQueries'
|
||||||
import { mutations } from '@/store'
|
import { mutations } from '@/store'
|
||||||
import fu from '@/fileUtils.js'
|
import fu from '@/file.utils'
|
||||||
|
|
||||||
describe('MyQueries.vue', () => {
|
describe('MyQueries.vue', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
Reference in New Issue
Block a user