Not long, not long ago

It is said that a company has two front end, every day lui bug, why? Only blame test MM tilt people country, light language brother has a bug. ✧(๑• ㅂ•́)و✧ but recently the two have become slightly paranoid about σ (flying ° д °). っ. Testing MM has several times to mention the urgent bug, in the side to encourage them to change the bug, but the online bug screening is more trouble, but also found not to change after the change, provoked test MM tears, good life. What to do?

The very rare rare bug was detected in the E2E simulator Cypress, and the SM smiled and told him: “666 is very nice of you!” Test MM after the new bug all ignore him ≡ ﹏ ̄≡

As an ideal front-end who seeks bug-free code and works with TESTERS to communicate with them, I felt compelled to learn how to use Cypress to test E2E in order to improve the quality of my code. So let’s take a look at getting started with the Cypress testing framework.

Cypress three questions. – Who are you

Cypress is an out-of-box E2E testing framework built on mocha-style apis. Compared to other testing frameworks, cypress provides its own best practices, requires no other testing libraries, is easy to configure, but extremely powerful. It can be configured using the WebPack project, and provides a powerful GUI graphical tool. Easy to get started, easy to use, how comfortable how to ah (. – > ‿ please.

The cypressGUI test uses a real browser, while the non-gui test uses chrome-headless, instead of simulation, to more truly show the test process and results in the actual environment.

Cypress three questions. – What’s your advantage

Cypress has several built-in features:

  • Come with GUI tool, want to test what point what, also can view the whole test process, want to record screen also can record screen yo (record screen can be sent to test MM see, sure she said brother really fierce yo. For one I don’t tell the danjun 乛◡乛 danjun)
  • Each step of the test has a snapshot, you can use the GUI tool to view the page status of each process, not a screenshot but a real page DOM environment!
  • With mock data and request interception mechanisms, it is easy to recover bugs caused by online data
  • And wepBAKc configuration, no matter modify test file or test code can be automatically retested
    • Tip: Test cases can be addedonlyorskipTo avoid retesting all use cases in the test file:It. Only (' Test this only '); Skip (' Don't test this ');

Cypress three questions – How to use

The installation

  • yarn add cypressornpm install cypress
  • After the installation,./node_modules/.bin/cypress installInstall the Cypress environment (including GUI tools)

configuration

  • Package. json: Configure both GUI and non-GUI (terminal) modes to run Cypress
    "scripts": {
        "cypress": "cypress run",
        "cypress-gui": "cypress open",
Copy the code

⚠️ After the configuration, run YARN Cypress [-gui] or NPM run cypress[-gui](parentheses mean optional) to initialize cypress and generate default configurations and directories

  • Cypress. json(the same directory as package.json): Cypress provides a flexible configuration that allows you to customize your behavior to suit your needs, such as the following configuration I have for a project
{
    "baseUrl": "http://localhost:8080".// Local dev service address (webpack-dev-server)
    "integrationFolder": "src".// Customize "SRC" as the test file root, default is "cypress/integration"
    "testFiles": "**/*.cypress.spec.js".// Custom test file matching re, default is "**/*.*", that is, all files
    "videoRecording": false.// Disable screen recording. If screen recording is enabled, add the "cypress/screenshots" directory to ".gitignore" to avoid accidentally adding screen recording to Git
    "viewportHeight": 800.// Set the height of the page view of the test environment
    "viewportWidth": 1600 // Set the width of the page view of the test environment
}
Copy the code
  • Cypress/plugins/index. Js: cypress running environment configuration, which can be used to configure webpack, etc. The following is an example of configuring the Webpack alias. No configuration is required here by default.
// See the official example address https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/preprocessors__typescript-webpack/cypress/plu gins/index.js
const wp = require("@cypress/webpack-preprocessor");
const path = require('path');

function resolve(dir) {
    return path.join(__dirname, ".. /..", dir);
}

module.exports = on= > {
    const options = {
        webpackOptions: {
            resolve: {
                alias: {
                    "@": resolve("src"),
                    cypress: resolve("cypress"}}}}; on("file:preprocessor", wp(options));
};
Copy the code

We’re all set. Beta beta

  • A simple example
describe('Test page contains an element', () => {
    it("The front brothers are so handsome, the front sisters are so beautiful.", () => {
        cy.contains("The front brothers are so handsome, the front sisters are so beautiful.");
    });

    it('Have a link', () => {
        cy.get('a').should('have.length'.1);
    });

    it('There is no element of class containing ABC', () => {
        cy.get('.abc').should('have.length'.0);
    });
});
Copy the code
  • Examples of interaction
describe('Move together', () => {
    it('Get the input field, type the text and press Enter', () = > {const text = 'not exist';
        / / type API usage: https://docs.cypress.io/api/commands/type.html#Usage
        cy.get('input').type(`${text}{enter}`);
    });

    it('Click the button', () => {
        cy.get('button').click();
    });
});
Copy the code
  • Network request mock example

The path match for Tip1: cy.route is strict, so be careful if wildcards are required. Cy.route (‘/ API /search’, []) will not intercept/API /search? Keyword = ABC, which only intercepts/API /search.

Cy. route(‘/ API /posts’) and cy.route(‘POST’, ‘/ API /posts’).

describe('Give me what YOU want', () => {
     beforeEach((a)= > {
        cy.server(); // It must be called before cy.route
        cy
            .fixture('/posts/list.json') // We created the mock data in cypress/fixtures
            .as('postsData'); // Alias the mock data to be used later by cy. Route
        cy
            .route('/api/posts'.'@postsData')
            .as('getPostsRoute'); // Alias the request for cy.wait
    })

    it('Go to the list page and intercept the list request interface', () => {
        cy.wait('@getPostsRoute'); // Wait for the intercepted interface request to complete

        cy.get('.post').should('have.length'.10); // There should be 10 pieces of data rendered to the page
    });
})
Copy the code
  • Example of a real-world scenario: Combining all of the postures above, we now test the search and action results of the search page
describe('test search page', () = > {// Several route path variables
    const searchRoutePath = '/api/items/activities? query=*';
    const deleteActivityRoutePath = '/api/activities/*/items/batch? num_iids[]=*';
    const undoActivityRoutePath = '/api/activities/*/items/undo';

    function search(keyword) {
        // Encapsulate the search behavior and wait for the search to return
        cy
            .fixture('items/activities.json')
            // Handle mock data and return only data that matches the search structure
            .then(data= > data.filter(item= >item.title.indexOf(keyword) ! = =- 1))
            .as('searchResult');
        cy.server();
        cy.route(searchRoutePath, '@searchResult').as('searchRoute');

        const input = cy.get('input');
        input.clear(); // Clear the text in the input box

        input.type(`${keyword}{enter}`);

        cy.wait('@searchRoute');
    }

    before((a)= > {
        // Before running any tests, visit the search page
        cy.visit('/activities/search');
    });

    it('should show no data tip when search result is empty', () = > {const text = 'not exist';
        search(text);
        cy.contains('Did not find about${text}The results of the `);
    });

    it('should remove activity from list when clean successful', () => {
        search('success');

        cy
            .route('delete', deleteActivityRoutePath, {
                success: 0.fail: 0.waiting: 0,
            })
            .as('deleteActivityResponse');

        // Within keeps the cy context within the dom node '. Activities-search '
        // The default cy execution is the result of the previous cy command as the context
        / / such as "cy. Get (' a '); Cy. Get ('span')", cy will look for 'span' in the 'a' tag found in the previous command
        cy.get('.activities-search').within((a)= > {
            const items = cy.get('.result-item');
            items.should('have.length'.1);
            const applyList = items.get('.apply-list');

            applyList.should('not.be.visible'); // The detailed content area within each data item is hidden

            const toggleBtn = items.get('.item-apply-count');
            toggleBtn.click(); // Click to display the details area
            applyList.should('be.visible');
            applyList.children().should('have.length'.1); // There is only one data item in the detailed content area

            const cleanBtn = cy.contains('exit');
            cleanBtn.click(); // Click the "Exit" button in the details area

            cy.wait('@deleteActivityResponse'); // Wait for the exit request to return
            cy.get('.apply-list').should('be'.null); // After the exit is successful, the data in the details area is reduced by 1, that is, empty
        });
    });
});
Copy the code

Several must-read documents

  • network-requests : https://docs.cypress.io/guides/guides/network-requests.html
  • assertions : https://docs.cypress.io/guides/references/assertions.html
  • Recipes example: https://docs.cypress.io/examples/examples/recipes.html
  • Code completion code prompt: https://docs.cypress.io/guides/tooling/intelligent-code-completion.html

About Test Coverage

Currently Cypress does not have built-in test coverage statistics, there is a special issue on Github that tracks this, there should be one in the future. There are also several temporary solutions on issue, I prefer to use chrome’s own to view them at present. Open DevTools in the test browser opened by the GUI, cut to Sources, press CMD + Shift + P (For Windows users, press CTRL + Shift + P), type Coverage, select refresh and count code execution coverage.

So, get high

In order to high quality (test) generation (M) code (M), high up. Like front-end MM can teach up (¬_¬)


This article was first published on my official account: Maple Leaf. Interested can long press the qr code below attention. ^v^