As we all know, unit test function is an essential part of component library development, responsible for checking and verifying, ensuring the rationality and standardization of components. This article focuses on the exploration and practice of unit testing in NUTUI component library. We will explain how to write unit tests, continuous integration service and Coveralls automatic test code coverage in three aspects. As shown in the figure:

If you are interested in these contents, please come and take a look with me!

Unit test configuration

Before we get into the body of the unit test configuration, let’s look at the following two questions.

  • What is a unit test?
  • Why do we need unit tests?

What is a unit test?

Unit testing, which can check and verify the smallest testable units in software, is an important part of software development. It makes it easier to add new features and track down problems.

Why do we need unit tests?

Unit tests are useful during development, both to help developers think about how to design a component and to refactor an existing component. They run every time the code changes. With unit testing, we can deliver our code with confidence and no worries. Unit testing of components has the following advantages:

  • Provide documentation that describes the behavior of the component
  • Reduce debugging time and save manual testing time
  • Reduce bugs when developing new features and detect hidden bugs in features
  • Reduce and quickly locate bugs
  • Facilitate refactoring and ensure the safety of code refactoring

How do I write unit tests?

We are both the beneficiaries and developers of unit testing, so let’s get down to business and talk about how to add unit testing to the VUE component library. The tools used in unit testing can be roughly divided into three parts: test framework, test runner, and assertion library.

The test framework

Since we are a VUE component library, we use Vue Test Utils as the testing framework. It is the official vUE component unit testing library, with detailed instructions and custom Settings for testing. It is clearly documented and easy to use.

We installed it in the project as a development dependency:

npm install --save-dev @vue/test-utils

It is browser-dependent and can run in either a real browser or the Node virtual browser, since launching a real browser on a different platform is complicated. So we let it run in the Node virtual browser, which requires JSDOM to help us run tests in the Node virtual browser environment.

We use JSDOM as a development dependency installation:

npm install --save-dev jsdom jsdom-global

Then create an empty /test folder in the project root directory and create the setup.js file

require('jsdom-global')()

Set jsDOM manually at the test entry using jdom-global. This introduces JSDOM by executing the setup.js file every time the unit test is run.

Test runner

A test runner is a program that runs tests. There are a lot of Test runners, and Vue Test Utils basically supports mainstream JavaScript Test runners. On the better side, Vue Test Utils helped us filter through and recommended two Test runners to us, so we could just choose one of them.

  • Jest: the most full-featured test runner. It requires minimal configuration, has JSDOM installed by default, built-in assertions, and a very good command-line user experience.
  • Mocha – Webpack: A wrapper for Webpack + Mocha, with a smooth interface and listening mode.

The strategy for testing single-file components is to compile all the test files through Webpack and run them in the test runner. The advantage of using Mocha-WebPack is that we can get full single-file component support through webPack + vue-loader without compromising any of the source code. Although Jest also provides vuE-Jest preprocessors to handle the most common single-file components, it is still not 100% functional for Vue-Loader. So we chose mocha-Webpack.

Install Mocha, Mocha-WebPack via NPM:

npm install --save-dev mocha mocha-webpack

Note that Mocha-Webpack relies on WebPack and Mocha, and has version requirements. The Webpack version requires 4.x.x, and the Mocha version is 4.x.x & 5.x.x.

Assertions library

When we use Mocha for testing, we need to use it in conjunction with the assertion library. Mocha does not have a built-in assertion library like the Jest framework. It allows us to choose the appropriate assertion library ourselves. Expect is an assertion library, and its minimalist BDD style is recognized by many test frameworks, which also have built-in Expect assertion library, so we also use Expect assertion library this time.

First install the development dependencies:

$ npm install --save-dev expect

And write to test/setup.js:

global.expect = require('expect')

Make it globally available so you don’t need to import it in every test file.

Once the various development dependencies are installed, define an NPM script test command in the root package.json file

