Added vitest
gitea/salix-front/pipeline/head There was a failure building this commit Details

This commit is contained in:
Joan Sanchez 2022-12-22 13:46:43 +01:00
parent 618c85315d
commit df203ddb9b
33 changed files with 12553 additions and 10887 deletions

22926
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +1,48 @@
{ {
"name": "salix-front", "name": "salix-front",
"version": "0.0.1", "version": "0.0.1",
"description": "Salix frontend", "description": "Salix frontend",
"productName": "Salix", "productName": "Salix",
"author": "Verdnatura", "author": "Verdnatura",
"private": true, "private": true,
"scripts": { "scripts": {
"lint": "eslint --ext .js,.vue ./", "lint": "eslint --ext .js,.vue ./",
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore", "format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
"test:e2e": "cypress open", "test:e2e": "cypress open",
"test:e2e:ci": "cypress run --browser chromium" "test:e2e:ci": "cypress run --browser chromium",
}, "test": "echo \"See package.json => scripts for available tests.\" && exit 0",
"dependencies": { "test:unit": "vitest",
"@quasar/extras": "^1.15.8", "test:unit:ci": "vitest run"
"axios": "^1.2.1", },
"pinia": "^2.0.28", "dependencies": {
"quasar": "^2.11.1", "@quasar/extras": "^1.15.8",
"validator": "^13.7.0", "axios": "^1.2.1",
"vue": "^3.2.45", "pinia": "^2.0.28",
"vue-i18n": "^9.2.2", "quasar": "^2.11.1",
"vue-router": "^4.1.6" "validator": "^13.7.0",
}, "vue": "^3.2.45",
"devDependencies": { "vue-i18n": "^9.2.2",
"@intlify/vite-plugin-vue-i18n": "^3.3.1", "vue-router": "^4.1.6",
"@pinia/testing": "^0.0.14", "vue-router-mock": "^0.1.9"
"@quasar/app-vite": "^1.1.3", },
"autoprefixer": "^10.4.13", "devDependencies": {
"cypress": "^12.2.0", "@intlify/vite-plugin-vue-i18n": "^3.3.1",
"eslint": "^8.30.0", "@pinia/testing": "^0.0.14",
"eslint-config-prettier": "^8.5.0", "@quasar/app-vite": "^1.1.3",
"eslint-plugin-vue": "^9.8.0", "@quasar/quasar-app-extension-testing-unit-vitest": "^0.1.2",
"postcss": "^8.4.20", "@vue/test-utils": "^2.0.0",
"prettier": "^2.8.1" "autoprefixer": "^10.4.13",
}, "cypress": "^12.2.0",
"engines": { "eslint": "^8.30.0",
"node": "^18 || ^16 || ^14.19", "eslint-config-prettier": "^8.5.0",
"npm": ">= 6.13.4", "eslint-plugin-vue": "^9.8.0",
"yarn": ">= 1.21.1" "postcss": "^8.4.20",
} "prettier": "^2.8.1",
"vitest": "^0.15.0"
},
"engines": {
"node": "^18 || ^16 || ^14.19",
"npm": ">= 6.13.4",
"yarn": ">= 1.21.1"
}
} }

7
quasar.extensions.json Normal file
View File

@ -0,0 +1,7 @@
{
"@quasar/testing-unit-vitest": {
"options": [
"scripts"
]
}
}

5
quasar.testing.json Normal file
View File

@ -0,0 +1,5 @@
{
"unit-vitest": {
"runnerCommand": "vitest run"
}
}

View File

@ -1,5 +1,5 @@
import { jest, describe, expect, it, beforeAll } from '@jest/globals'; import { jest, describe, expect, it, beforeAll } from '@jest/globals';
import { createWrapper } from 'app/tests/jest/jestHelpers'; import { createWrapper } from 'app/test/jest/jestHelpers';
import App from '../App.vue'; import App from '../App.vue';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';

View File

