This article mainly explains how to build a relatively complete set of unit testing process based on Vite 2 and Vue 3

📦 Warehouse address: vue-Unit, welcome ✨ Star ✨ ~~


Installation and configuration

1. Create a vue3 empty project using create Vite Cli

yarn create vite
Copy the code

2. Install jest

yarn add jest -D
Copy the code

3. After installation, create the jest. Config. js file

// jest.config.js
module.exports = {
  transform: {}}Copy the code

If you want to use the ES6 syntax, you need to install Babel and run the following command:

yarn add babel-jest @babel/core @babel/preset-env -D
Copy the code

5. Configure babel.config.js

module.exports = {
  presets: [['@babel/preset-env', {
        targets: {
          node: 'current'}}]],};Copy the code

5. Configure Babel to jest. Config.js

module.exports = {
  transform: {
    '^.+\\.js$': 'babel-jest'}}Copy the code

6. Since we mainly test vUE components, we need to install the corresponding VUE-Jest and dependency packages.

Since it is VUe3 and the JEST version I installed before is 27.x, I execute the command (note the jEST version I installed here, different versions of JEST need to install different VUE-Jest).

For reference:

Github.com/vuejs/vue-j…

Github.com/vuejs/vue-t…

Yarn add @vue/vue3-jest@^27.0.0-alpha.3 @vue/test-utils@^2.0.0-rc.17 -d yarn add @vue/vue3-jest@^27.0.0-alphaCopy the code

7. After installing vue-jest, you need to further configure jest. Config.js

// jest.config.js
module.exports = {
  transform: {
    '^.+\\.js$': 'babel-jest'.'^.+\\.vue$': '@vue/vue3-jest',}}Copy the code

In general, unit test code is placed in the __tests__ folder

We can display the configuration to jest.config.js like this:

// jest.config.js
module.exports = {
  transform: {
    '^.+\\.js$': 'babel-jest'.'^.+\\.vue$': '@vue/vue3-jest',},testMatch: ['<rootDir>/__tests__/**/*.spec.js']}Copy the code

Every unit test file we write after that ends with *.spec.js.

Let’s use an example to verify the effect. Don’t forget to add jest to package.json before testing:

{
  "scripts": {
    "test": "jest"}}Copy the code

example

We can refer to the example given by vue-test-utils official next.vue-test-utils.vuejs.org/guide/ :

Create a hello.spec.js file in __tests__

// hello.spec.js
import { mount } from '@vue/test-utils'

// The component to test
const MessageComponent = {
  template: '<p>{{ msg }}</p>'.props: ['msg']
}

test('displays message'.() = > {
  const wrapper = mount(MessageComponent, {
    props: {
      msg: 'Hello world'}})// Assert the rendered text of the component
  expect(wrapper.text()).toContain('Hello world')})Copy the code

2. An error message is displayed when you run the YARN test command. This message indicates that the single-test environment needs to be configured in jsDOM mode

IO /docs/config…

