Jest isn’t compatible with Vite, if you use
@quasar/app-vite
and you need unit testing, you should use Vitest instead.
We’re looking for a maintainer! Currently no one in the Quasar team is using Jest in his day-to-day life, thus we miss many use cases and the DX is suboptimal. We’re looking for someone who is using it and would like to help us maintain this package. If you’re interested, please reach out on Discord
$ quasar ext add @quasar/testing-unit-jest
Add into your .eslintrc.js
the following code:
{
// ...
overrides: [
{
files: ["**/*.{js,ts}"],
// If the `script` part of a Vue component is stored in a separate JS/TS file,
// as is the case when using DFC (https://testing.quasar.dev/packages/unit-jest/#double-file-components-dfc),
// Vue ESLint plugin will highlight all public properties as unused
// as it's not able to detect their usage into the template
// We disable this rule and only keep it for Vue files
rules: { "vue/no-unused-properties": "off" },
},
{
files: [
'**/test/jest/__tests__/**/*.{spec,test}.{js,jsx,ts,tsx}',
'**/*.jest.{spec,test}.{js,jsx,ts,tsx}',
],
env: {
browser: true,
},
extends: [
// Removes 'no-undef' lint errors for Jest global functions (`describe`, `it`, etc),
// add Jest-specific lint rules and Jest plugin
// See https://github.com/jest-community/eslint-plugin-jest#recommended
'plugin:jest/recommended',
// Uncomment following line to apply style rules
// 'plugin:jest/style',
],
},
],
}
This App Extension (AE) manages Quasar and Jest integration for you, both for JavaScript and TypeScript.
What is included:
jest.config.js
);installQuasarPlugin
function to help you setup and configure the test Quasar instance on a per-test-suite basis;MyButton.vue
) and related example test (eg. MyButton.spec.[js|ts]
);package.json
scripts;This AE is a lightweight add-on to “@vue/test-utils” package, which helps you test Vue components that rely on some Quasar features. Please check out “@vue/test-utils” official documentation to learn how to test Vue components.
Call this helper at the top of your test files. It will configure @vue/test-utils
to setup Quasar plugin every time mount
/shallowMount
is called.
It will also restore the original configuration after all tests completed.
Usage:
import { describe, expect, it } from '@jest/globals';
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-jest';
import { mount } from '@vue/test-utils';
import BookComponent from './BookComponent.vue';
/*
* You can provide a config object as param like such:
*
* ```ts
* installQuasarPlugin({ plugins: { Dialog } });
* ```
*/
installQuasarPlugin();
describe('BookComponent', () => {
it('mounts without errors', () => {
const wrapper = mount(MyButton);
expect(wrapper).toBeTruthy();
});
});
You can choose to install Majestic, which is a UI interface to see how your tests are doing.
This package had a long alpha phase due to narrow bandwidth on Quasar team to care about it as much as it was needed. When the first alpha release took place the active Jest version was v26, while at the time of the beta release it bumped to v29. We decided to update directly to Jest v29 before releasing the beta of this package. The suggested path to migrate projects using v3 alpha or beta releases of this package is to re-read and apply the migration guide which has been updated to account for new changes.
Alternatively to the following guide, a faster way for advanced developers would be to run yarn quasar ext add @quasar/testing-unit-jest
and yarn add -D jest @vue/test-utils eslint-plugin-jest@latest
, then let the package scaffold new files overriding the existing ones and manually merge your changes into the generated files. Ensure to have version control in place to be able to revert if needed. Even in this case, we suggest to take a look to the following migration guide and use it as a checklist, as some files must be renamed/removed.
Please note that Jest v29 requires Node v14, thus this package can only be used with Node 14 or higher.
We adapted to the ecosystem shift towards externalizing dependencies, we now manage supported versions of third parties packages via peerDependencies.
Run yarn add -D jest @vue/test-utils
to install previously bundled dependencies.
Run yarn add -D @quasar/quasar-app-extension-testing-unit-jest eslint-plugin-jest@latest
to upgrade dependencies which were already externalized.
Here are some resources which you should read, adapting your tests accordingly:
Here are some resources which you should read only if you still have errors after having applied this guide steps:
We removed some dependencies and scripts which didn’t really prove to be that much useful:
concurrently
package and related 'concurrently:dev:jest'
script: if you were using them in any way, add the package back in your project by running yarn add -D concurrently
, otherwise remove the related script from your package.json
.jest-serializer-vue
package: it’s not compatible with Vue 3. Feel free to help upstream efforts to catch up if you need this feature. There’s also a more advanced fork with the same problem.serve:test:coverage
script: it probably never actually worked as intended, check out https://github.com/quasarframework/quasar-testing/issues/97#issuecomment-1289054992 for an explanation about its problems, you can still run quasar serve test/jest/coverage/lcov-report/ --port 8788
manually and we’ll try to re-add it back in a future release.mountQuasar
/mountFactory
, hello installQuasarPlugin
The new VTU mount
helper comes with improved typings and extended features, thus Quasar-specific helpers, like mountQuasar
, don’t quite make sense anymore.
They have been replaced by the installQuasarPlugin
helper, which you should call at the very top of your test files.
@jest/globals
(Optional*, but strongly recommended)We suggest you switch from Jest globals to their ESM-imported counterparts (especially if you use TypeScript), as this will avoid global scope pollution and simplify integrating Jest with other testing tools. If you choose to proceed on this path, then:
yarn remove @types/jest
jest
value from compilerOptions.types
property into tsconfig.json
. If only quasar
remains in that array, remove compilerOptions.types
altogether, as it’s already provided by src/quasar.d.ts
shim@jest/globals
package, eg. import { describe, expect, jest, it, test } from "@jest/globals"
*= If you’re using other testing frameworks (e.g. Cypress) this step is required to avoid type and linting conflicts
We moved most of Jest configuration needed to integrate Jest with Quasar into @quasar/quasar-app-extension-testing-unit-jest
preset.
Upgrade your jest.config.js
to be a .mjs
file, then update its content to match the TS configuration or JS configuration, depending on your needs, and integrate any custom configuration you had.
When in need of extending the preset, you can import it and cherry-pick the properties you need to extend like such:
import { config } from '@quasar/quasar-app-extension-testing-unit-jest/jest-preset.mjs';
const { transform } = config;
export default {
// ... other config properties
transform: {
...transform,
// Add your custom transform here
},
};
If you’ve never touched test/jest/jest.setup
file since you installed this AE, you can now safely delete it: its main purpose was to apply a Promise
polyfill, which isn’t needed anymore due to the new minimum Node version being v14.
If you actually added custom code there, add setupFilesAfterEnv
property into your updated jest.config.mjs
to reference it.
"esModuleInterop": true
from tsconfig.json
, as Vue Test Utils now supports tsconfig extends
property and will infer esModuleInterop
value from Quasar TS config presetWe removed “Babel config” prompt as latest Quasar projects already come with Babel presets to detect Node environment and adapt Babel configuration accordingly.
Make sure your Quasar packages are up-to-date and your babel.config.js
matches latest available version. You can remove any pre-existing .babelrc
file generated by this AE.
If your codebase is written in JavaScript, you’ll need to update babel.config.js
to match this version instead.
Remove eslint configuration into test/jest
and add an override into the root eslint config as explained as explained into this AE installation instructions.
We removed some nice-to-have options present in the old AE version which increased the maintenance effort. Some of them will come back with time, some others were pretty clunky and won’t probably be migrated.
As far as we know, the ability to add tests directly into the SFC isn’t really used, as it still requires an intermediate step to extract those tests into .spec
files anyway.
We don’t plan to migrate it, unless many people ask for it and someone from the community steps up to enhance this feature DX.
Wallaby support has been dropped. We plan to explore this feature again in some time, but a better path would be to discuss with Wallaby team for them to integrate Quasar CLI into their own automatic configurator as is already the case for other CLIs.
ssrContextMock helper has been dropped to discourage testing components in SSR mode: many Quasar components aren’t meant to work in that environment or work partially/have a different behaviour. If you think you have some legit use cases for this feature, please reach back to us by opening an issue.
setCookies helper has been temporarly removed, but we plan to add it back.
Portal-based component (eg. QMenu, QDialog, etc) require a body
so that they can attach themselves to the document.
Vue Test Utils provides a DOMWrapper that allows you to mount the document body, and access the document for testing
purposes. The example provided in MyDialog.spec.[ts/js]
demonstrates how this can be implemented.
However, if this does not work for your specific use case, the recommended way of testing these components with Jest is to abstract them into their own component and test them in isolation.
Note that, if you end up trying to test interactions between multiple components, you are probably trying to test an e2e/integration scenario using a unit testing tool. Take a look to our Cypress AE instead: it supports proper Component Testing since v4 and may be what you’re searching for.
If you’re using vue-i18n
, you may want to mock translations. You can easily create Jest mocks for all translation functions and provide them into options.mocks
.
import { describe, it, jest } from '@jest/globals';
import { config, mount } from '@vue/test-utils';
import BookshelfComponent from './BookshelfComponent';
const $t = jest.fn();
$t.mockReturnValue(''); // <= will always return an empty string
// Global mock
config.global.mocks.$t = $t;
describe('BookshelfComponent', () => {
it('should mount with translations mock', () => {
// Local mock
const wrapper = mount(BookshelfComponent, {
global: { mocks: { $t } },
});
// ...
});
});
QPage
usually only works when placed inside a QLayout
component, because the latter provides some references to other layout components.
You can use qLayoutInjections
to get stubs of those references, then you should provide them while mounting the component.
This will allow you to test QPage
s in isolation.
import { qLayoutInjections } from '@quasar/quasar-app-extension-testing-unit-jest';
import { mount } from '@vue/test-utils';
import BookshelfPage from './BookshelfPage';
describe('BookshelfPage', () => {
it('should mount a page with mocked layout', () => {
const wrapper = mount(BookshelfPage, {
global: { provide: qLayoutInjections() },
});
// ...
});
});
This AE ships with project-level type-checking disabled by default since it increases dramatically the first run time, and the performance penality increases as the project grows. If you want to re-enable it (eg. because you need to use const enum
), switch isolatedModules
option of ts-jest
transformer to false
into jest.config.mjs
.
Project-wide type-checking already takes place during development and into your IDE, so you won’t usually need this during tests anyway.
There are a couple of limitations due to Vue and TS incompabilities. These limitations also affect JS users to some degree, as under-the-hood code autocomplete is powered by TypeScript.
TypeScript cannot infer a component type from an SFC, because it cannot understand the content of files which are not JavaScript or TypeScript.
To allow correct inference of the component type, you should separate the <script>
tag content of your SFC into a standalone file, adopting a DFC (Double File Component) fashion.
// BookComponent.ts
import { defineComponent } from 'vue';
export default defineComponent({
name: 'BookComponent',
// ...
});
<!-- BookComponent.vue -->
<script lang="ts" src="./book-component.ts"></script>
<template></template>
<style scoped></style>
jest --watch
will not work if you don’t have a version control system (Git, Mercurial) in place, as jest relies on it to track which files should be watched for changes.
Alternatively you can use jest --watchAll
, but be aware there will be a performance impact and you should ignore all folders not containing tests in your Jest configuration.
cd test-project-webpack # or "cd test-project-app"
yarn sync:jest # or "yarn sync:all", if it's the first time you run this command
yarn test:unit:ci # check if unit tests still work with the local version of the AE