DEV Community

Cover image for Jest Best Practice 1: Use eslint-plugin-jest
alex
alex

Posted on

Jest Best Practice 1: Use eslint-plugin-jest

Wasteland in the project

We used to focus on the quality of business code only and ignore the unit test code quality. That makes the unit tests code becomes the wild west of our project. So I gonna share some practice I've used in my project.

Start with the code style

First, let's begin with the style of your unit test code. We used to use eslint on our business code. But have you try to use eslint on the jest code? Try eslint-plugin-jest. Here is the introduction of this package: https://www.npmjs.com/package/eslint-plugin-jest

Here are the rule set I've used in my project

'jest/expect-expect': 'error',
'jest/lowercase-name': [
    'error',
    {
        ignore: ['describe'],
    },
],
'jest/no-disabled-tests': 'error'
'jest/no-done-callback': 'error',
'jest/no-duplicate-hooks': 'error',
'jest/no-conditional-expect': 'error',
'jest/no-export': 'error',
'jest/no-focused-tests': 'error',
'jest/no-identical-title': 'error',
'jest/no-interpolation-in-snapshots': 'error',
'jest/no-jasmine-globals': 'error',
'jest/no-jest-import': 'error',
'jest/no-large-snapshots': 'error',
'jest/no-mocks-import': 'error',
'jest/no-standalone-expect': 'error',
'jest/no-test-prefixes': 'error',
'jest/valid-describe': 'error',
'jest/valid-expect-in-promise': 'error',
'jest/prefer-to-have-length': 'warn',
'jest/valid-expect': 'error',
Enter fullscreen mode Exit fullscreen mode

Most of them are easy to understand. But I want to introduce some of them.

jest/no-done-callback

We might need to change our habits. Don't use done anymore. Because if the code is not able to reach done it will easily get an error. Also using callback can be very prone, as it requires careful understanding of how assertions work in tests, or otherwise tests won't behave as expected.

There are 2 scenarios we need to change our way to write the test

for async operation

For async operation. Turn to use async...await instead of done. Or you can return the Promise like

return doSomething().then(data => {...})
Enter fullscreen mode Exit fullscreen mode

for setTimeout

For setTimeout. Use jest.useFakeTimers() at the beginning of the test file. Then use jest.runAllTimers() to fast-forward until all timers have been executed

For more information about timer mocker, please refer to https://jestjs.io/docs/timer-mocks.

jest/no-conditional-expect

Use the expect in conditional call could lead to the expect silently being skipped. Put the expect in catch is also easy to be skipped.

The following patterns are warnings:

it ('foo', () => {
    const result = doSomething();
    if (result === 1) {
        expect(1).toBe(1)
    }
})

it ('bar', () => {
    try {
        await foo();
    } catch (err) {
        expect(err).toMatchObject({ code: 'MODULE_NOT_FOUND' });
    }
})
Enter fullscreen mode Exit fullscreen mode

It will be better to write these tests in this way

it ('foo', () => {
    const result = doSomething();
    expect(result).toBe(1);
    expect(1).toBe(1);
})

it ('throws an error', () => {
    await expect(foo).rejects.toThrow(Error);
})

Enter fullscreen mode Exit fullscreen mode

jest/no-identical-title

There is an important rule no-identical-title. It's for preventing us to name 2 test cases with the same name.

The following patterns are considered warnings:

it('should do bar', () => {});
it('should do bar', () => {}); // Has the same title as the previous test
Enter fullscreen mode Exit fullscreen mode

It's simple but very useful. I have the experience that I tried to fix the failed unit test. But it was still failed after 30mins troubleshooting. Then I found that I'm not fixing the one that failed. It's especially tricky when there are 2 failed unit tests with the same name.

Top comments (1)

Collapse
 
srshifu profile image
Ildar Sharafeev

Jest best practice 2: use findRelatedTests command in your pre-commit hook. See ore about how it works in my post: dev.to/srshifu/under-the-hood-how-...