@ -8,6 +8,7 @@ const i18n = createI18n({
globalInjection: true, globalInjection: true,
messages, messages,
missingWarn: false, missingWarn: false,
legacy: false,
}); });
export default boot(({ app }) => { export default boot(({ app }) => {

View File

@ -1,5 +1,5 @@
import { jest, describe, expect, it, beforeAll } from '@jest/globals'; import { jest, describe, expect, it, beforeAll } from '@jest/globals';
import { createWrapper } from 'app/tests/jest/jestHelpers'; import { createWrapper } from 'app/test/jest/jestHelpers';
import Leftmenu from '../LeftMenu.vue'; import Leftmenu from '../LeftMenu.vue';
import { createTestingPinia } from '@pinia/testing'; import { createTestingPinia } from '@pinia/testing';

View File

@ -1,5 +1,5 @@
import { jest, describe, expect, it, beforeAll } from '@jest/globals'; import { jest, describe, expect, it, beforeAll } from '@jest/globals';
import { createWrapper, axios } from 'app/tests/jest/jestHelpers'; import { createWrapper, axios } from 'app/test/jest/jestHelpers';
import Paginate from '../PaginateData.vue'; import Paginate from '../PaginateData.vue';
const mockPush = jest.fn(); const mockPush = jest.fn();
@ -7,7 +7,7 @@ const mockPush = jest.fn();
jest.mock('vue-router', () => ({ jest.mock('vue-router', () => ({
useRouter: () => ({ useRouter: () => ({
push: mockPush, push: mockPush,
currentRoute: { value: 'myCurrentRoute' } currentRoute: { value: 'myCurrentRoute' },
}), }),
})); }));
@ -19,8 +19,8 @@ describe('Paginate', () => {
attrs: { attrs: {
url: expectedUrl, url: expectedUrl,
sortBy: 'id DESC', sortBy: 'id DESC',
rowsPerPage: 3 rowsPerPage: 3,
} },
}; };
vm = createWrapper(Paginate, options).vm; vm = createWrapper(Paginate, options).vm;
@ -29,7 +29,7 @@ describe('Paginate', () => {
{ id: 1, name: 'Tony Stark' }, { id: 1, name: 'Tony Stark' },
{ id: 2, name: 'Jessica Jones' }, { id: 2, name: 'Jessica Jones' },
{ id: 3, name: 'Bruce Wayne' }, { id: 3, name: 'Bruce Wayne' },
] ],
}); });
}); });
@ -37,7 +37,7 @@ describe('Paginate', () => {
vm.rows = []; vm.rows = [];
vm.pagination.page = 1; vm.pagination.page = 1;
vm.hasMoreData = true; vm.hasMoreData = true;
}) });
describe('paginate()', () => { describe('paginate()', () => {
it('should call to the paginate() method and set the data on the rows property', async () => { it('should call to the paginate() method and set the data on the rows property', async () => {
@ -46,9 +46,9 @@ describe('Paginate', () => {
filter: { filter: {
order: 'id DESC', order: 'id DESC',
limit: 3, limit: 3,
skip: 0 skip: 0,
} },
} },
}; };
await vm.paginate(); await vm.paginate();
@ -63,9 +63,9 @@ describe('Paginate', () => {
filter: { filter: {
order: 'id DESC', order: 'id DESC',
limit: 3, limit: 3,
skip: 0 skip: 0,
} },
} },
}; };
await vm.paginate(); await vm.paginate();
@ -78,9 +78,9 @@ describe('Paginate', () => {
filter: { filter: {
order: 'id DESC', order: 'id DESC',
limit: 3, limit: 3,
skip: 3 skip: 3,
} },
} },
}; };
vm.pagination.page = 2; vm.pagination.page = 2;
@ -125,8 +125,8 @@ describe('Paginate', () => {
jest.spyOn(axios, 'get').mockResolvedValue({ jest.spyOn(axios, 'get').mockResolvedValue({
data: [ data: [
{ id: 1, name: 'Tony Stark' }, { id: 1, name: 'Tony Stark' },
{ id: 2, name: 'Jessica Jones' } { id: 2, name: 'Jessica Jones' },
] ],
}); });
vm.rows = [ vm.rows = [

View File

@ -1,23 +1,22 @@
import { describe, expect, it, jest } from '@jest/globals'; import { describe, expect, it, jest } from '@jest/globals';
import { axios, flushPromises } from 'app/tests/jest/jestHelpers'; import { axios, flushPromises } from 'app/test/jest/jestHelpers';
import { useRole } from '../useRole'; import { useRole } from '../useRole';
const role = useRole(); const role = useRole();
describe('useRole', () => { describe('useRole', () => {
describe('fetch', () => { describe('fetch', () => {
it('should call setUser and setRoles of the state with the expected data', async () => { it('should call setUser and setRoles of the state with the expected data', async () => {
const rolesData = [ const rolesData = [
{ {
role: { role: {
name: 'salesPerson' name: 'salesPerson',
} },
}, },
{ {
role: { role: {
name: 'admin' name: 'admin',
} },
} },
]; ];
const fetchedUser = { const fetchedUser = {
id: 999, id: 999,
@ -26,18 +25,18 @@ describe('useRole', () => {
lang: 'en', lang: 'en',
userConfig: { userConfig: {
darkMode: false, darkMode: false,
} },
} };
const expectedUser = { const expectedUser = {
id: 999, id: 999,
name: `T'Challa`, name: `T'Challa`,
nickname: 'Black Panther', nickname: 'Black Panther',
lang: 'en', lang: 'en',
darkMode: false, darkMode: false,
} };
const expectedRoles = ['salesPerson', 'admin'] const expectedRoles = ['salesPerson', 'admin'];
jest.spyOn(axios, 'get').mockResolvedValue({ jest.spyOn(axios, 'get').mockResolvedValue({
data: { roles: rolesData, user: fetchedUser } data: { roles: rolesData, user: fetchedUser },
}); });
jest.spyOn(role.state, 'setUser'); jest.spyOn(role.state, 'setUser');
@ -50,19 +49,19 @@ describe('useRole', () => {
expect(role.state.setUser).toHaveBeenCalledWith(expectedUser); expect(role.state.setUser).toHaveBeenCalledWith(expectedUser);
expect(role.state.setRoles).toHaveBeenCalledWith(expectedRoles); expect(role.state.setRoles).toHaveBeenCalledWith(expectedRoles);
role.state.setRoles([]) role.state.setRoles([]);
}); });
}); });
describe('hasAny', () => { describe('hasAny', () => {
it('should return true if a role matched', async () => { it('should return true if a role matched', async () => {
role.state.setRoles(['admin']) role.state.setRoles(['admin']);
const hasRole = role.hasAny(['admin']); const hasRole = role.hasAny(['admin']);
await flushPromises(); await flushPromises();
expect(hasRole).toBe(true); expect(hasRole).toBe(true);
role.state.setRoles([]) role.state.setRoles([]);
}); });
it('should return false if no roles matched', async () => { it('should return false if no roles matched', async () => {

View File

@ -1,7 +1,7 @@
import { describe, expect, it, jest } from '@jest/globals'; import { describe, expect, it, jest } from '@jest/globals';
import { useSession } from '../useSession'; import { useSession } from '../useSession';
import { useState } from '../useState'; import { useState } from '../useState';
import { axios } from 'app/tests/jest/jestHelpers'; import { axios } from 'app/test/jest/jestHelpers';
const session = useSession(); const session = useSession();
const state = useState(); const state = useState();
@ -9,7 +9,7 @@ const state = useState();
describe('session', () => { describe('session', () => {
describe('getToken / setToken', () => { describe('getToken / setToken', () => {
it('should return an empty string if no token is found in local or session storage', async () => { it('should return an empty string if no token is found in local or session storage', async () => {
const expectedToken = '' const expectedToken = '';
const token = session.getToken(); const token = session.getToken();
@ -17,11 +17,11 @@ describe('session', () => {
}); });
it('should return the token stored in local or session storage', async () => { it('should return the token stored in local or session storage', async () => {
const expectedToken = 'myToken' const expectedToken = 'myToken';
const data = { const data = {
token: expectedToken, token: expectedToken,
keepLogin: false keepLogin: false,
} };
session.setToken(data); session.setToken(data);
const token = session.getToken(); const token = session.getToken();
@ -38,23 +38,22 @@ describe('session', () => {
nickname: 'Black Panther', nickname: 'Black Panther',
lang: 'en', lang: 'en',
darkMode: false, darkMode: false,
} };
const expectedUser = { const expectedUser = {
id: 0, id: 0,
name: '', name: '',
nickname: '', nickname: '',
lang: '', lang: '',
darkMode: null, darkMode: null,
} };
let user = state.getUser(); let user = state.getUser();
localStorage.setItem('token', 'tokenToBeGone'); localStorage.setItem('token', 'tokenToBeGone');
state.setUser(previousUser) state.setUser(previousUser);
expect(localStorage.getItem('token')).toEqual('tokenToBeGone'); expect(localStorage.getItem('token')).toEqual('tokenToBeGone');
expect(user.value).toEqual(previousUser); expect(user.value).toEqual(previousUser);
session.destroy(); session.destroy();
user = state.getUser(); user = state.getUser();
@ -71,29 +70,29 @@ describe('session', () => {
lang: 'en', lang: 'en',
userConfig: { userConfig: {
darkMode: false, darkMode: false,
} },
} };
const rolesData = [ const rolesData = [
{ {
role: { role: {
name: 'salesPerson' name: 'salesPerson',
} },
}, },
{ {
role: { role: {
name: 'admin' name: 'admin',
} },
} },
]; ];
it('should fetch the user roles and then set token in the sessionStorage', async () => { it('should fetch the user roles and then set token in the sessionStorage', async () => {
const expectedRoles = ['salesPerson', 'admin'] const expectedRoles = ['salesPerson', 'admin'];
jest.spyOn(axios, 'get').mockResolvedValue({ jest.spyOn(axios, 'get').mockResolvedValue({
data: { roles: rolesData, user: expectedUser } data: { roles: rolesData, user: expectedUser },
}); });
const expectedToken = 'mySessionToken' const expectedToken = 'mySessionToken';
const keepLogin = false const keepLogin = false;
await session.login(expectedToken, keepLogin); await session.login(expectedToken, keepLogin);
@ -105,17 +104,17 @@ describe('session', () => {
expect(localToken).toBeNull(); expect(localToken).toBeNull();
expect(sessionToken).toEqual(expectedToken); expect(sessionToken).toEqual(expectedToken);
session.destroy() // this clears token and user for any other test session.destroy(); // this clears token and user for any other test
}); });
it('should fetch the user roles and then set token in the localStorage', async () => { it('should fetch the user roles and then set token in the localStorage', async () => {
const expectedRoles = ['salesPerson', 'admin'] const expectedRoles = ['salesPerson', 'admin'];
jest.spyOn(axios, 'get').mockResolvedValue({ jest.spyOn(axios, 'get').mockResolvedValue({
data: { roles: rolesData, user: expectedUser } data: { roles: rolesData, user: expectedUser },
}); });
const expectedToken = 'myLocalToken' const expectedToken = 'myLocalToken';
const keepLogin = true const keepLogin = true;
await session.login(expectedToken, keepLogin); await session.login(expectedToken, keepLogin);
@ -127,7 +126,7 @@ describe('session', () => {
expect(localToken).toEqual(expectedToken); expect(localToken).toEqual(expectedToken);
expect(sessionToken).toBeNull(); expect(sessionToken).toBeNull();
session.destroy() // this clears token and user for any other test session.destroy(); // this clears token and user for any other test
}); });
}); });
}); });

View File

@ -1,5 +1,5 @@
import { jest, describe, expect, it, beforeAll } from '@jest/globals'; import { jest, describe, expect, it, beforeAll } from '@jest/globals';
import { createWrapper, axios } from 'app/tests/jest/jestHelpers'; import { createWrapper, axios } from 'app/test/jest/jestHelpers';
import ClaimDescriptorMenu from '../Card/ClaimDescriptorMenu.vue'; import ClaimDescriptorMenu from '../Card/ClaimDescriptorMenu.vue';
const mockPush = jest.fn(); const mockPush = jest.fn();
@ -23,9 +23,9 @@ describe('ClaimDescriptorMenu', () => {
vm = createWrapper(ClaimDescriptorMenu, { vm = createWrapper(ClaimDescriptorMenu, {
propsData: { propsData: {
claim: { claim: {
id: 1 id: 1,
} },
} },
}).vm; }).vm;
}); });
@ -40,9 +40,7 @@ describe('ClaimDescriptorMenu', () => {
await vm.deleteClaim(); await vm.deleteClaim();
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining( expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining({ type: 'positive' }));
{ 'type': 'positive' }
));
}); });
}); });
}); });

View File

@ -1,5 +1,5 @@
import { jest, describe, expect, it, beforeAll } from '@jest/globals'; import { jest, describe, expect, it, beforeAll } from '@jest/globals';
import { createWrapper, axios } from 'app/tests/jest/jestHelpers'; import { createWrapper, axios } from 'app/test/jest/jestHelpers';
import Login from '../LoginMain.vue'; import Login from '../LoginMain.vue';
const mockPush = jest.fn(); const mockPush = jest.fn();
@ -7,7 +7,7 @@ const mockPush = jest.fn();
jest.mock('vue-router', () => ({ jest.mock('vue-router', () => ({
useRouter: () => ({ useRouter: () => ({
push: mockPush, push: mockPush,
currentRoute: { value: 'myCurrentRoute' } currentRoute: { value: 'myCurrentRoute' },
}), }),
})); }));
@ -29,8 +29,8 @@ describe('Login', () => {
lang: 'en', lang: 'en',
userConfig: { userConfig: {
darkMode: false, darkMode: false,
} },
} };
jest.spyOn(axios, 'post').mockResolvedValue({ data: { token: 'token' } }); jest.spyOn(axios, 'post').mockResolvedValue({ data: { token: 'token' } });
jest.spyOn(axios, 'get').mockResolvedValue({ data: { roles: [], user: expectedUser } }); jest.spyOn(axios, 'get').mockResolvedValue({ data: { roles: [], user: expectedUser } });
jest.spyOn(vm.quasar, 'notify'); jest.spyOn(vm.quasar, 'notify');
@ -40,9 +40,7 @@ describe('Login', () => {
await vm.onSubmit(); await vm.onSubmit();
expect(vm.session.getToken()).toEqual('token'); expect(vm.session.getToken()).toEqual('token');
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining( expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining({ type: 'positive' }));
{ 'type': 'positive' }
));
vm.session.destroy(); vm.session.destroy();
}); });

View File

@ -1,5 +1,5 @@
import { jest, describe, expect, it, beforeAll } from '@jest/globals'; import { jest, describe, expect, it, beforeAll } from '@jest/globals';
import { createWrapper, axios } from 'app/tests/jest/jestHelpers'; import { createWrapper, axios } from 'app/test/jest/jestHelpers';
import TicketBoxing from '../TicketBoxing.vue'; import TicketBoxing from '../TicketBoxing.vue';
const mockPush = jest.fn(); const mockPush = jest.fn();
@ -10,10 +10,10 @@ jest.mock('vue-router', () => ({
currentRoute: { currentRoute: {
value: { value: {
params: { params: {
id: 1 id: 1,
} },
} },
} },
}), }),
})); }));
@ -34,13 +34,9 @@ xdescribe('TicketBoxing', () => {
const expeditionId = 1; const expeditionId = 1;
const timed = { const timed = {
min: 1, min: 1,
max: 2 max: 2,
} };
const videoList = [ const videoList = ['2022-01-01T01-01-00.mp4', '2022-02-02T02-02-00.mp4', '2022-03-03T03-03-00.mp4'];
"2022-01-01T01-01-00.mp4",
"2022-02-02T02-02-00.mp4",
"2022-03-03T03-03-00.mp4",
]
jest.spyOn(axios, 'get').mockResolvedValue({ data: videoList }); jest.spyOn(axios, 'get').mockResolvedValue({ data: videoList });
jest.spyOn(vm.quasar, 'notify'); jest.spyOn(vm.quasar, 'notify');
@ -55,17 +51,15 @@ xdescribe('TicketBoxing', () => {
const expeditionId = 1; const expeditionId = 1;
const timed = { const timed = {
min: 1, min: 1,
max: 2 max: 2,
} };
jest.spyOn(axios, 'get').mockResolvedValue({ data: [] }); jest.spyOn(axios, 'get').mockResolvedValue({ data: [] });
jest.spyOn(vm.quasar, 'notify') jest.spyOn(vm.quasar, 'notify');
await vm.getVideoList(expeditionId, timed); await vm.getVideoList(expeditionId, timed);
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining( expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining({ type: 'negative' }));
{ 'type': 'negative' }
));
}); });
}); });
}); });

