Write Your First Vue Component Test

Introducing cypress-vue-unit-test for better Vue component testing experience inside Cypress test runner.

Let's create a new Vue application and write a component test using Cypress + cypress-vue-unit-test combo. We will use Vue CLI v3 to scaffold our application and you can find the complete application in bahmutov/vue-component-test-example repository.

Application

  1. First install the Vue CLI globally
1
https://cli.vuejs.org/
  1. Create a new application
1
2
3
$ vue create vue-component-test-example
Vue CLI v4.4.6
...

I picked the "default" option to use Babel and ESLint. The folder contains the scaffolded files

1
2
3
4
$ ls -a
. .gitignore node_modules public
.. README.md package-lock.json src
.git babel.config.js package.json
  1. We can start the application and see it run at localhost:8080 url
1
$ npm run serve

The application running at localhost:8080

End-to-end tests

We definitely recommend ensuring your web application's quality by writing end-to-end tests. With Cypress E2E tests are:

  • fast to write and run
  • effective at covering lots of code
  • can perform visual testing via 3rd-party plugins

You can write E2E tests for Vue applications by using the official @vue/cli-plugin-e2e-cypress plugin. And I suggest reading one of the many blog posts on this topic, like End-To-End Testing A VueJS HackerNews Clone. In this blog post I want to show how to move down one level of the testing pyramid to perform component testing.

Components

In our current application the App.vue uses HelloWorld.vue component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
name: 'App',
components: {
HelloWorld
}
}
</script>

The logic inside a component might become pretty complex. To guarantee the component still works as expected as the project becomes more complex, we need tests - and the closer the tests are to the way our users are going to use in the browser, the better. In this blog post I will show how to write realistic component tests that run in a true browser using cypress-vue-unit-test.

Component tests

Let's update our project to be able to write Cypress component tests.

1
2
3
4
5
6
$ vue add cypress-experimental

📦 Installing vue-cli-plugin-cypress-experimental...

+ [email protected]
...

The vue-cli-plugin-cypress-experimental scaffolds an example component test and adds Cypress and cypress-vue-unit-test dev dependencies.

1
2
3
4
$ npm ls cypress cypress-vue-unit-test
[email protected] /Users/gleb/git/vue-component-test-example
├── [email protected]
└── [email protected]

You can see the component testing enabled in cypress.json file

1
2
3
4
{
"experimentalComponentTesting": true,
"componentFolder": "tests/components"
}

Let's write a component test for HelloWorld.vue component to make sure it correctly renders the property msg.

tests/components/HelloWorld.spec.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// <reference types="cypress" />
import { mount } from 'cypress-vue-unit-test'
import HelloWorld from '../../src/components/HelloWorld.vue'

describe('HelloWorld', () => {
it('Works awesomely', () => {
// mount command comes from
// https://github.com/bahmutov/cypress-vue-unit-test
mount(HelloWorld, { propsData: {msg: 'Hello, Cypress!'} })

// now we can use any Cypress command to interact with the component
// https://on.cypress.io/api
cy.contains('h1', 'Hello, Cypress!').should('be.visible')
})
})

In the test we import the component and mount it using a function from cypress-vue-unit-test. We pass props using propsData option and then the component becomes a full-fledged web application! Let's see this in action.

We can see the new script test:components added by vue-cli-plugin-cypress-experimental.

1
2
3
4
5
6
7
8
9
10
11
12
$ npm run
Scripts available in vue-component-test-example via `npm run-script`:
serve
vue-cli-service serve
build
vue-cli-service build
lint
vue-cli-service lint
test:components
vue-cli-service test:components

$ npm run test:components

With the above command we have started Cypress. We see a couple of component spec files in the window that opens

The component tests list

Tip: use browser drop down to select a different browser amongst the browsers detected on your machine.

Cypress allows to run tests using any detected supported browser

Click on "HelloWorld.spec.js" file to start the test. The test shows the component running inside the browser.

Passing HelloWorld.spec test

We can confirm the msg prop was rendered in the right H1 element by hovering over the command in the Command Log on the left. The found element is highlighted in the DOM snapshot on the right.

The cy.contains command finds the expected element and text

As you edit the spec file and save it, the tests automatically re-run.

Re-running the test on spec file save

In fact, if you change the spec or any file it imports, even indirectly, the tests will re-run. For example, let's change HelloWorld.vue to show the message in H2 element instead of H1.

Changing the component and updating the test

In the movie above we jumped to the failing test command using Cypress Test Error Frames. Clicking on the error location opens my text editor at the right command.

App component

Everything in a modern Vue application is built out of components. The src/App.vue is a component too! Let's write a test to ensure there are essential links.

tests/components/App.spec.js
1
2
3
4
5
6
7
8
9
10
11
/// <reference types="cypress" />
import { mount } from 'cypress-vue-unit-test'
import App from '../../src/App.vue'

describe('App', () => {
it('works', () => {
mount(App)
cy.contains('h3', 'Essential Links')
.next().find('li').should('have.length', 5)
})
})

The correct links are found by first finding the h3 element, then its next sibling and then finding all li elements under it.

App.vue component test

Next steps

We are very excited about component tests running inside a real browser with full Cypress API, built-in code coverage, huge list of plugins for visual testing and other tasks, Dashboard support, etc. Give cypress-vue-unit-test a try, open any issues found, give us feedback!

Happy Vue Testing!