When writing components, verify whether components can be used, usually in the page, but this is more cumbersome, need to use their own mouse to trigger, the efficiency is very low. It is unknown whether the component will still work if the requirements change a bit.

In order to ensure the quality of components, it is necessary to introduce unit tests. When requirements change, unit tests may not be compiled, so that bugs can be corrected at the first time to ensure the quality of components.

Unit testing

Unit tests generally fall into two types of BDD and TDD:

  • BDD: Behavior driven development,Behavior-driven development
  • TDD: Test-driven development,Test-driven development

Behavior-driven development is used to simulate user behavior and describe requirements in natural language. Test-driven development is fulfilling product requirements;

In unit testing, there is a concept called Assert. It means I make a subjective assumption that something is true. If it is true, nothing will happen.

The installation

The tools used here are:

  • KarmaIs a test runner that calls up the browser, loads the test script, and then runs the test case
  • MochaIs a unit testing framework/library that can be used to write test cases
  • SinonIs aspy/stub/mockLibrary to aid in testing

Install related plug-ins:

npm i -D karma karma-chrome-launcher karma-mocha karma-sinon-chai mocha sinon sinon-chai karma-chai karma-chai-spies
Copy the code

Create a new karmap.conf. js file in the root directory and add CSS to the files file, otherwise the style section cannot be tested.

module.exports = function (config) {
  config.set({
    basePath: "".frameworks: ["mocha"."sinon-chai"].client: {
      chai: {
        includeStack: true,}},files: ["dist/**/*.test.js"."dist/**/*.test.css"].exclude: [].preprocessors: {},
    reporters: ["progress"].port: 9876.colors: true.logLevel: config.LOG_INFO,
    autoWatch: true.browsers: ["ChromeHeadless"].singleRun: false.concurrency: Infinity}); };Copy the code

Writing unit tests

Component unit test writing is divided into four parts:

  • Check whether the component exists on the page
  • Component properties are set correctly
  • Is the component’s style loaded correctly
  • Whether the component event is triggered

The preparatory work

Introduce dependencies before writing test cases

const expect = chai.expect;
import Vue from "vue";
import Button from ".. /src/button";
Copy the code

Several concepts in unit testing

Describe is a set of use case tests that can be nested

describe("Button", () = > {// Do button-related unit tests
});
Copy the code

Each IT corresponds to one unit test case

it("", () = > {// Related test code
});
Copy the code

Only, the skip

  • onlyUnder the current parent Describe block, only tests are performed for that unit
  • skipSkip testing for this unit under the current parent Describe block
describe("Button", () => {
  describe.only("Only the test unit is executed under the parent Describe block", () => {
    it.skip("Skipped test unit", () = > {}); }); });Copy the code

Check whether the component exists on the page

it("Does the component exist on the page?", () => {
  except(Button).to.be.ok; // Check whether there are components in the page
});
Copy the code

Component properties are set correctly

  • ButtonComponent attributesicon, is used to setButtonThe icon
  • ButtonComponent attributesloading, is used to setButtonIn the load icon, it andiconThere can only be one.

From this use case analysis, you can see that there are two test cases to be written here.

Case 1:

it("Icon can be set", () = > {const Constructor = Vue.extend(Button);
  const vm = new Constructor({
    propsData: {
      icon: "settings",
    },
  }).$mount(); // Mount it in memory
  const useElement = vm.$el.querySelector("use"); // Get the use element
  expect(useElement.getAttribute("xlink:href")).to.eq("#i-settings"); // Get the attribute of the use element and use the assertion to check if xlink:href is #i-settings
  vm.$destroy();
});
Copy the code

Case 2:

it("Set loading", () = > {const Constructor = Vue.extend(Button);
  const vm = new Constructor({
    propsData: {
      loading: true.icon: "settings",
    },
  }).$mount();
  const useElement = vm.$el.querySelectorAll("use"); // Get all use elements
  expect(useElement.length).to.equal(1); // Check that the number of use elements is not equal to 1, because only one loading and Settings can occur
  expect(useElement[0].getAttribute("xlink:href")).to.eq("#i-loading"); // Check whether xlink:href is #i-loading with an assertion
  vm.$destroy();
});
Copy the code

Is the component’s style loaded correctly

The icon may appear to the left or right of the text, and we control the component through CSS. When writing the test case, we need to check whether the style is correct.

  • iconDefault styleorderfor1
  • When setting theiconPositionLater,icontheorderfor2

To test the style, you need to mount the component to the page, so to write the test case, you need to mount the component to the page

Case 1:

it("Icon default order 1", () = > {const div = document.createElement("div");
  document.body.appendChild(div);
  const Constructor = Vue.extend(Button);
  const vm = new Constructor({
    propsData: {
      icon: "setting",
    },
  }).$mount(div); // Mount to the page
  const svgElement = vm.$el.querySelector("svg");
  expect(getComputedStyle(svgElement).order).to.eq("1"); // Check whether the SVG element's style order defaults to 1
  vm.$el.remove(); // Elements mounted to the page need to be destroyed
  vm.$destroy();
});
Copy the code

Case 2:

it("Set iconPosition to change order", () = > {const div = document.createElement("div");
  document.body.appendChild(div);
  const Constructor = Vue.extend(Button);
  const vm = new Constructor({
    propsData: {
      icon: "settings".iconPosition: "right".// Set iconPosition to right
    },
  }).$mount(div);
  const svgElement = vm.$el.querySelector("svg");
  expect(getComputedStyle(svgElement).order).to.eq("2"); // With iconPosition set to right, check whether the SVG element's style order defaults to 1
  vm.$el.remove();
  vm.$destroy();
});
Copy the code

Whether the component event is triggered

it("Button trigger click event", () = > {const Constructor = Vue.extend(Button);
  const vm = new Constructor({
    propsData: {
      icon: "settings",
    },
  }).$mount();
  const callback = sinon.fake(); // Create a function with sinon
  vm.$on("click", callback); // Bind events
  vm.$el.click(); // Click call
  expect(callback).to.have.been.called; // Check if it is called when clicked
  vm.$destroy();
});
Copy the code

In addition, wechat ttXBg180218 can be added for communication