View File

@ -1,5 +1,5 @@
import { mount, flushPromises } from '@vue/test-utils'; import { mount, flushPromises } from '@vue/test-utils';
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-jest'; import { installQuasarPlugin, installRouter } from '@quasar/quasar-app-extension-testing-unit-jest';
import { i18n } from 'src/boot/i18n'; import { i18n } from 'src/boot/i18n';
import { Notify, Dialog } from 'quasar'; import { Notify, Dialog } from 'quasar';
import axios from 'axios'; import axios from 'axios';
@ -10,6 +10,7 @@ installQuasarPlugin({
Dialog, Dialog,
}, },
}); });
installRouter();
export function createWrapper(component, options) { export function createWrapper(component, options) {
const mountOptions = {}; const mountOptions = {};

View File

@ -0,0 +1,34 @@
import { installQuasar } from '@quasar/quasar-app-extension-testing-unit-vitest';
import { mount } from '@vue/test-utils';
import { describe, expect, it } from 'vitest';
import ExampleComponent from './demo/ExampleComponent.vue';
installQuasar();
describe('example Component', () => {
it('should mount component with todos', () => {
const wrapper = mount(ExampleComponent, {
props: {
title: 'Hello',
totalCount: 4,
todos: [
{ id: 1, content: 'Hallo' },
{ id: 2, content: 'Hoi' },
],
},
});
expect(wrapper.vm.clickCount).toBe(0);
wrapper.find('.q-item').trigger('click');
expect(wrapper.vm.clickCount).toBe(1);
});
it('should mount component without todos', () => {
const wrapper = mount(ExampleComponent, {
props: {
title: 'Hello',
totalCount: 4,
},
});
expect(wrapper.findAll('.q-item')).toHaveLength(0);
});
});

View File

@ -0,0 +1,19 @@
import { installQuasar } from '@quasar/quasar-app-extension-testing-unit-vitest';
import { mount } from '@vue/test-utils';
import { Notify } from 'quasar';
import { describe, expect, it, vi } from 'vitest';
import NotifyComponent from './demo/NotifyComponent.vue';
installQuasar({ plugins: { Notify } });
describe('notify example', () => {
it('should call notify on click', async () => {
expect(NotifyComponent).toBeTruthy();
const wrapper = mount(NotifyComponent, {});
const spy = vi.spyOn(Notify, 'create');
expect(spy).not.toHaveBeenCalled();
wrapper.trigger('click');
expect(spy).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,44 @@
<template>
<div>
<p>{{ title }}</p>
<q-list>
<q-item v-for="todo in todos" :key="todo.id" @click="increment" clickable>
{{ todo.id }} - {{ todo.content }}
</q-item>
</q-list>
<p>Count: {{ todoCount }} / {{ totalCount }}</p>
<p>Active: {{ active ? 'yes' : 'no' }}</p>
<p>Clicks on todos: {{ clickCount }}</p>
</div>
</template>
<script setup>
import { computed, ref } from 'vue';
const props = defineProps({
title: {
type: String,
required: true,
},
todos: {
type: Array,
default() {
return [];
},
},
totalCount: {
type: Number,
required: true,
},
active: Boolean,
});
const clickCount = ref(0);
function increment() {
clickCount.value += 1;
return clickCount.value;
}
const todoCount = computed(() => props.todos.length);
</script>

View File

@ -0,0 +1,11 @@
<template>
<q-btn @click="onClick"> Click me! </q-btn>
</template>
<script setup>
import { Notify } from 'quasar';
function onClick() {
Notify.create('Hello there!');
}
</script>

View File

@ -0,0 +1,90 @@
import { installQuasar } from '@quasar/quasar-app-extension-testing-unit-vitest';
import { vi, describe, expect, it, beforeAll } from 'vitest';
// import { createWrapper } from 'app/test/jest/jestHelpers';
import { mount } from '@vue/test-utils';
import { i18n } from 'src/boot/i18n';
import { Notify, Dialog } from 'quasar';
import App from 'src/App.vue';
import { useSession } from 'src/composables/useSession';
installQuasar({
plugins: {
Notify,
Dialog,
},
});
const mockPush = vi.fn();
const mockLoggedIn = vi.fn();
const mockDestroy = vi.fn();
const session = useSession();
vi.mock('vue-router', () => ({
useRouter: () => ({
push: mockPush,
currentRoute: { value: 'myCurrentRoute' },
}),
}));
vi.mock('src/composables/useSession', () => ({
useSession: () => ({
isLoggedIn: mockLoggedIn,
destroy: mockDestroy,
}),
}));
describe('App', () => {
let vm;
beforeAll(() => {
const options = {
global: {
stubs: ['router-view'],
plugins: [i18n],
},
};
vm = mount(App, options).vm;
});
it('should return a login error message', async () => {
vi.spyOn(vm.quasar, 'notify');
session.isLoggedIn.mockReturnValue(false);
const response = {
response: {
status: 401,
},
};
expect(vm.responseError(response)).rejects.toEqual(expect.objectContaining(response));
expect(vm.quasar.notify).toHaveBeenCalledWith(
expect.objectContaining({
message: 'Invalid username or password',
type: 'negative',
})
);
});
it('should return an unauthorized error message', async () => {
vi.spyOn(vm.quasar, 'notify');
session.isLoggedIn.mockReturnValue(true);
const response = {
response: {
status: 401,
},
};
expect(vm.responseError(response)).rejects.toEqual(expect.objectContaining(response));
expect(vm.quasar.notify).toHaveBeenCalledWith(
expect.objectContaining({
message: 'Access denied',
type: 'negative',
})
);
expect(session.destroy).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,13 @@
import { beforeEach } from 'vitest';
import { createRouterMock, injectRouterMock, VueRouterMock } from 'vue-router-mock';
import { config } from '@vue/test-utils';
// https://github.com/posva/vue-router-mock
export function installRouter(options) {
beforeEach(() => {
const router = createRouterMock(options);
injectRouterMock(router);
});
config.plugins.VueWrapper.install(VueRouterMock);
}

View File

@ -0,0 +1 @@
// This file will be run before each test file

27
vitest.config.js Normal file
View File

@ -0,0 +1,27 @@
import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';
import { quasar, transformAssetUrls } from '@quasar/vite-plugin';
import jsconfigPaths from 'vite-jsconfig-paths';
// https://vitejs.dev/config/
export default defineConfig({
test: {
environment: 'happy-dom',
setupFiles: 'test/vitest/setup-file.js',
include: [
// Matches vitest tests in any subfolder of 'src' or into 'test/vitest/__tests__'
// Matches all files with extension 'js', 'jsx', 'ts' and 'tsx'
'src/**/*.vitest.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
'test/vitest/__tests__/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
],
},
plugins: [
vue({
template: { transformAssetUrls },
}),
quasar({
sassVariables: 'src/quasar-variables.scss',
}),
jsconfigPaths(),
],
});