Skip to content

[new rule] Enforce using jest.doMock if a jest.mock call cannot be hoisted #1315

@NotWoods

Description

@NotWoods

The conditions around when babel-jest can hoist a function is a bit confusing. If mocks are hoisted, then it's safe to require a module that depends on them. But if they aren't, then the real module will be unintentionally used instead.

If tests consistently use jest.mock for hoistable module mocks, and use jest.doMock for mocks that cannot be hoisted, then its easy to just look at the test and see if its safe to require a module that depends on the mocks at the top level.

Here’s the checks I found from digging through the source code of Jest’s babel plugin.

  • jest.mock() must be called at the top-level, and not inside another function.
  • The first argument to jest.mock() should be a literal value.
  • The second argument, if provided, should be an inline function.
  • That function shouldn’t reference any variables defined outside the function.

Examples of incorrect code for this rule:

const moduleName = './module';
jest.mock(moduleName);

function factory() {
  return jest.fn();
}
jest.mock('./module', factory);

jest.mock('./module', () => {
  // variable defined outside scope
  return jest.fn().mockReturnValue(moduleName);
});

Examples of correct code for this rule:

const moduleName = './module';
jest.doMock(moduleName);

function factory() {
  return jest.fn();
}
jest.doMock('./module', factory);

jest.doMock('./module', () => {
  return jest.fn().mockReturnValue(moduleName);
});

// can be hoisted
jest.mock('random-num');
jest.mock('../module', () => {
  return jest.fn().mockReturnValue('foo');
});

Auto-fixable: Yes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions