background

There is an important link in the development process of the project UI walk-through. After the current developer restores the style, UI will compare the restoration of the page with his design draft. The norm I’ve seen is that there’s always a slight adjustment. Maybe the margins are 2px off, maybe the height is 3px too high. Very test UI vision, with everyone to find fault with the same. If there is a mistake in this walk check link, there is some error on the line, then the impact is very bad. In my opinion, the probability of online occurrence is very high, after all, it is not 100% accurate to compare with eyes only.

Therefore, in order to solve the above phenomenon in Web development, backstopJs came into our vision.

The official introduction of Backstop is as follows

BackstopJS automates visual regression testing of your responsive web UI by comparing DOM screenshots over time. BackstopJS automates visual regression testing of responsive Web UI by comparing DOM screenshots over time.

As you can see, Backstop solves the problem of automated UI regression testing. The main scenario is web responsive. So let’s go ahead and actually use it and see what surprises it can bring.

Explain in the order of actual development

How to use

Install backstopJs globally

$ npm install -g backstopjs
Copy the code

After the global installation is complete, the console can enter the backstop command to see the following description, then it indicates that the installation is successful. BackstopJS 5.1.0 CLI is used in this article

Create a folder, I’ll call it backstop-article

$ mkdir backstop-article && cd backstop-article
Copy the code

After entering the created folder, run the backstopJs init command to initialize the infrastructure project structure.

$ backstop init
Copy the code

After initialization, the terminal displays the following information:

Next, open the project and take a look at the directory structure.

First, analyze the directory structure

 |- backstop_data // Data files| - engine_scripts// Core configuration file
      |- puppet
        |- clickAndHoverHelper.js // Some script flow operations, such as click, hover, interaction, etc
        |- ignoreCSP.js // Mask the CSP security policy (detailed below)
        |- interceptImages.js // Block the image address and replace the image execution file. Configuration not here
        |- loadCookies.js // Load the cookie execution file.
        |- onBefore.js // The script executed before the page loads
        |- onReady.js // The script executed after the page loads
        |- overrideCSS.js // Style overwrites the execution file| - cookies. Json// Cookie configuration file| - imageStub. JPG// Image replacement placeholder| - backstop. Json// backstopJs configuration file
Copy the code

ignoreCSP.js

Content Security Policy (CSP) was created to prevent XSS attacks.

The essence of CSP is whitelisting. The developer clearly tells the client which external resources can be loaded and executed, which is equivalent to providing a whitelist. Its implementation and execution are all done by the browser, and the developer only needs to provide the configuration. CSP greatly enhances the security of web pages. Even if an attacker discovers a vulnerability, he cannot inject scripts unless he also controls a whitelisted trusted host.

There are two ways to enable CSP. One is through the content-security-Policy field of the HTTP header.

The above image was captured on Github

The other is through a
tag on a web page.

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
Copy the code

Take a look at the above introduction and brief introduction. Back in backstopJs, remember the ignorecsp.js file name and it’s easy to understand why it’s there. It’s necessary to block CSP because otherwise you might not be able to access some of the page’s data, resources, etc.

Perform the test

So let’s do that

$ backstop test
Copy the code

After execution, a page will pop up, as shown below:

It can be seen that there are some screening operations at the top, including successful screening, failed screening and fuzzy screening. The setting button at the upper right corner can adjust the display content of the comparison card below.

Now let’s look at the presentation card. The basic information of the current card is displayed in the upper left corner of the card.

The card center department is divided into three blocks: reference, test, and diff. But when you first start up, the page you see is the same as the screenshot above, only the test image. You will be prompted “no reference image found at present”. Since there is no reference picture, there is also no diff contrast picture on the right.

Take a look at the directory structure at this point.

The directory structure has changed a bit since the beginning, with two more folders

  • Bitmaps_test // Test comparison result Image result, internally identified by date + time folder name
  • Html_report // HTML file directory of the pop-up page

After a brief look at the page that pops up, let’s go back to the console where we just executed and see an Error at the bottom

These two sentences are in error

compare | Reference image not found backstop_default_BackstopJS_Homepage_0__0_phone.png
compare | Reference image not found backstop_default_BackstopJS_Homepage_0__1_tablet.png
Copy the code

Than steps when | not found reference pictures, picture name for backstop_default_BackstopJS_Homepage_0__0_phone. The PNG, named respectively are test cases ID_ selector name _ _ the screen size

How to create a reference image, there are several ways:

backstop approve

If the current screenshot is what you think is the reference template, the current test image will be saved as the reference image after executing this statement. This mode is usually used to generate reference images in batches. If the UI design can be batch imported to another site. However, our company does not have such a website, we can consider building one.

At the beginning, the url of the UI design library was used to generate reference pictures in batches. Then, after the reference pictures were generated, the address was changed into the address of the development environment, that is, the project address after we restored it. This allows for comparisons between the UI and developing the Web. Specific operations are as follows:

Perform backstop the approve

$ backstop approve
Copy the code

completed

Backstop_reference = bitmaps_test/

/

Inside the backstop_reference folder are two images of the size of the address you just tested. Now that you have a reference image in your project, execute the test command and you’ll see the complete screen below.

The reference picture was compared with the test picture, and no diff contrast picture was found. Since our control image was taken from the test site, it is identical. At this point, if you change the test address, you can see the diff image.