{..."scripts": {..."test": "cross-env NODE_ENV=test mocha-webpack --webpack-config dist_cli/webpack/test.config.js  --require dist_cli/test/setup.js src/packages/*/__test__/**.spec.js"},... }Copy the code

It is important to note that if your project does not have cross-env installed, you will need to do so first, which is used to set environment variables across platforms. To understand the meaning of the test command parameters:

  • –webpack-config: Specifies the Webpack configuration file to use for this test.
  • –require: ensures that the file test/setup.js will be run before any tests, so that we can setup the global environment required by the tests in this file.
  • The last parameter, SRC/directory: is the collection of all the test files covered by the test package.

With the above environment ready, NPM test can be executed from the command line. The effect is as follows:

The most basic unit tests have been configured, but we’re not done yet, so read on

Increase unit test code coverage

Coverage is both a measure of test integrity and a measure of test validity. Test coverage is a measure of how complete a test is. Mocha is the testing tool for the JavaScript project and Istanbul is the generation tool for the JS test coverage report. We use both to test the code and generate test coverage reports for the code base.

Nyc is the Istanbul command line interface that we installed in the project as a development dependency:

$ npm install --save-dev nyc 
Copy the code

Then add nyc to the NPM script above

{..."scripts": {..."test": "cross-env NODE_ENV=test nyc mocha-webpack --webpack-config dist_cli/webpack/test.config.js --require dist_cli/test/setup.js src/packages/*/__test__/**.spec.js"},... }Copy the code

You also need to configure nyc in package.json:

{..."nyc": {
    "include": [
        ".. /.. /.. /src/packages/**/*.vue"]."reporter": [
        "lcov"."text"]."instrument": false."sourceMap": false},... }Copy the code

This section describes the meanings of parameters.

  • Include: test file path
  • Reporter: Output lCOV (lcov.info + HTML report) and text coverage reports
  • Instrument and sourceMap: Set to false, disable NYC to instrumenting and sourceMap your code, then we specify loader to do it.

To get a test coverage report for the code base, run the NPM test command.

As shown, there are many Unknow, obviously there are some problems, need to install the Istanbul – instrumenter – loader, and then add the loader to our test. The config. Ts in the configuration file. Import the configuration file package.conf.ts of the generated environment into merge.