yarn run v1.22.17
$Jest FAIL __tests__/hello.spec.js ● Displays message The error below may be caused byusing the wrong test environment, see https://jestjs.io/docs/configuration#testenvironment-string.
    Consider using the "jsdom" test environment.
    
    ReferenceError: document is not defined

       9 |
      10 | test('displays message', () => {>11 |   const wrapper = mount(MessageComponent, {
         |                   ^
      12 |     props: {
      13 |       msg: 'Hello world'
      14 |     }

      at mount (node_modules/@vue/test-utils/dist/vue-test-utils.cjs.js:7757:14)
      at Object.<anonymous> (__tests__/hello.spec.js:11:19)
Copy the code

TestEnvironment: ‘jsdom’

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom'.transform: {
    '^.+\\.js$': 'babel-jest'.'^.+\\.vue$': '@vue/vue3-jest',},testMatch: ['<rootDir>/__tests__/**/*.spec.js']}Copy the code

Run yarn test again, and the PASS succeeds 🎉

The vUE component in the single test is a template component created temporarily and not imported from SRC. The actual situation may be:

1. Create.vue under SRC

2. Introduce to __tests__, mount to perform the test.

So let’s try it out and use the default app. vue instead:

App.vue

<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3 + Vite" />
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
Copy the code

To introduce app. vue to __tests__ :

Before we rush to execute the single test, let’s print the App and see if it can be introduced correctly:

// hello.spec.js
import { mount } from '@vue/test-utils'
import App from '.. /src/App.vue'
console.log(App)

// The component to test
const MessageComponent = {
  template: '<p>{{ msg }}</p>'.props: ['msg']
}

test('displays message'.() = > {
  const wrapper = mount(MessageComponent, {
    props: {
      msg: 'Hello world'}})// Assert the rendered text of the component
  expect(wrapper.text()).toContain('Hello world')})Copy the code

Yarn test error:

● Test suite failed to run Jest encountered an unexpected token Jest failed to parse a file  code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax. Out of the box Jest supports Babel,which will be used to transform your files into valid JS based on your Babel configuration.

    By default "node_modules" folder is ignored by transformers.

    Here's what you can do: • If you are trying to use ECMAScript Modules, See https://jestjs.io/docs/ecmascript-modules for how to enable it. • If you are trying to use TypeScript. See https://jestjs.io/docs/getting-started#using-typescript, and some of your "node_modules" files transformed, You can specify a custom "transformIgnorePatterns" in your config. • If you need a custom transformation specify a • If you simply want to mock your non-js modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option. You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/configuration
    For information about custom transformations, see:
    https://jestjs.io/docs/code-transformation

    Details:

    /Users/wisdom/Documents/workspace/vue-unit/src/assets/logo.png:1
    ({"Object.<anonymous>":function(module, exports, the require, __dirname __filename, jest) {� PNG SyntaxError: Invalid or unexpected token at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14) at Object.<anonymous> (src/App.vue:40:36)Copy the code

PNG fails to be parsed and cannot be converted. An additional transform is required

Jest does not process assets by default, but there is a package that does: jest-transform-stub

Install jest-transform-stub:

yarn add jest-transform-stub -D
Copy the code

Use jest-transform-stub in the Jest configuration file

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom'.transform: {
    '^.+\\.js$': 'babel-jest'.'^.+\\.vue$': '@vue/vue3-jest'.'.+\\.(css|scss|png|jpg|svg)$': 'jest-transform-stub'
  },
  testMatch: ['<rootDir>/__tests__/**/*.spec.js']}Copy the code

Run the YARN test again. The PASS succeeds 🎉

Configuration alias

In real projects, we typically use the alias configuration as the absolute path introduced, such as the @ symbol for SRC directories,

So how to use it in a single test, do you need to do some configuration?

Helloworld.vue: HelloWorld.vue: helloWorld.vue: helloWorld.vue: helloWorld.vue

// hello.spec.js
import { mount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'

test('displays message'.() = > {
  const wrapper = mount(HelloWorld, {
    props: {
      msg: 'Hello world'}})// Assert the rendered text of the component
  expect(wrapper.text()).toContain('Hello world')})Copy the code

Does yarn test report an error?

Execute the test, as expected, error:

FAIL  __tests__/hello.spec.js
  ● Test suite failed to run

    Cannot find module '@/components/HelloWorld.vue' from '__tests__/hello.spec.js'
Copy the code

In conjunction with the @alias symbol just mentioned, jest.config.js needs to be modified slightly:

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom'.moduleNameMapper: {
    "^ @ / (. *) $": "<rootDir>/src/$1"
  },
  transform: {
    '^.+\\.js$': 'babel-jest'.'^.+\\.vue$': '@vue/vue3-jest'.'.+\\.(css|scss|png|jpg|svg)$': 'jest-transform-stub'
  },
  testMatch: ['<rootDir>/__tests__/**/*.spec.js']}Copy the code

The moduleNameMapper parameter, which can be used to map a module path to another module, is shown in the official description:

Jestjs. IO/docs/config…

Restart yarn test, PASS 🎉

Unit test coverage

Because the JEST version is 27.x, the coverageProvider: “V8” parameter needs to be added to generate coverage reports

module.exports = {
  testEnvironment: 'jsdom'.moduleFileExtensions: ["js"."vue"].moduleNameMapper: {
    "^ @ / (. *) $": "<rootDir>/src/$1"
  },

  testMatch: ['<rootDir>/__tests__/**/*.spec.js'].transformIgnorePatterns: ['/node_modules/'].transform: {
    '^.+\\.js$': 'babel-jest'.'^.+\\.(vue)$': '@vue/vue3-jest'.'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub'
  },

  coverageDirectory: 'coverage'.coverageProvider: "v8".collectCoverageFrom: [
    'src/**/*.{js,vue}'.'! src/main.js'.'! src/App.vue'].coverageThreshold: {
    global: {
      branches: 40.functions: 80.lines: 90.statements: 80}}}Copy the code

Package. json add the following command:

"test:coverage": "jest --coverage"
Copy the code

Execute:

Yarn Run v1.22.17 $jest -- Coverage PASS __tests__/sum.spec.js PASS __tests__/hello.spec.js ----------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line#s 
----------------|---------|----------|---------|---------|-------------------
All files       |     100 |      100 |     100 |     100 |                   
 HelloWorld.vue |     100 |      100 |     100 |     100 |                   
----------------|---------|----------|---------|---------|-------------------

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        7.84 s
Ran all testSuites. ✨ Donein11.21 s.Copy the code

Associated Codecov

1, first enter the app. Codecov. IO/gh/pdsuwwz /… Codecov should prompt you to authorize Github. Click Authorize

2. After the authorization is completed, you can select which Github project to associate with, such as VUe-Unit

3. Click on the name and you should be presented with a token like this:

Click Copy to Copy, and then we will enter the key secrets setting page of github corresponding project:

Create a new token and name it CODECOV_TOKEN (CODECOV_TOKEN is used for convenience in github CI)

4. After creating the token, we need to create a Github CI

In the first place in the project root directory to create. Making/workflows/unit.and yml file

Write in the file:

name: Unit-Testing

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 12.20.x

      - name: Install dependencies
        run: yarn install

      - name: Testing
        run: yarn test:coverage
        env:
          CI: true
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v1
        with:
          token: The ${{ secrets.CODECOV_TOKEN }}
Copy the code

Note the last ${{secrets.codecov_token}}, github Action will get the secrets token we just created from the secrets when executing this workflow

5. Show the Codecov badge

Push code to Github, and github automatically executes the workflow

After the workflow is executed, we can write in readme.md:

[! [codecov] (https://codecov.io/gh/pdsuwwz/vue-unit/branch/main/graph/badge.svg(a)]https://codecov.io/gh/pdsuwwz/vue-unit)
Copy the code

Just change pdSUwwz to your username and vue-Unit to your repository name.

You can try it. It should look like this:

✿ Angry (° °) Blue ✿

📦 Warehouse address: vue-Unit, welcome ✨ Star ✨ ~~