The above reference picture is still the official website picture of our Approve. I changed the first picture and several text colors in the second paragraph for the test address. It can be seen that in the diff comparison image, differences are highlighted and overlaid, so that a complete comparison is completed. (The red box in the picture was drawn by me to highlight the area).

Manual import

If you happen to be like me, the company does not have a website to display design, this time to manually import. When preparing for manual import, the most important thing is to know the naming method first. Above, we mentioned the naming method:

Backstop_default_backstopjs_homepage_0__0_phone.png. The names are test name_test Case ID_selector _ Screen size

This naming is the default, but can also be changed through configuration files.

{ 
  // ... FileNameTemplate: '{scenarioIndex} _ {scenarioLabel} _ {selectorIndex} _ {selectorLabel} _ {viewportIndex} _ {viewportLabel}'.// ... 
}
Copy the code

After the design draft exported from UI design is named according to convention, it can be directly compared.

If so, it’s not clear what the rules are, so we need to take a look at the backstop.json configuration file to see what configuration options are available.

The configuration file

{
  "id": "backstop_default".// Test case ID, used for screen capture naming. BackstopJS will automatically generate one for you to avoid naming conflicts with BackstopJS resources.
  "viewports": [ // Test a series of screen size objects for your DOM. Add as many as you need - but at least one
    {
      "label": "phone".// The phone is small
      "width": 320."height": 480
    },
    {
      "label": "tablet"./ / tablet
      "width": 1024."height": 768}]."onBeforeScript": "puppet/onBefore.js".// The script before executing the script
  "onReadyScript": "puppet/onReady.js".// The script after executing the script
  "scenarios": [ // Test case
    {
      "label": "BackstopJS Homepage".// Test name
      "cookiePath": "backstop_data/engine_scripts/cookies.json".// Set cookies This configuration file can be used to configure cookies for web sites that need to set cookies
      "url": "https://garris.github.io/BackstopJS/".// Necessary. Tell BackstopJS which endpoint/document you want to test. This can be an absolute URL or a local URL to your current working directory
      "referenceUrl": "".// Specify different states or environments when creating references.
      "readyEvent": "".// A predefined string is recorded to the console to trigger screen capture. -- Implement asynchronous interaction
      "readySelector": "".// Wait until this selector exists to continue -- implement asynchronous interaction
      "delay": 0./ / delay
      "hideSelectors": [].// The selector array set to visibility: hidden
      "removeSelectors": [].// Set the selector array to display: None
      "hoverSelector": "".// Move the pointer to the specified DOM element before taking a screenshot
      "keyPressSelectors": "".// Accepts an array of selectors and string values - simulates multiple sequential keystrokes.
      "clickSelector": "".// Click the specified DOM element before the screen capture.
      "clickSelectors": "".Puppeteer * only access the selctors array - simulates multiple sequential click interactions.
      "postInteractionWait": 0.Wait for the selector after interacting with hoverSelector or clickSelector (optionally accept wait times in ms. The idea is to click or hover element transformations. OnReadyScript is used by default.
      "selectors": [].// Select the selectors you want to capture
      "selectorExpansion": true.// Locate the element
      "expect": 0.If the number of selectors you expect to find matches the number of configured selectors, the test fails
      "misMatchThreshold": 0.1.// The percentage of different pixels allowed to pass the test
      "requireSameDimensions": true // The test must be the same as the reference size}]."paths": {
    "bitmaps_reference": "backstop_data/bitmaps_reference".// Store the sample image
    "bitmaps_test": "backstop_data/bitmaps_test".// Capture the output path
    "engine_scripts": "backstop_data/engine_scripts".// js configures the path
    "html_report": "backstop_data/html_report".// Display the HTML for the comparison diagram
    "ci_report": "backstop_data/ci_report"
  },
  "report": [ // The report format can be command-line or browser
    "browser"]."engine": "casper".Slimerjs (Gecko/Mozilla, need to install), Casper, Chromy (webKit)
  "engineOptions": { // Configure the default values for the engine properties
    "casperFlags": [
      "--engine=slimerjs"."--proxy-type=http"."--proxy=proxyIp:port"."--proxy-auth=user:pass"]},"asyncCaptureLimit": 5.// Capture 5 screens at a time
  "asyncCompareLimit": 50.// Configure the amount of RAM required during testing
  "debug": false.// Whether to print test logs
  "debugWindow": false."resembleOutputOptions": { // Compare the configuration of the output image
    "errorColor": {
      "red": 255."green": 0."blue": 255
    },
    "errorType": "movement"."transparency": 0.3."ignoreAntialiasing": true}}Copy the code

There are many configuration options, covering most of the screenshot requirements.

Test commands can execute specified configuration files and differentiate the environment from multiple configuration files

backstop test --config=<configFilePathStr>
Copy the code

Create backstop.config.js

module.exports = { Same object as backstop.json }
Copy the code

END

BackstopJs greatly reduces UI walk-through time, and can be used for automation. Git integration, Docker integration, Jenkins/Travis integration are all available, very powerful. This article serves as a gateway, and we will take some time to introduce backstopJs in automation integration. There are some interesting backstopJs logo pictures to share with you

Add 1:

  • What is Content Security Policy (CSP)? Why is it resistant to XSS attacks?

Previous articles are recommended

  • Pointfree in Functional Programming
  • The Concept of Side effects in Functional programming
  • Hindley-milner in Functional Programming