3. Unit testing – Effective Volto – Testing

Unit testing

3. Unit testing#

Unit testing in Volto is achieved using Jest as the test runner. Unit testing is best used to test components or utilities in isolation.

Here's an example of a unit test in Volto.

Note

Notice the use of snapshots to facilitate making broad assertions of how a component would render. This type of testing is only useful as a "sanity check", as it can be tedious to model the complex behavior of components using the @testing-library/react package. But the "utility" and "service" type of code can be fully tests, in rich environment similar to Python's testing libraries.

import React from 'react';
import configureStore from 'redux-mock-store';
import { Provider } from 'react-intl-redux';
import { MemoryRouter } from 'react-router-dom';
import { waitFor, render, screen } from '@testing-library/react';

import Diff from './Diff';

const mockStore = configureStore();

jest.mock('react-portal', () => ({
  Portal: jest.fn(() => <div id="Portal" />),
}));

jest.mock('@plone/volto/helpers/Loadable/Loadable');
beforeAll(
  async () =>
    await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
);

describe('Diff', () => {
  it('renders a diff component', async () => {
    const store = mockStore({
      history: {
        entries: [
          {
            time: '2017-04-19T14:09:36+02:00',
            version: 1,
            actor: { fullname: 'Web Admin' },
          },
          {
            time: '2017-04-19T14:09:35+02:00',
            version: 0,
            actor: { fullname: 'Web Admin' },
          },
        ],
      },
      content: {
        data: {
          title: 'Blog',
          '@type': 'Folder',
        },
      },
      schema: {
        schema: {
          fieldsets: [
            {
              fields: ['title'],
            },
          ],
          properties: {
            title: {
              title: 'Title',
              type: 'string',
            },
          },
        },
      },
      diff: {
        data: [
          {
            title: 'My old title',
          },
          {
            title: 'My new title,',
          },
        ],
      },
      intl: {
        locale: 'en',
        messages: {},
      },
    });
    const { container } = render(
      <Provider store={store}>
        <MemoryRouter initialEntries={['/blog?one=0&two=1']}>
          <Diff />
        </MemoryRouter>
      </Provider>,
    );
    await waitFor(() => screen.getByTestId('DiffField'));
    expect(container).toMatchSnapshot();
  });
});

This example was chosen specifically because it shows two potential tricky situations in unit testing:

  • lazy-loaded libraries, and

  • stateful components, that change their rendered content during their lifecycle.

So, when dealing with lazy-loaded libraries, we have to mock the lazy-loading process and fully load them before we can do the test:

jest.mock('@plone/volto/helpers/Loadable/Loadable');
beforeAll(
  async () =>
    await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
);

And to solve the second part, we use await the component to finish updating before we test its rendered output:

    await waitFor(() => screen.getByTestId('DiffField'));
    expect(container).toMatchSnapshot();