import { ROOT_PACKAGE_PATH } from '.. /common/dic';
import { packageConfig } from './package.config';
import merge from 'webpack-merge';
module.exports =  merge(packageConfig(false), {
    module: {
        rules: [
            {
                test: /\.(js|ts)/,
                use: {
                    loader: 'istanbul-instrumenter-loader',
                    options: { esModules: true }
                },
                include: [ROOT_PACKAGE_PATH('src/packages')]}, {test: /\.css$/,
                use: [
                    'style-loader'.'css-loader',]}, {test: /\.scss$/,
                use: [
                    'style-loader'.'css-loader',
                    {
                        loader: 'sass-loader',
                        options: { 
                            prependData: `@import "@/styles/index.scss"; `
                        }
                    }
                ]
            }
        ],
    },
    devtool: 'inline-cheap-module-source-map',
    externals: [require('webpack-node-externals')()] // Ignore all modules in the node_modules folder});Copy the code

At this point, the whole project code coverage statistics basic configuration is completed, it is worth noting that the Istanbul – instrumenter – loader must be placed on the top, make sure it finally, then we in the terminal execution of NPM test test coverage results will be shown.

Also, in the project root directory, the Coverage folder is automatically created, which contains the generated test coverage report file (icov.info + HTML).

Next we will introduce continuous integration services

Continuous integration services

Continuous integration refers to automatically running builds and tests whenever code changes and reporting back the results. Integrating new code into the trunk after ensuring that it meets expectations can help improve project quality. Continuous integration enables automatic compilation, packaging, and signing of projects, and continuous integration + automated testing can be achieved with unit testing. Our project is maintained on Github. Github has a good friend Travis CI, an online hosted distributed continuous integration service that we can use to build and test software projects hosted on Github. You can easily sync your Github projects with Travis CI, and you can test your projects in minutes.

It’s worth noting that Travis CI is free and self-paid. For our open source projects on Github, you can use the free version.

Here’s how to test your Github project with Travis CI.

First, access the Travis CI and log in using the project’s Github account. After logging in, Travis grants access to all of your Github repositories on behalf of your Github. Select the warehouse that you need Travis CI to help you integrate continuously and click the activation switch on the right. This way Travis CI will help you listen to all changes to the repository automatically build and complete the scheduled operations.

Next, we need to add a.travis. Yml file to the root of our repository to tell Travis CI to define the predetermined commands that will tell Travis CI what to do and how to do it. Configure the following parameters and you can change them as required:

sudo: required
language: node_js
node_js:
- '8'
script:
- npm test
- npm run coveralls
Copy the code

Travis’s running process is simple and consists of two phases: Install (installing dependencies) and script (executing scripts). For Node projects, both the Install and Script stages have default scripts that can be omitted if they do not need to be modified. To understand the meaning of parameters:

  • Sudo: Required Indicates that sudo permissions are required.
  • Language: specifies the language of the project. Node_js specifies the running environment as Node.
  • Node_js: Specifies the Node version. Multiple Node versions can be specified.
  • Install: Installation dependency, used to specify the installation script, the default script is NPM install
  • Script: Used to specify build or test scripts. The default script is NPM test.

There are many other parameters, I will not list them one by one, you can check the official website configuration

After completing the above steps, push this file to your Github repository. Every time he then pushes code to the Github repository, Travis finds the file and executes the predefined commands.

You can see the results of the run here, and you can click to see the details of the build process. If there is an error in the script build phase, the status will be displayed as a failure if there is a single failure.

This is a simple Travis CI and Github project association process.

Travis CI is really awesome. If you want to see the CI result logo directly on Github projects, just click on the icon, select MarkDown, and copy the contents of the Result text box into the readme.md file on Github.

Coveralls automatically tests code coverage

Finally, we want to generate a code coverage report, where Coveralls are required. Coveralls supports projects on Github and can also integrate with Travis CI. Go to coveralls. IO /, log in using the Github account, click Add Repo above, and set the button to ON

Click the right detail and click Detials to enter the detailed configuration page. On the right side of the page, obtain the token of the project, edit the corresponding configuration file according to your environment type, add the.coverall.yml file under the root directory, and add the following content:

service_name: travis-ci
repo_token: bOzghLfr6hi9x**************56vdl1YG
Copy the code

The test report uploaded to Coveralls needs to have a unified LCOV format. We have configured NYC above, generated lcov.info in the root directory coverage folder, and added the following command to the scripts field of package.json file

 "coveralls": "cat ./coverage/lcov.info | coveralls".Copy the code

Push the code to the Github repository. Again, we can get a test coverage logo and go to the details configuration page. Click the button to copy the Markdown content to the readme.md file on Github.

conclusion

The unit testing function has been integrated into the NUTUI component library developed by our team. NUTUI is a JINGdong style mobile Vue component library that develops and serves enterprise-class front, middle and back end products for mobile Web interfaces. With NutUI, you can quickly build unified pages to improve development efficiency. At present, there are nearly 50 components, which are widely used in JD’s various mobile business. In the future, we will reform the entire NutUI system architecture by removing the entire component library building tool and using the WebPack Node API to make more fine-grained control over compilation. At the same time, we will increase the optimization and adjustment of compilation configuration to greatly improve performance and reduce the size of packaged files. Provides independently built NutUI-CLI. The functionality of unit testing also ensures that components are normalized and errors are reduced. Welcome to use, if there is any problem in the use, we will timely feedback follow-up. Fleeting smile throw, the future can be ~

Finally, this is the NUTUI component library official website, welcome to scan the experience ~