Vite is the brand new development server created by Evan You. It's framework agnostic and incredibly fast thanks to native ES Modules instead of bundling. Vite has a starter template for Vue applications. The template has the tooling for development and production deployment; only one is missing: testing. This tutorial shows you how to add unit and end-to-end testing to a newly generated Vue 3 Vite project.
Project setup
Let's start by creating a Vite project from scratch.
npm init @vitejs/app my-vite-app --template vue-ts
The above command creates a Vue 3 Typescript application into the my-vite-app
folder. The folder structure will look like this.
We have a HelloWorld
component in the src/components/HelloWorld.vue
file that displays the header on the page "Hello Vue 3 + TypeScript + Vite". This component receives the header text a prop
input named msg
. We'll write a test against this component whether it displays the same message as what we give as input.
Unit test
As mentioned in the headline, the Vite template doesn't include any test runner; we have to choose one. The Jest test runner is a good choice if we want a simple and fast setup as it gives us everything that we need: a test runner that executes the tests, an assertion library with which we can assert for the outcome and a DOM implementation where Vue components can be mounted.
Here is our first unit test placed next to the HelloWorld.vue
component file.
// src/components/HelloWorld.spec.ts
import { mount } from '@vue/test-utils'
import HelloWorld from './HelloWorld.vue'
describe('HelloWorld', () => {
it('should display header text', () => {
const msg = 'Hello Vue 3'
const wrapper = mount(HelloWorld, { props: { msg } })
expect(wrapper.find('h1').text()).toEqual(msg)
})
})
The test uses the Vue Test Utils library, the official unit test helper library. With its help, we can mount a single component to the DOM and fill the input parameters, like its props
.
We feed the "Hello Vue 3" text to the component and check the outcome through the components wrapper object. If the header element has the same text as the input, the test passes. But how do we run this test?
I've mentioned Jest and Vue Test Utils, but we haven't installed any packages.
npm install jest @types/jest ts-jest vue-jest@next @vue/test-utils@next --save-dev
By default, Jest doesn't understand Vue and Typescript files, so we need to transpile them before and pass the transpilation step as configuration (jest.config.js
). We need the next
version for multiple packages because they are the only ones that support Vue 3.
// jest.config.js
module.exports = {
moduleFileExtensions: [
'js',
'ts',
'json',
'vue'
],
transform: {
'^.+\\.ts$': 'ts-jest',
'^.+\\.vue$': 'vue-jest'
}
}
We are two little steps away from running and seeing passing tests. First, we have to add the type definition of Jest to the config.
// tsconfig.json
{
"compilerOptions": {
...
"types": ["vite/client", "@types/jest"],
...
},
...
}
Finally, add the script to package.json
, and after that, we can run the tests with npm test
.
// package.json
{
...
"scripts": {
...
"test": "jest src"
},
...
}
And here it is the result of our first unit test, beautiful green, and passing.
E2E test
While unit tests are good for checking smaller bits of code, end-to-end tests are really good at checking the application as a whole in the browser. Vue CLI comes with built-in support for Cypress, an end-to-end test runner. We'll also use Cypress for this purpose.
// e2e/main.spec.ts
describe('Main', () => {
it('should display header text', () => {
cy.visit('/')
cy.contains('h1', 'Hello Vue 3 + TypeScript + Vite')
})
})
Cypress provides a global object cy
that can interact with the browser. It can visit certain pages (visit
) and check the content of elements defined by a selector (contains
). In the above test, we navigate to the main page and check for the correct header text.
It's time to install the necessary packages to run the test.
npm install cypress start-server-and-test --save-dev
Next to Cypress, we've installed a utility library called start-server-and-test. This utility library can start the development server, wait until it responds to the given URL, and then runs the Cypress tests. In the end, it stops all running processes during the cleanup phase.
Cypress doesn't know where the test files are located and the base URL of the application, we have to tell it with a configuration file.
// cypress.json
{
"baseUrl": "http://localhost:3000",
"integrationFolder": "e2e",
"pluginsFile": false,
"supportFile": false,
"video": false
}
Manually declared types
within our Typescript configuration needs manual work again: add Cypress types to the list.
// tsconfig.json
{
"compilerOptions": {
...
"types": ["vite/client", "@types/jest", "cypress"],
...
},
...
}
One piece is left to create the script command in package.json
to run the tests. We use the start-server-and-test
package with three command-line arguments:
-
dev
: the npm script name which runs the development server -
http-get://localhost:3000
: the URL where the development server is available -
cypress
: the npm script name which runs the end-to-end tests
// package.json
{
...
"scripts": {
...
"test:e2e": "start-server-and-test dev http-get://localhost:3000 cypress",
"cypress": "cypress run"
},
...
}
If we run the above script, we get passing shiny green end-to-end test results.
Summary
Vite is a great development server, but its templates lack testing solutions. We have to add them manually. Jest and Cypress offer straightforward scenarios to fill in this gap. We can also swap them to similar libraries like Mocha, Jasmine, and Puppeteer. After this article, I hope the lack of out-of-the-box testing with Vite doesn't hold back anyone from using it.
If you don't want to set up everything manually, you can use my Vue 3 Playground as a starter.
Cover photo by Liam Shaw
Top comments (22)
Hey! Thanks a load for this, but it seems it doesn’t work for me… The error I got says
Cannot find module './xxx.vue' or its corresponding type declarations.
. I tried searching for ways to fix this but couldn’t understand what’s wrong. :( It’s such a shame because Vite was a nice experience until then.just use vue-jest@next don't use vue-jest/next or vue3-jest ,it's a issues of Version compatibility, then config in jest.config.js as follow:
module.exports = {
moduleFileExtensions: ['js', 'ts', 'json', 'vue'],
transform: {
'^.+\.ts$': 'ts-jest',
'^.+\.vue$': '@vue/vue3-jest',
},
testEnvironment: 'jsdom',
// transformIgnorePatterns: ['node_modules/(?!variables/.*)'],
}
remember set the testEnvironment to 'jsdom'
I had the same problem, got it to working by downing
jest version to 26.6.3
ts-jest to 26.5.6
here is my package.json
{
"name": "vite-testing",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"serve": "vite preview",
"test": "jest src"
},
"dependencies": {
"vue": "^3.2.13"
},
"devDependencies": {
"@types/jest": "^26.0.2",
"@vitejs/plugin-vue": "^1.9.0",
"@vue/test-utils": "^2.0.0-rc.15",
"jest": "^26.6.3",
"ts-jest": "^26.5.6",
"typescript": "^4.4.3",
"vite": "^2.5.10",
"vue-jest": "^5.0.0-alpha.10",
"vue-tsc": "^0.3.0"
}
}
the problem now is it's passing while it shouldn't lol
This also worked for me
i have same problem, just use @vue/vue3-jest
I got the same error. How to fix this ?
Can you share code alongside the error message?
I tried it again, and I think I got it right this time. Thanks!
I tried this from a freshly created vite/vue ts project and just ended up with
import { mount } from '@vue/test-utils';
^^^^^^
If any of you guys setting for Vue Javascript, or having
.js
file in theproject, thejest.config.js
file should look like this to avoid the errorSyntaxError: Cannot use import statement outside a module
.@vuesomedev Can you update the post to include
.js
files to usets-jest
as well. Sincetypecsript.json
might have option"allowJs": true
.hio! i don't know what im doing wrong, but its giving me this error:
TypeError: Cannot destructure property 'config' of 'undefined' as it is undefined.
Have you encountered this error, and how do you fix it? ThanksHey
It's not working for me.
I'm dealing with the same problem that was already mention before, and I tried to follow what they did to fix but didn't worked for me.
Worked like a charm.
thanks for bringing vite back to my mind and all the nice vue content. keep it up!
thanks, planning to write about vue cli -> vite migration
I'm currently in the process of migrating to Vite, that would be very helpful!
Great article, thanks!
how to do testing using the testing library with vite?
its hard stackoverflow.com/questions/729404...
It isn't clear where either jest.config.js or cypress.json should be saved. Is it in src, or at the root of the project?