Over the last few months, I’ve been exploring scenarios and scenarios for automated front-end UI testing. At the beginning, faced with a large number of technology selection, I was a little confused, and the team did not have much experience in this area, so we could only explore and summarize step by step. Of course, during the period, we also stepped on a lot of holes, and finally formed a relatively stable test program, which will continue to expand and improve in the future.

Project address: Jest-puppeteer-testing

In this article, I would like to share with you my thoughts and experience on UI automation testing.

Why UI automation testing

Business updates and iterations are frequent, and most of the traditional tests are carried out manually and visually, which cannot meet the needs of agile product development and rapid iteration. And UI automation which make the return of the fully functional becomes simple, release the pure manual testing of human resources, and regression testing can cover all the logic of the scene, the efficiency of the test, and the efficiency of the whole development process is a lot of ascension, and can avoid a lot of subjective and objective factors lead to the missing or negligence.

Limitations of other testing methods:

Unit Testing

In fact, unit testing does help us find most of the problems, but in complex front-end interactions, unit testing alone does not really reflect the path of user operations, and the common scenario of unit testing is to test a set of features.

Snapshot Testing

The DOM structure does not fully reflect the visual effect of the page, and constant DOM structure does not necessarily mean constant style. In addition, most of the tools are React specific, and non-React applications have little support.

The author would like to say:

Many people believe that UI changes frequently, resulting in high maintenance costs and low cost performance of test cases. Therefore, UI automated testing is suitable for businesses with stable scenarios. No, the UI here is more about business logic than just vision. The UI can be changeable, but the business logic is bound to be stable, especially in the core business, and think about how hard it is for users to adapt to a product whose business logic changes so frequently.

About technology selection

TypeScript + Jest + Puppeteer

In fact, there is not much difference between many frameworks for UI automation testing, and it has never been a critical factor in the robustness of the entire set of test cases. In contrast, how to improve the stability and comprehensiveness of test cases is an important detail for the implementation of UI automated test solutions.

Development practices

Project structures,

You can refer to jest-puppeteer-testing, which is not repeated here.

The core file

// setup/expect-image-snapshot.ts
// Let Jest support save/compare screenshots
import { configureToMatchImageSnapshot } from 'jest-image-snapshot';

expect.extend({
  toMatchImageSnapshot: configureToMatchImageSnapshot({
    customSnapshotsDir: '__image_snapshots__',})});Copy the code
// setup/enhance-puppeteer.ts
// Enhance puppeteer functionality, such as blocking requests and using mock data
import { onRequestInterceptor } from '.. /utils/request';

jest.setTimeout(30000);

beforeAll(async () => {
  page.on('request', onRequestInterceptor); // Intercepts requests, using proxy data
  await page.setRequestInterception(true);
});
Copy the code
// utils/request.ts
// Mock data core file
// Only XHR or FETCH requests are intercepted here, although you can extend it yourself
import { URL } from 'url';
import { Request } from 'puppeteer';
import mocks from '.. /mocks';

// Set the request interceptor data, used for the same request to return different results, effective once after the automatic destruction
export const interceptors: { [api: string] :any } = {};
export const setRequestInterceptor = (api: string, value: any) = > {
  interceptors[api] = value;
};

export const onRequestInterceptor = (request: Request) = > {
  const resourceType = request.resourceType();
  if (resourceType === 'xhr' || resourceType === 'fetch') {
    const location = new URL(request.url());
    const mockKey = location.pathname;
    if (mockKey && mocks.hasOwnProperty(mockKey)) {
      const mock = mocks[mockKey];
      let response: any;
      if (typeof mock === 'function') {
        response = mock({ location, request, interceptor: interceptors[mockKey] });
        delete interceptors[mockKey]; // It will be automatically destroyed after it takes effect once
      } else {
        response = mock;
      }
      if (response) {
        if(response.body ! =null && typeof response.body === 'object') {
          response.body = JSON.stringify(response.body); } request.respond(response); }}else{ request.continue(); }}else{ request.continue(); }};Copy the code

Other documents

  • shared.d.tsDefining data types
  • casesThe test cases are stored in the directory
  • mocksDirectory to store mock data
  • utilsDirectory to store tools

Note: Mock type definitions can be found in shared.ts, but you can add other type definitions here as well

experience

Test address selection (local/online)

  • Local server: Request response is fast, test results are stable, but problems caused by online environment differences or code packaging cannot be ruled out
  • Online server: can reflect the real display of the website, no need to start the server, can be tested at any time, but affected by network factors, may lead to unstable test results

Try to smooth out the effects of uncertainty

Such as maintaining the stability of data request results, date and time stability, to ensure the consistency of page rendering. If the page is rendered differently each time due to uncertainty in data return or timing, then it is useless.

Try to be specific about when to save the screenshot

For example, after visiting a page to take a screenshot, due to network factors, image resources are not always loaded, resulting in different screenshots.

. (Write this much for now, more at your leisure)

conclusion

In fact, the UI test automation solution is more like the end-to-end test (E2E Testing), which simulates a user program as a completely black box, open the application analog input, function and the interface is correct, check with screenshots can have an intuitive feel for some user interaction is a visual effect.

Project address: Jest-puppeteer-testing