Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 30, 2021 02:49 pm GMT

What is your testing approach when working on fast-pace projects?

Hey guys, I'm wondering how you tackle testing React-based apps. Particularly, I'd like to hear your thoughts about testing rapidly changing products like MVPs.

For a long time I was a big fan of e2e tests. However, many of my past teams struggled setting them up or/and were underestimating their value. Instead, the most common way of testing I observed is unit (I suppose) testing with jest + testing library + axios-mock-adapter (or some other request mocking libs). And here is my inner struggle: in my opinion, very granular unit testing on a MVP isn't the most efficient as often its implementation radically changes. I believe the main purpose of tests on MVP is to lock the current state of UI so the future implementation changes don't break what's been already working. Of course, one will argue that the more tests the better, but the reality is that we need to choose what will work best in a given time-frame (often very limited). Therefore, I worked out my own pattern which is a sort of hybrid:

  • I test entire pages (mocking routing)
  • I mock auth-related action(s)
  • I mock actions which manipulate URL
  • I even mock Web Workers if necessary
  • I mock all AJAX requests with axios-mock-adapter in a way which lets me wait for those calls (a combination of spies and waitFor)
  • My tests are driven by AJAX calls i.e. it's AJAX calls which indicate when certain interaction has been completed
  • I often use snapshots and treat them carefully when they fail

See this stripped-out real world example:

import React from 'react';import { ExamplePage } from '../pages';import { screen, waitFor, fireEvent } from '@testing-library/react';import axios from 'axios';import MockAdapter from 'axios-mock-adapter';import mocks from '../mocks/someCollectionEdit.json';import renderPage from './helpers/renderPage';const API_BASE_URL = '/api';jest.mock('../actions/getters/user.ts', () => {  const actions = jest.requireActual('../actions/getters/user.ts');  actions.authenticateUser = jest.fn();  return actions;});jest.mock('../workers/someWorker/someWorker.client.ts');jest.mock('../actions/setters/url.ts');describe('render example page', () => {  let mock;  const mockRequests = () => {    // used by waitFor() in tests    const spies = {      [`${API_BASE_URL}/user`]: jest.fn(),      [`${API_BASE_URL}/organizations`]: jest.fn(),      [`${API_BASE_URL}/some-collection/example-id?someFilter=filter1&organizationId=2`]: jest.fn(),      [`${API_BASE_URL}/some-filters/example-id`]: jest.fn(),      [`${API_BASE_URL}/some-collection/details/example-id`]: jest.fn(),      // ...    };    // mocking calls which may include query strings    ((url) =>      mock.onGet(url).reply((config) => {        process.nextTick(() => spies[config.url]());        return [200, mocks[config.url]];      }))(new RegExp(`${API_BASE_URL}/user$`));    ((url) =>      mock.onGet(url).reply((config) => {        process.nextTick(() => spies[config.url]());        return [200, mocks[config.url]];      }))(new RegExp(`${API_BASE_URL}/organizations$`));    ((url) =>      mock.onGet(url).reply((config) => {        process.nextTick(() => spies[config.url]());        return [200, mocks[config.url]];      }))(      new RegExp(        `${API_BASE_URL}/some-collection/example-id\\?.*`,      ),    );    ((url) =>      mock.onGet(url).reply((config) => {        process.nextTick(() => spies[config.url]());        return [200, mocks[config.url]];      }))(      new RegExp(        `${API_BASE_URL}/some-filters/example-id$`,      ),    );    ((url) =>      mock.onPost(url).reply((config) => {        process.nextTick(() => spies[config.url]());        return [200, mocks[config.url]];      }))(      new RegExp(        `${API_BASE_URL}/some-collection/example-id/data-draft$`,      ),    );    ((url) =>      mock.onPut(url).reply((config) => {        process.nextTick(() => spies[config.url](), 0);        return [200, mocks[config.url]];      }))(      new RegExp(        `${API_BASE_URL}/some-collection/example-id/data$`,      ),    );    // ...    return spies;  };  beforeAll(() => {    mock = new MockAdapter(axios);  });  afterEach(() => {    mock.reset();  });  it('should edit some form with a confirmation modal', async () => {    const spies = mockRequests();    renderPage(ExamplePage, {      route: '/organizations/:organizationId/some-collection/:collectionId/record/edit',      url: '/organizations/2/some-collection/example-id/record/edit',      search: '?someFilter=filter1',    });    await waitFor(() => // page has been rendered with all the necessary data      expect(        spies[          `${API_BASE_URL}/some-collection/example-id?someFilter=filter1&organizationId=2`        ],      ).toHaveBeenCalledTimes(1),    );    const inputField = screen.getByDisplayValue(/example value/i);    const saveChangesButton = screen.getByText(/Save changes/i);    fireEvent.change(inputField, { target: { value: 'updated value' } }); // user action    fireEvent.click(saveChangesButton); // user action    await waitFor(() => // data draft has been sent      expect(        spies[          `${API_BASE_URL}/some-collection/example-id/data-draft`        ],      ).toHaveBeenCalledTimes(1),    );    expect(screen.getByText(/Save some collection changes changes\?/i)).toBeInTheDocument();    expect(screen.getByText(/updated value/i)).toBeInTheDocument();    fireEvent.click(screen.getByText(/Confirm/i)); // user action    await waitFor(() => // data has been submitted      expect(        spies[          `${API_BASE_URL}/some-collection/example-id/data`        ],      ).toHaveBeenCalledTimes(1),    );    expect(      screen.getByText(        /Some collection records has been successfully changed./i,      ),    ).toBeInTheDocument();  });  // ...});

Please share your thoughts about this matter and feel free to criticise my approach and suggest what would be better based on your commercial experience. Also, Happy New Year!


Original Link: https://dev.to/chrisczopp/what-is-your-testing-approach-when-working-on-fast-pace-projects-465e

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To