DEV Community

loading...
Cover image for Add testing to Vite

Add testing to Vite

vuesomedev profile image Gábor Soós Updated on ・4 min read

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
Enter fullscreen mode Exit fullscreen mode

The above command creates a Vue 3 Typescript application into the my-vite-app folder. The folder structure will look like this.

Folder Structure

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.

Application

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)
  })
})
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'
  }
}
Enter fullscreen mode Exit fullscreen mode

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"],
    ...
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

Finally, add the script to package.json, and after that, we can run the tests with npm test.

// package.json
{
  ...
  "scripts": {
    ...
    "test": "jest src"
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

And here it is the result of our first unit test, beautiful green, and passing.

Jest Output

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')
  })
})
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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"],
    ...
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

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"
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

If we run the above script, we get passing shiny green end-to-end test results.

Cypress Output

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

Discussion (7)

pic
Editor guide
Collapse
soetz profile image
Sœtz - Simon Lecutiez • Edited

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.

Collapse
vuesomedev profile image
Gábor Soós Author

Can you share code alongside the error message?

Collapse
soetz profile image
Sœtz - Simon Lecutiez

I tried it again, and I think I got it right this time. Thanks!

Collapse
jaiko86 profile image
jaiko86

Worked like a charm.

Collapse
patrikbird profile image
PatrikBird

thanks for bringing vite back to my mind and all the nice vue content. keep it up!

Collapse
vuesomedev profile image
Gábor Soós Author

thanks, planning to write about vue cli -> vite migration

Collapse
mattdeacalion profile image
Matt Deacalion

I'm currently in the process of migrating to Vite, that would be very helpful!