first commit
This commit is contained in:
8
test/unit/.eslintrc
Normal file
8
test/unit/.eslintrc
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"env": {
|
||||
"jest": true
|
||||
},
|
||||
"extends": [
|
||||
"../../.eslintrc.js"
|
||||
]
|
||||
}
|
||||
33
test/unit/jest.conf.js
Normal file
33
test/unit/jest.conf.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
rootDir: path.resolve(__dirname, '../../'),
|
||||
moduleFileExtensions: [
|
||||
'js',
|
||||
'json',
|
||||
'vue',
|
||||
],
|
||||
moduleNameMapper: {
|
||||
'\\.(css|scss)$': 'identity-obj-proxy',
|
||||
'^!raw-loader!': 'identity-obj-proxy',
|
||||
'^worker-loader!\\./templateWorker\\.js$': '<rootDir>/test/unit/mocks/templateWorkerMock',
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
|
||||
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest',
|
||||
'.*\\.(yml|html|md)$': 'jest-raw-loader',
|
||||
},
|
||||
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
|
||||
setupFiles: [
|
||||
'<rootDir>/test/unit/setup',
|
||||
],
|
||||
coverageDirectory: '<rootDir>/test/unit/coverage',
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.{js,vue}',
|
||||
'!src/main.js',
|
||||
'!**/node_modules/**',
|
||||
],
|
||||
globals: {
|
||||
NODE_ENV: 'production',
|
||||
},
|
||||
};
|
||||
7
test/unit/mocks/cryptoMock.js
Normal file
7
test/unit/mocks/cryptoMock.js
Normal file
@@ -0,0 +1,7 @@
|
||||
window.crypto = {
|
||||
getRandomValues(array) {
|
||||
for (let i = 0; i < array.length; i += 1) {
|
||||
array[i] = Math.floor(Math.random() * 1000000);
|
||||
}
|
||||
},
|
||||
};
|
||||
9
test/unit/mocks/localStorageMock.js
Normal file
9
test/unit/mocks/localStorageMock.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const store = {};
|
||||
window.localStorage = {
|
||||
getItem(key) {
|
||||
return store[key] || null;
|
||||
},
|
||||
setItem(key, value) {
|
||||
store[key] = value.toString();
|
||||
},
|
||||
};
|
||||
6
test/unit/mocks/mutationObserverMock.js
Normal file
6
test/unit/mocks/mutationObserverMock.js
Normal file
@@ -0,0 +1,6 @@
|
||||
/* eslint-disable class-methods-use-this */
|
||||
class MutationObserver {
|
||||
observe() {
|
||||
}
|
||||
}
|
||||
window.MutationObserver = MutationObserver;
|
||||
1
test/unit/mocks/templateWorkerMock.js
Normal file
1
test/unit/mocks/templateWorkerMock.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = 'test-file-stub';
|
||||
5
test/unit/setup.js
Normal file
5
test/unit/setup.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import Vue from 'vue';
|
||||
import './mocks/cryptoMock';
|
||||
import './mocks/mutationObserverMock';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
47
test/unit/specs/components/ButtonBar.spec.js
Normal file
47
test/unit/specs/components/ButtonBar.spec.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import ButtonBar from '../../../../src/components/ButtonBar';
|
||||
import store from '../../../../src/store';
|
||||
import specUtils from '../specUtils';
|
||||
|
||||
describe('ButtonBar.vue', () => {
|
||||
it('should toggle the navigation bar', async () => specUtils.checkToggler(
|
||||
ButtonBar,
|
||||
wrapper => wrapper.find('.button-bar__button--navigation-bar-toggler').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].showNavigationBar,
|
||||
'toggleNavigationBar',
|
||||
));
|
||||
|
||||
it('should toggle the side preview', async () => specUtils.checkToggler(
|
||||
ButtonBar,
|
||||
wrapper => wrapper.find('.button-bar__button--side-preview-toggler').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].showSidePreview,
|
||||
'toggleSidePreview',
|
||||
));
|
||||
|
||||
it('should toggle the editor', async () => specUtils.checkToggler(
|
||||
ButtonBar,
|
||||
wrapper => wrapper.find('.button-bar__button--editor-toggler').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].showEditor,
|
||||
'toggleEditor',
|
||||
));
|
||||
|
||||
it('should toggle the focus mode', async () => specUtils.checkToggler(
|
||||
ButtonBar,
|
||||
wrapper => wrapper.find('.button-bar__button--focus-mode-toggler').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].focusMode,
|
||||
'toggleFocusMode',
|
||||
));
|
||||
|
||||
it('should toggle the scroll sync', async () => specUtils.checkToggler(
|
||||
ButtonBar,
|
||||
wrapper => wrapper.find('.button-bar__button--scroll-sync-toggler').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].scrollSync,
|
||||
'toggleScrollSync',
|
||||
));
|
||||
|
||||
it('should toggle the status bar', async () => specUtils.checkToggler(
|
||||
ButtonBar,
|
||||
wrapper => wrapper.find('.button-bar__button--status-bar-toggler').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].showStatusBar,
|
||||
'toggleStatusBar',
|
||||
));
|
||||
});
|
||||
32
test/unit/specs/components/ContextMenu.spec.js
Normal file
32
test/unit/specs/components/ContextMenu.spec.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import ContextMenu from '../../../../src/components/ContextMenu';
|
||||
import store from '../../../../src/store';
|
||||
import '../specUtils';
|
||||
|
||||
const mount = () => shallowMount(ContextMenu, { store });
|
||||
|
||||
describe('ContextMenu.vue', () => {
|
||||
const name = 'Name';
|
||||
const makeOptions = () => ({
|
||||
coordinates: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
items: [{ name }],
|
||||
});
|
||||
|
||||
it('should open/close itself', async () => {
|
||||
const wrapper = mount();
|
||||
expect(wrapper.contains('.context-menu__item')).toEqual(false);
|
||||
setTimeout(() => wrapper.find('.context-menu__item').trigger('click'), 1);
|
||||
const item = await store.dispatch('contextMenu/open', makeOptions());
|
||||
expect(item.name).toEqual(name);
|
||||
});
|
||||
|
||||
it('should cancel itself', async () => {
|
||||
const wrapper = mount();
|
||||
setTimeout(() => wrapper.trigger('click'), 1);
|
||||
const item = await store.dispatch('contextMenu/open', makeOptions());
|
||||
expect(item).toEqual(null);
|
||||
});
|
||||
});
|
||||
194
test/unit/specs/components/Explorer.spec.js
Normal file
194
test/unit/specs/components/Explorer.spec.js
Normal file
@@ -0,0 +1,194 @@
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Explorer from '../../../../src/components/Explorer';
|
||||
import store from '../../../../src/store';
|
||||
import workspaceSvc from '../../../../src/services/workspaceSvc';
|
||||
import specUtils from '../specUtils';
|
||||
|
||||
const mount = () => shallowMount(Explorer, { store });
|
||||
const select = (id) => {
|
||||
store.commit('explorer/setSelectedId', id);
|
||||
expect(store.getters['explorer/selectedNode'].item.id).toEqual(id);
|
||||
};
|
||||
const ensureExists = file => expect(store.getters.allItemsById).toHaveProperty(file.id);
|
||||
const ensureNotExists = file => expect(store.getters.allItemsById).not.toHaveProperty(file.id);
|
||||
const refreshItem = item => store.getters.allItemsById[item.id];
|
||||
|
||||
describe('Explorer.vue', () => {
|
||||
it('should create new file in the root folder', async () => {
|
||||
expect(store.state.explorer.newChildNode.isNil).toBeTruthy();
|
||||
const wrapper = mount();
|
||||
wrapper.find('.side-title__button--new-file').trigger('click');
|
||||
expect(store.state.explorer.newChildNode.isNil).toBeFalsy();
|
||||
expect(store.state.explorer.newChildNode.item).toMatchObject({
|
||||
type: 'file',
|
||||
parentId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create new file in a folder', async () => {
|
||||
const folder = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
const wrapper = mount();
|
||||
select(folder.id);
|
||||
wrapper.find('.side-title__button--new-file').trigger('click');
|
||||
expect(store.state.explorer.newChildNode.item).toMatchObject({
|
||||
type: 'file',
|
||||
parentId: folder.id,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not create new files in the trash folder', async () => {
|
||||
const wrapper = mount();
|
||||
select('trash');
|
||||
wrapper.find('.side-title__button--new-file').trigger('click');
|
||||
expect(store.state.explorer.newChildNode.item).toMatchObject({
|
||||
type: 'file',
|
||||
parentId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create new folders in the root folder', async () => {
|
||||
expect(store.state.explorer.newChildNode.isNil).toBeTruthy();
|
||||
const wrapper = mount();
|
||||
wrapper.find('.side-title__button--new-folder').trigger('click');
|
||||
expect(store.state.explorer.newChildNode.isNil).toBeFalsy();
|
||||
expect(store.state.explorer.newChildNode.item).toMatchObject({
|
||||
type: 'folder',
|
||||
parentId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create new folders in a folder', async () => {
|
||||
const folder = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
const wrapper = mount();
|
||||
select(folder.id);
|
||||
wrapper.find('.side-title__button--new-folder').trigger('click');
|
||||
expect(store.state.explorer.newChildNode.item).toMatchObject({
|
||||
type: 'folder',
|
||||
parentId: folder.id,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not create new folders in the trash folder', async () => {
|
||||
const wrapper = mount();
|
||||
select('trash');
|
||||
wrapper.find('.side-title__button--new-folder').trigger('click');
|
||||
expect(store.state.explorer.newChildNode.item).toMatchObject({
|
||||
type: 'folder',
|
||||
parentId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not create new folders in the temp folder', async () => {
|
||||
const wrapper = mount();
|
||||
select('temp');
|
||||
wrapper.find('.side-title__button--new-folder').trigger('click');
|
||||
expect(store.state.explorer.newChildNode.item).toMatchObject({
|
||||
type: 'folder',
|
||||
parentId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('should move file to the trash folder on delete', async () => {
|
||||
const file = await workspaceSvc.createFile({}, true);
|
||||
expect(file.parentId).toEqual(null);
|
||||
const wrapper = mount();
|
||||
select(file.id);
|
||||
wrapper.find('.side-title__button--delete').trigger('click');
|
||||
ensureExists(file);
|
||||
expect(refreshItem(file).parentId).toEqual('trash');
|
||||
await specUtils.expectBadge('removeFile');
|
||||
});
|
||||
|
||||
it('should not delete the trash folder', async () => {
|
||||
const wrapper = mount();
|
||||
select('trash');
|
||||
wrapper.find('.side-title__button--delete').trigger('click');
|
||||
await specUtils.resolveModal('trashDeletion');
|
||||
await specUtils.expectBadge('removeFile', false);
|
||||
});
|
||||
|
||||
it('should not delete file in the trash folder', async () => {
|
||||
const file = await workspaceSvc.createFile({ parentId: 'trash' }, true);
|
||||
const wrapper = mount();
|
||||
select(file.id);
|
||||
wrapper.find('.side-title__button--delete').trigger('click');
|
||||
await specUtils.resolveModal('trashDeletion');
|
||||
ensureExists(file);
|
||||
await specUtils.expectBadge('removeFile', false);
|
||||
});
|
||||
|
||||
it('should delete the temp folder after confirmation', async () => {
|
||||
const file = await workspaceSvc.createFile({ parentId: 'temp' }, true);
|
||||
const wrapper = mount();
|
||||
select('temp');
|
||||
wrapper.find('.side-title__button--delete').trigger('click');
|
||||
await specUtils.resolveModal('tempFolderDeletion');
|
||||
ensureNotExists(file);
|
||||
await specUtils.expectBadge('removeFolder');
|
||||
});
|
||||
|
||||
it('should delete temp file after confirmation', async () => {
|
||||
const file = await workspaceSvc.createFile({ parentId: 'temp' }, true);
|
||||
const wrapper = mount();
|
||||
select(file.id);
|
||||
wrapper.find('.side-title__button--delete').trigger('click');
|
||||
ensureExists(file);
|
||||
await specUtils.resolveModal('tempFileDeletion');
|
||||
ensureNotExists(file);
|
||||
await specUtils.expectBadge('removeFile');
|
||||
});
|
||||
|
||||
it('should delete folder after confirmation', async () => {
|
||||
const folder = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
const file = await workspaceSvc.createFile({ parentId: folder.id }, true);
|
||||
const wrapper = mount();
|
||||
select(folder.id);
|
||||
wrapper.find('.side-title__button--delete').trigger('click');
|
||||
await specUtils.resolveModal('folderDeletion');
|
||||
ensureNotExists(folder);
|
||||
// Make sure file has been moved to Trash
|
||||
ensureExists(file);
|
||||
expect(refreshItem(file).parentId).toEqual('trash');
|
||||
await specUtils.expectBadge('removeFolder');
|
||||
});
|
||||
|
||||
it('should rename file', async () => {
|
||||
const file = await workspaceSvc.createFile({}, true);
|
||||
const wrapper = mount();
|
||||
select(file.id);
|
||||
wrapper.find('.side-title__button--rename').trigger('click');
|
||||
expect(store.getters['explorer/editingNode'].item.id).toEqual(file.id);
|
||||
});
|
||||
|
||||
it('should rename folder', async () => {
|
||||
const folder = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
const wrapper = mount();
|
||||
select(folder.id);
|
||||
wrapper.find('.side-title__button--rename').trigger('click');
|
||||
expect(store.getters['explorer/editingNode'].item.id).toEqual(folder.id);
|
||||
});
|
||||
|
||||
it('should not rename the trash folder', async () => {
|
||||
const wrapper = mount();
|
||||
select('trash');
|
||||
wrapper.find('.side-title__button--rename').trigger('click');
|
||||
expect(store.getters['explorer/editingNode'].isNil).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not rename the temp folder', async () => {
|
||||
const wrapper = mount();
|
||||
select('temp');
|
||||
wrapper.find('.side-title__button--rename').trigger('click');
|
||||
expect(store.getters['explorer/editingNode'].isNil).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should close itself', async () => {
|
||||
store.dispatch('data/toggleExplorer', true);
|
||||
specUtils.checkToggler(
|
||||
Explorer,
|
||||
wrapper => wrapper.find('.side-title__button--close').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].showExplorer,
|
||||
'toggleExplorer',
|
||||
);
|
||||
});
|
||||
});
|
||||
307
test/unit/specs/components/ExplorerNode.spec.js
Normal file
307
test/unit/specs/components/ExplorerNode.spec.js
Normal file
@@ -0,0 +1,307 @@
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import ExplorerNode from '../../../../src/components/ExplorerNode';
|
||||
import store from '../../../../src/store';
|
||||
import workspaceSvc from '../../../../src/services/workspaceSvc';
|
||||
import explorerSvc from '../../../../src/services/explorerSvc';
|
||||
import specUtils from '../specUtils';
|
||||
|
||||
const makeFileNode = async () => {
|
||||
const file = await workspaceSvc.createFile({}, true);
|
||||
const node = store.getters['explorer/nodeMap'][file.id];
|
||||
expect(node.item.id).toEqual(file.id);
|
||||
return node;
|
||||
};
|
||||
|
||||
const makeFolderNode = async () => {
|
||||
const folder = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
const node = store.getters['explorer/nodeMap'][folder.id];
|
||||
expect(node.item.id).toEqual(folder.id);
|
||||
return node;
|
||||
};
|
||||
|
||||
const mount = node => shallowMount(ExplorerNode, {
|
||||
store,
|
||||
propsData: { node, depth: 1 },
|
||||
});
|
||||
const mountAndSelect = (node) => {
|
||||
const wrapper = mount(node);
|
||||
wrapper.find('.explorer-node__item').trigger('click');
|
||||
expect(store.getters['explorer/selectedNode'].item.id).toEqual(node.item.id);
|
||||
expect(wrapper.classes()).toContain('explorer-node--selected');
|
||||
return wrapper;
|
||||
};
|
||||
|
||||
const dragAndDrop = (sourceItem, targetItem) => {
|
||||
const sourceNode = store.getters['explorer/nodeMap'][sourceItem.id];
|
||||
mountAndSelect(sourceNode).find('.explorer-node__item').trigger('dragstart', {
|
||||
dataTransfer: { setData: () => {} },
|
||||
});
|
||||
expect(store.state.explorer.dragSourceId).toEqual(sourceItem.id);
|
||||
const targetNode = store.getters['explorer/nodeMap'][targetItem.id];
|
||||
const wrapper = mount(targetNode);
|
||||
wrapper.trigger('dragenter');
|
||||
expect(store.state.explorer.dragTargetId).toEqual(targetItem.id);
|
||||
wrapper.trigger('drop');
|
||||
const expectedParentId = targetItem.type === 'file' ? targetItem.parentId : targetItem.id;
|
||||
expect(store.getters['explorer/selectedNode'].item.parentId).toEqual(expectedParentId);
|
||||
};
|
||||
|
||||
describe('ExplorerNode.vue', () => {
|
||||
const modifiedName = 'Name';
|
||||
|
||||
it('should open file on select after a timeout', async () => {
|
||||
const node = await makeFileNode();
|
||||
mountAndSelect(node);
|
||||
expect(store.getters['file/current'].id).not.toEqual(node.item.id);
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
expect(store.getters['file/current'].id).toEqual(node.item.id);
|
||||
await specUtils.expectBadge('switchFile');
|
||||
});
|
||||
|
||||
it('should not open already open file', async () => {
|
||||
const node = await makeFileNode();
|
||||
store.commit('file/setCurrentId', node.item.id);
|
||||
mountAndSelect(node);
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
expect(store.getters['file/current'].id).toEqual(node.item.id);
|
||||
await specUtils.expectBadge('switchFile', false);
|
||||
});
|
||||
|
||||
it('should open folder on select after a timeout', async () => {
|
||||
const node = await makeFolderNode();
|
||||
const wrapper = mountAndSelect(node);
|
||||
expect(wrapper.classes()).not.toContain('explorer-node--open');
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
expect(wrapper.classes()).toContain('explorer-node--open');
|
||||
});
|
||||
|
||||
it('should open folder on new child', async () => {
|
||||
const node = await makeFolderNode();
|
||||
const wrapper = mountAndSelect(node);
|
||||
// Close the folder
|
||||
wrapper.find('.explorer-node__item').trigger('click');
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
expect(wrapper.classes()).not.toContain('explorer-node--open');
|
||||
explorerSvc.newItem();
|
||||
expect(wrapper.classes()).toContain('explorer-node--open');
|
||||
});
|
||||
|
||||
it('should create new file in a folder', async () => {
|
||||
const node = await makeFolderNode();
|
||||
const wrapper = mount(node);
|
||||
wrapper.trigger('contextmenu');
|
||||
await specUtils.resolveContextMenu('New file');
|
||||
expect(wrapper.contains('.explorer-node__new-child')).toBe(true);
|
||||
store.commit('explorer/setNewItemName', modifiedName);
|
||||
wrapper.find('.explorer-node__new-child .text-input').trigger('blur');
|
||||
await new Promise(resolve => setTimeout(resolve, 1));
|
||||
expect(store.getters['explorer/selectedNode'].item).toMatchObject({
|
||||
name: modifiedName,
|
||||
type: 'file',
|
||||
parentId: node.item.id,
|
||||
});
|
||||
expect(wrapper.contains('.explorer-node__new-child')).toBe(false);
|
||||
await specUtils.expectBadge('createFile');
|
||||
});
|
||||
|
||||
it('should cancel file creation on escape', async () => {
|
||||
const node = await makeFolderNode();
|
||||
const wrapper = mount(node);
|
||||
wrapper.trigger('contextmenu');
|
||||
await specUtils.resolveContextMenu('New file');
|
||||
expect(wrapper.contains('.explorer-node__new-child')).toBe(true);
|
||||
store.commit('explorer/setNewItemName', modifiedName);
|
||||
wrapper.find('.explorer-node__new-child .text-input').trigger('keydown', {
|
||||
keyCode: 27,
|
||||
});
|
||||
await new Promise(resolve => setTimeout(resolve, 1));
|
||||
expect(store.getters['explorer/selectedNode'].item).not.toMatchObject({
|
||||
name: 'modifiedName',
|
||||
type: 'file',
|
||||
parentId: node.item.id,
|
||||
});
|
||||
expect(wrapper.contains('.explorer-node__new-child')).toBe(false);
|
||||
await specUtils.expectBadge('createFile', false);
|
||||
});
|
||||
|
||||
it('should not create new file in a file', async () => {
|
||||
const node = await makeFileNode();
|
||||
mount(node).trigger('contextmenu');
|
||||
expect(specUtils.getContextMenuItem('New file').disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not create new file in the trash folder', async () => {
|
||||
const node = store.getters['explorer/nodeMap'].trash;
|
||||
mount(node).trigger('contextmenu');
|
||||
expect(specUtils.getContextMenuItem('New file').disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should create new folder in folder', async () => {
|
||||
const node = await makeFolderNode();
|
||||
const wrapper = mount(node);
|
||||
wrapper.trigger('contextmenu');
|
||||
await specUtils.resolveContextMenu('New folder');
|
||||
expect(wrapper.contains('.explorer-node__new-child--folder')).toBe(true);
|
||||
store.commit('explorer/setNewItemName', modifiedName);
|
||||
wrapper.find('.explorer-node__new-child--folder .text-input').trigger('blur');
|
||||
await new Promise(resolve => setTimeout(resolve, 1));
|
||||
expect(store.getters['explorer/selectedNode'].item).toMatchObject({
|
||||
name: modifiedName,
|
||||
type: 'folder',
|
||||
parentId: node.item.id,
|
||||
});
|
||||
expect(wrapper.contains('.explorer-node__new-child--folder')).toBe(false);
|
||||
await specUtils.expectBadge('createFolder');
|
||||
});
|
||||
|
||||
it('should cancel folder creation on escape', async () => {
|
||||
const node = await makeFolderNode();
|
||||
const wrapper = mount(node);
|
||||
wrapper.trigger('contextmenu');
|
||||
await specUtils.resolveContextMenu('New folder');
|
||||
expect(wrapper.contains('.explorer-node__new-child--folder')).toBe(true);
|
||||
store.commit('explorer/setNewItemName', modifiedName);
|
||||
wrapper.find('.explorer-node__new-child--folder .text-input').trigger('keydown', {
|
||||
keyCode: 27,
|
||||
});
|
||||
await new Promise(resolve => setTimeout(resolve, 1));
|
||||
expect(store.getters['explorer/selectedNode'].item).not.toMatchObject({
|
||||
name: modifiedName,
|
||||
type: 'folder',
|
||||
parentId: node.item.id,
|
||||
});
|
||||
expect(wrapper.contains('.explorer-node__new-child--folder')).toBe(false);
|
||||
await specUtils.expectBadge('createFolder', false);
|
||||
});
|
||||
|
||||
it('should not create new folder in a file', async () => {
|
||||
const node = await makeFileNode();
|
||||
mount(node).trigger('contextmenu');
|
||||
expect(specUtils.getContextMenuItem('New folder').disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not create new folder in the trash folder', async () => {
|
||||
const node = store.getters['explorer/nodeMap'].trash;
|
||||
mount(node).trigger('contextmenu');
|
||||
expect(specUtils.getContextMenuItem('New folder').disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not create new folder in the temp folder', async () => {
|
||||
const node = store.getters['explorer/nodeMap'].temp;
|
||||
mount(node).trigger('contextmenu');
|
||||
expect(specUtils.getContextMenuItem('New folder').disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should rename file', async () => {
|
||||
const node = await makeFileNode();
|
||||
const wrapper = mount(node);
|
||||
wrapper.trigger('contextmenu');
|
||||
await specUtils.resolveContextMenu('Rename');
|
||||
expect(wrapper.contains('.explorer-node__item-editor')).toBe(true);
|
||||
wrapper.setData({ editingValue: modifiedName });
|
||||
wrapper.find('.explorer-node__item-editor .text-input').trigger('blur');
|
||||
expect(store.getters['explorer/selectedNode'].item.name).toEqual(modifiedName);
|
||||
await specUtils.expectBadge('renameFile');
|
||||
});
|
||||
|
||||
it('should cancel rename file on escape', async () => {
|
||||
const node = await makeFileNode();
|
||||
const wrapper = mount(node);
|
||||
wrapper.trigger('contextmenu');
|
||||
await specUtils.resolveContextMenu('Rename');
|
||||
expect(wrapper.contains('.explorer-node__item-editor')).toBe(true);
|
||||
wrapper.setData({ editingValue: modifiedName });
|
||||
wrapper.find('.explorer-node__item-editor .text-input').trigger('keydown', {
|
||||
keyCode: 27,
|
||||
});
|
||||
expect(store.getters['explorer/selectedNode'].item.name).not.toEqual(modifiedName);
|
||||
await specUtils.expectBadge('renameFile', false);
|
||||
});
|
||||
|
||||
it('should rename folder', async () => {
|
||||
const node = await makeFolderNode();
|
||||
const wrapper = mount(node);
|
||||
wrapper.trigger('contextmenu');
|
||||
await specUtils.resolveContextMenu('Rename');
|
||||
expect(wrapper.contains('.explorer-node__item-editor')).toBe(true);
|
||||
wrapper.setData({ editingValue: modifiedName });
|
||||
wrapper.find('.explorer-node__item-editor .text-input').trigger('blur');
|
||||
expect(store.getters['explorer/selectedNode'].item.name).toEqual(modifiedName);
|
||||
await specUtils.expectBadge('renameFolder');
|
||||
});
|
||||
|
||||
it('should cancel rename folder on escape', async () => {
|
||||
const node = await makeFolderNode();
|
||||
const wrapper = mount(node);
|
||||
wrapper.trigger('contextmenu');
|
||||
await specUtils.resolveContextMenu('Rename');
|
||||
expect(wrapper.contains('.explorer-node__item-editor')).toBe(true);
|
||||
wrapper.setData({ editingValue: modifiedName });
|
||||
wrapper.find('.explorer-node__item-editor .text-input').trigger('keydown', {
|
||||
keyCode: 27,
|
||||
});
|
||||
expect(store.getters['explorer/selectedNode'].item.name).not.toEqual(modifiedName);
|
||||
await specUtils.expectBadge('renameFolder', false);
|
||||
});
|
||||
|
||||
it('should not rename the trash folder', async () => {
|
||||
const node = store.getters['explorer/nodeMap'].trash;
|
||||
mount(node).trigger('contextmenu');
|
||||
expect(specUtils.getContextMenuItem('Rename').disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not rename the temp folder', async () => {
|
||||
const node = store.getters['explorer/nodeMap'].temp;
|
||||
mount(node).trigger('contextmenu');
|
||||
expect(specUtils.getContextMenuItem('Rename').disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should move file into a folder', async () => {
|
||||
const sourceItem = await workspaceSvc.createFile({}, true);
|
||||
const targetItem = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
dragAndDrop(sourceItem, targetItem);
|
||||
await specUtils.expectBadge('moveFile');
|
||||
});
|
||||
|
||||
it('should move folder into a folder', async () => {
|
||||
const sourceItem = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
const targetItem = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
dragAndDrop(sourceItem, targetItem);
|
||||
await specUtils.expectBadge('moveFolder');
|
||||
});
|
||||
|
||||
it('should move file into a file parent folder', async () => {
|
||||
const targetItem = await workspaceSvc.storeItem({ type: 'folder' });
|
||||
const file = await workspaceSvc.createFile({ parentId: targetItem.id }, true);
|
||||
const sourceItem = await workspaceSvc.createFile({}, true);
|
||||
dragAndDrop(sourceItem, file);
|
||||
await specUtils.expectBadge('moveFile');
|
||||
});
|
||||
|
||||
it('should not move the trash folder', async () => {
|
||||
const sourceNode = store.getters['explorer/nodeMap'].trash;
|
||||
mountAndSelect(sourceNode).find('.explorer-node__item').trigger('dragstart');
|
||||
expect(store.state.explorer.dragSourceId).not.toEqual('trash');
|
||||
});
|
||||
|
||||
it('should not move the temp folder', async () => {
|
||||
const sourceNode = store.getters['explorer/nodeMap'].temp;
|
||||
mountAndSelect(sourceNode).find('.explorer-node__item').trigger('dragstart');
|
||||
expect(store.state.explorer.dragSourceId).not.toEqual('temp');
|
||||
});
|
||||
|
||||
it('should not move file to the temp folder', async () => {
|
||||
const targetNode = store.getters['explorer/nodeMap'].temp;
|
||||
const wrapper = mount(targetNode);
|
||||
wrapper.trigger('dragenter');
|
||||
expect(store.state.explorer.dragTargetId).not.toEqual('temp');
|
||||
});
|
||||
|
||||
it('should not move file to a file in the temp folder', async () => {
|
||||
const file = await workspaceSvc.createFile({ parentId: 'temp' }, true);
|
||||
const targetNode = store.getters['explorer/nodeMap'][file.id];
|
||||
const wrapper = mount(targetNode);
|
||||
wrapper.trigger('dragenter');
|
||||
expect(store.state.explorer.dragTargetId).not.toEqual(file.id);
|
||||
});
|
||||
});
|
||||
19
test/unit/specs/components/NavigationBar.spec.js
Normal file
19
test/unit/specs/components/NavigationBar.spec.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import NavigationBar from '../../../../src/components/NavigationBar';
|
||||
import store from '../../../../src/store';
|
||||
import specUtils from '../specUtils';
|
||||
|
||||
describe('NavigationBar.vue', () => {
|
||||
it('should toggle the explorer', async () => specUtils.checkToggler(
|
||||
NavigationBar,
|
||||
wrapper => wrapper.find('.navigation-bar__button--explorer-toggler').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].showExplorer,
|
||||
'toggleExplorer',
|
||||
));
|
||||
|
||||
it('should toggle the side bar', async () => specUtils.checkToggler(
|
||||
NavigationBar,
|
||||
wrapper => wrapper.find('.navigation-bar__button--stackedit').trigger('click'),
|
||||
() => store.getters['data/layoutSettings'].showSideBar,
|
||||
'toggleSideBar',
|
||||
));
|
||||
});
|
||||
38
test/unit/specs/components/Notification.spec.js
Normal file
38
test/unit/specs/components/Notification.spec.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Notification from '../../../../src/components/Notification';
|
||||
import store from '../../../../src/store';
|
||||
import '../specUtils';
|
||||
|
||||
const mount = () => shallowMount(Notification, { store });
|
||||
|
||||
describe('Notification.vue', () => {
|
||||
it('should autoclose itself', async () => {
|
||||
const wrapper = mount();
|
||||
expect(wrapper.contains('.notification__item')).toBe(false);
|
||||
store.dispatch('notification/showItem', {
|
||||
type: 'info',
|
||||
content: 'Test',
|
||||
timeout: 10,
|
||||
});
|
||||
expect(wrapper.contains('.notification__item')).toBe(true);
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
expect(wrapper.contains('.notification__item')).toBe(false);
|
||||
});
|
||||
|
||||
it('should show messages from top to bottom', async () => {
|
||||
const wrapper = mount();
|
||||
store.dispatch('notification/info', 'Test 1');
|
||||
store.dispatch('notification/info', 'Test 2');
|
||||
const items = wrapper.findAll('.notification__item');
|
||||
expect(items.length).toEqual(2);
|
||||
expect(items.at(0).text()).toMatch(/Test 1/);
|
||||
expect(items.at(1).text()).toMatch(/Test 2/);
|
||||
});
|
||||
|
||||
it('should not open the same message twice', async () => {
|
||||
const wrapper = mount();
|
||||
store.dispatch('notification/info', 'Test');
|
||||
store.dispatch('notification/info', 'Test');
|
||||
expect(wrapper.findAll('.notification__item').length).toEqual(1);
|
||||
});
|
||||
});
|
||||
58
test/unit/specs/specUtils.js
Normal file
58
test/unit/specs/specUtils.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import store from '../../../src/store';
|
||||
import utils from '../../../src/services/utils';
|
||||
import '../../../src/icons';
|
||||
import '../../../src/components/common/vueGlobals';
|
||||
|
||||
const clone = object => JSON.parse(JSON.stringify(object));
|
||||
|
||||
const deepAssign = (target, origin) => {
|
||||
Object.entries(origin).forEach(([key, value]) => {
|
||||
const type = Object.prototype.toString.call(value);
|
||||
if (type === '[object Object]' && Object.keys(value).length) {
|
||||
deepAssign(target[key], value);
|
||||
} else {
|
||||
target[key] = value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const freshState = clone(store.state);
|
||||
|
||||
beforeEach(() => {
|
||||
// Restore store state before each test
|
||||
deepAssign(store.state, clone(freshState));
|
||||
});
|
||||
|
||||
export default {
|
||||
async checkToggler(Component, toggler, checker, featureId) {
|
||||
const wrapper = shallowMount(Component, { store });
|
||||
const valueBefore = checker();
|
||||
toggler(wrapper);
|
||||
const valueAfter = checker();
|
||||
expect(valueAfter).toEqual(!valueBefore);
|
||||
await this.expectBadge(featureId);
|
||||
},
|
||||
async resolveModal(type) {
|
||||
const config = store.getters['modal/config'];
|
||||
expect(config).toBeTruthy();
|
||||
expect(config.type).toEqual(type);
|
||||
config.resolve();
|
||||
await new Promise(resolve => setTimeout(resolve, 1));
|
||||
},
|
||||
getContextMenuItem(name) {
|
||||
return utils.someResult(store.state.contextMenu.items, item => item.name === name && item);
|
||||
},
|
||||
async resolveContextMenu(name) {
|
||||
const item = this.getContextMenuItem(name);
|
||||
expect(item).toBeTruthy();
|
||||
store.state.contextMenu.resolve(item);
|
||||
await new Promise(resolve => setTimeout(resolve, 1));
|
||||
},
|
||||
async expectBadge(featureId, isEarned = true) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1));
|
||||
expect(store.getters['data/allBadges'].filter(badge => badge.featureId === featureId)[0]).toMatchObject({
|
||||
isEarned,
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user