Skip to main content

Test

Unit tests

  • In this project, a unit test is expected to be a test without a database/network connection

  • The unit test file should suffix with .test

  • The jest config file is jest.config.js

  • run all unit test

    yarn test

E2E tests

  • In this project, the e2e test is expected to be a test with a database/network connection.

  • The e2e test file should suffix with .e2e-spec

  • The jest config file is jest.e2e.config.js

  • run all e2e test

    yarn test:e2e

Strapi Environment

  • StrapiEnvironment presets for each e2e test. A strapi instance and a database will start automatically. You do not need to handle the lifecycle of strapi in each test file like this example

  • But be careful, the strapi instance and database are reuse in each test.

  • You could use the strapi and request instance directly in the e2e test file

    strapi.query('products').find();
    strapi.services.product.creates({});

    // instead of request(strapi.server).get('/products').send`
    request.get('/products').send();
  • For more details, see strapi/tests/helpers/strapiEnvironment.ts

Test Api

  • I have created an API instance/utility for the e2e testing. You do not need to care about the HTTP method and the path.

  • The API instance is strongly typed. It depends on strapi/tests/helpers/routes.ts which is a file auto-generated by esbuild/routeMetadata.ts. If you found the content is not up to date. Just run yarn build

  • Examples:

    // basic usage
    api.category.find().send();
    // dynamic path '/categories/:id'
    api.category.findOne({ id: 'mongoid' }).send();
    // add bearer token
    api.profile.get().token(token).send();
    // multipart, file upload
    api.product
    .create()
    .multipart()
    .attach('file', './image.png')
    .field({ data: JSON.stringify({}) });

    The above code same as below

    request.get('/categories').send();
    request.get(`/categories/${mongoid}`).send();
    request.get(`/profile`).set('Authorization', `bearer ${token}`).send();
    request
    .post(`/products`)
    .set('Content-Type', 'multipart/form-data')
    .attach('file', './image.png')
    .field({ data: JSON.stringify({}) });

Custom Jest matcher

I have defined some custom jest matcher in strapi/tests/matchers

import { HTTPStatus } from '@/tests/helpers/httpStatus';

test('...', async () => {
const response = await request.get('/categories').send();
// expect response status to be 200
expect(response).toHaveStatus(HTTPStatus.OK);
// expect response.error not false
expect(response).toHaveError(HTTPStatus.OK);
// expect response.error is false
expect(response).not.toHaveError(HTTPStatus.OK);
});

step to create custom Jest matcher

  1. Refer to the matchers in tests/matchers

  2. Remember to extend and export the matcher function

export function theMatcherFunction(
this: jest.MatcherContext,
received: unknwon,
expected: unknwon
): jest.CustomMatcherResult | Promise<jest.CustomMatcherResult> {}

expect.extend({ theMatcherFunction });
  1. Export the matcher file in tests/matchers/index.js

Define new global variables for test

  1. Define the type of variables in tests/jest-e2e.d.ts
  2. Set the initial values in /jest-setup.js
  3. Update the globals field in .eslintrc

Watch

start development using yarn dev or docker-compose up. Open another terminal and type

yarn app test --watch
yarn app test:e2e --watch

Specify a test

yarn test app/schema/joi/mongoid.test.js
yarn test:e2e app/tests/category.e2e-spec.ts

No console output

Copy below test as the last test

test('delay', async () => {
const delay = (ms: number) => new Promise(_ => setTimeout(_, ms));
await expect(delay(2000).then(() => 1)).resolves.toBe(1);
});

Test cronjobs

try to add below test at the end ...

import { cron } from '@/tests/helpers/cron';

test('...', async () => {
await cron('*/5 * * * *', {
advanceTimersByTime: 5 * 60 * 1000
});
});