22. Testing – Mastering Plone 6 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.

Frontend chapter

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

Checkout volto-ploneconf at tag "vocabularies":

git checkout vocabularies

The code at the end of the chapter:

git checkout testing

More info in The code for the training

22.1. Testing the rendering of a component#

With jest you can create snapshots of components.

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

  • Create a Talk.test.js file as a sibling of Talk.jsx

  • You are testing the component Talk. The test is rendering the component with some props:

 1import renderer from 'react-test-renderer';
 2import { Provider } from 'react-intl-redux';
 3import configureStore from 'redux-mock-store';
 4import Talk from './Talk';
 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 component = renderer.create(
16    <Provider store={store}>
17      <Talk
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  const json = component.toJSON();
32  expect(json).toMatchSnapshot();
33});

Create a snapshot by running the tests:

make 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

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders a talk view component with only required props 1`] = `
<div
  className="ui container"
  id="view-wrapper talk-view"
>
  <h1
    className="documentFirstHeading"
  >
    <span
      className="type_of_talk"
    >
      Talk
      : 
    </span>
    Security of Plone
  </h1>
  <p
    className="documentDescription"
  >
    What makes Plone secure?
  </p>
  <div
    className="ui right floated segment"
  />
  <div
    dangerouslySetInnerHTML={
      Object {
        "__html": "<p>some details about this <strong>talk</strong>.</p>",
      }
    }
  />
  <div
    className="ui clearing segment"
  >
    <div
      className="ui dividing header"
    >
      Speaker
    </div>
  </div>
</div>
`;

See also

Testing

22.2. Testing permissions, features and user interface topics#

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 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});

With a frontend package NOT relying on a backend package, you could proceed with next step Run cypress tests.

Preparing acceptance backend with add-ons#

For a test like above, with talks, the acceptance backend needs the backend package with content type talk to be installed.

Have a look at /frontend/backend/, where a backend with the add-on ploneconf-site is configured. The configuration instructs to install the package from its repository and editable. So you can proceed developing the backend package while working on the frontend package. Necessary changes of the backend package while developing the couple of backend add-on and frontend add-on can be committed right out of /frontend/backend/sources/ploneconf.site.

Run cypress tests#

Go to your frontend folder, start the test backend and the test frontend. Then run the acceptance tests:

It's recommended to start three individual terminal sessions, one each for running the Plone backend, the Volto frontend, and the acceptance tests. All sessions should start from the frontend directory.

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

    make backend-install
    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 tests runner.

    make acceptance-test
    
  4. In the Cypress pop-up test style, 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 headless 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, interact with the file based tree that displays all possible tests to run, and click on the test spec you want to run.

Have a look in the code of volto-ploneconf to see that the continuous integration includes these cypress tests: .github/workflows/acceptance.yml. Commits to pull requests trigger a run of the tests.

See also

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