22. Testing – Mastering Plone Development

22. Testing#

It's good practice to write tests for the requirements of a project. The requirements become clearer. A path towards implementation is emerging.

This chapter is a starting point for testing in Volto.

For information on testing backend code, see the separate training: Testing Plone

Check out mastering-plone-project at tag search:

git checkout search

The code at the end of the chapter:

git checkout testing

More info in The code for the training

22.1. Test the rendering of a component#

With vitest you can create snapshots of components.

If the snapshot changes after a change in the code, you can check if the snapshot change was intentionally caused, and if not, rethink your changes.

  • Create a TalkView.test.js file as a sibling of frontend/packages/volto-ploneconf-site/src/components/Views/TalkView.jsx

  • You are testing the component TalkView. The test renders the component with some props:

 1import { render } from '@testing-library/react';
 2import { Provider } from 'react-intl-redux';
 3import configureStore from 'redux-mock-store';
 4import TalkView from './TalkView';
 5const mockStore = configureStore();
 6
 7const store = mockStore({
 8  intl: {
 9    locale: 'en',
10    messages: {},
11  },
12});
13
14test('renders a talk view component with only required props', () => {
15  const { container } = render(
16    <Provider store={store}>
17      <TalkView
18        content={{
19          title: 'Security of Plone',
20          description: 'What makes Plone secure?',
21          type_of_talk: { title: 'Talk', token: 'talk' },
22          details: {
23            'content-type': 'text/html',
24            data: '<p>some details about this <strong>talk</strong>.</p>',
25            encoding: 'utf8',
26          },
27        }}
28      />
29    </Provider>,
30  );
31  expect(container).toMatchSnapshot();
32});

Create a snapshot by running the tests:

make frontend-test

See the snapshot in folder __snapshots__. If this is a rendering you expect, you are good to go. For example you see that the heading is the talk title with preceding type of talk.

packages/volto-ploneconf/src/components/Views/__snapshots__/Talk.test.js.snap

// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`renders a talk view component with only required props 1`] = `
<div>
  <div
    class="ui container"
    id="view-wrapper talk-view"
  >
    <h1
      class="documentFirstHeading"
    >
      <span
        class="type_of_talk"
      >
        talk
        : 
      </span>
      Security of Plone
    </h1>
    <p
      class="documentDescription"
    >
      What makes Plone secure?
    </p>
    <div
      class="ui right floated segment"
    />
    <div>
      <p>
        some details about this 
        <strong>
          talk
        </strong>
        .
      </p>
    </div>
    <div
      class="ui clearing segment"
    >
      <p />
      <img
        class="ui small right floated image"
        item="[object Object]"
      />
    </div>
  </div>
</div>
`;

See also

Testing

22.2. Run an end-to-end acceptance test#

With Cypress you can run browser-based acceptance tests.

The following simple test checks if an editor can add an instance of the custom content type talk.

The test mimics the editor visiting her site and adding a talk via the appropriate menu action.

Create a test file frontend/cypress/tests/content.cy.js

 1describe('content type tests', () => {
 2  beforeEach(() => {
 3    cy.intercept('GET', `/**/*?expand*`).as('content');
 4    cy.createUser({
 5      username: 'editor',
 6      fullname: 'Editor',
 7      roles: ['Member', 'Reader', 'Contributor'],
 8    });
 9    cy.visit('/');
10    cy.wait('@content');
11  });
12
13  afterEach(() => {
14    cy.removeUser('editor', 'password');
15  });
16
17  it('As editor I can add a talk.', function () {
18    cy.autologin('editor', 'password');
19
20    cy.visit('/');
21    cy.wait('@content');
22
23    // when I add a talk with title, type and details
24    cy.get('#toolbar-add').click();
25    cy.get('#toolbar-add-talk').click();
26    // title
27    cy.get('input[name="title"]')
28      .type('Security in Plone')
29      .should('have.value', 'Security in Plone');
30    // type of talk
31    cy.get(
32      '#field-type_of_talk > .react-select__control > .react-select__value-container',
33    )
34      .click()
35      .type('talk{enter}');
36    // details
37    cy.get('.field-wrapper-details .slate-editor').type('This is the text.');
38    cy.get('#toolbar-save').click();
39
40    // Then a new talk should have been created
41    cy.url().should('eq', Cypress.config().baseUrl + '/security-in-plone');
42    // Then the title should read 'Talk: Security in Plone' with the type of talk mentioned
43    cy.get('body').contains('Talk: Security in Plone');
44  });
45});

To run the acceptance tests, it's recommended to start three individual terminal sessions, one each for running the backend, the frontend, and the tests themselves.

  1. In the first session, start the backend server.

    make acceptance-backend-start
    
  2. In the second session, start the frontend server.

    make acceptance-frontend-dev-start
    
  3. In the third session, start the Cypress test runner.

    make acceptance-test
    
  4. In the Cypress window, choose E2E Testing, since Volto's tests are end-to-end tests.

  5. In the next section, select the browser you want Cypress to run in. Although the core tests use Electron by default, you can choose your preferred browser for the tests development.

  6. In the main Cypress runner section, you will see all test specs.

  7. To run a test, click on the test spec you want to run.

See also

Helper functions for an auto login, creating content, etc. from Volto.