Jest: Manual mock documentation is incorrect and lacking

Created on 11 Sep 2020  路  5Comments  路  Source: facebook/jest

馃悰 Bug Report

View the documentation for Mocking Node modules.

The incorrect statement:

... the mock should be placed in the __mocks__ directory adjacent to node_modules ...

Latter on there is some confusing language about "scoped modules". There is no explanation of what a "scoped module" is. Searching for the term "scoped module" on MDN doesn't reveal it's meaning. Observe that "scope" according to MDN, a trusted authority on JavaScript documentation, discusses variable scope and closures, not directory structure. Searching for documentation on modules doesn't clarify this term.

If you follow this advice for many node modules it will fail. This includes async-storage.

Expected behavior

I infer from some React-Native-Community documentation and this use of the term "scoped module" what is meant. It seems that "scoped module" means a node module that is nested, in terms of directories (directory scope).

EDIT
I'm asking for the documentation to link to the term, "scoped module", which NPM more readily refers to as a "scoped package". Using this terminology from NPM seems more correct as it is the only one available documenting it AFAIK but in the event that the link becomes dead explaining both terms as equivalent would be helpful. I couldn't find any relevant documentation by searching for "scoped module javascript" but I could find documentation using "scoped package javascript". I'm also asking to clarify the section, Mocking Node modules, to read:

If the module you are mocking is a Node module[, but not a scoped package/module,] (e.g.: lodash), the mock should be placed in the __mocks__ directory adjacent to node_modules (unless you configured roots to point to a folder other than the project root) and will be automatically mocked. There's no need to explicitly call jest.mock('module_name').

Scoped [packages, which are always organized in subdirectories of node_modules] can be mocked [similarly] by creating a file in a directory [under a __mocks__ directory that is adjacent to the node_moduels directory but with subdirectories] that match [those] of the scoped [package]. For example, to mock a scoped [package] called @scope/project-name, create a file at __mocks__/@scope/project-name.js[, which should match the scoped package having a directory structure of node_modules/@scope/project-name].

Perhaps including an example of a scoped package, which Jest refers to as a "scoped module", in the example section would be more appropriate than showing an unrelated example. Showing and highlighting the actual and mocked scoped package would be helpful regardless of whether or not the other examples like user.js were to remain.
END

A developer of JavaScript with basic knowledge of the language and after having successfully made and run tests without mocking should be able to read just this page of documentation to know how to correctly mock a node module that is nested/"scoped".

Documentation Help Wanted

All 5 comments

A "scoped module" refers to a scoped npm package, explained here: https://docs.npmjs.com/cli/v6/using-npm/scope

For example, this package is "called" (meaning named) "@babel/cli" https://www.npmjs.com/package/@babel/cli

A "scoped module" refers to a scoped npm package, explained here: https://docs.npmjs.com/cli/v6/using-npm/scope

For example, this package is "called" (meaning named) "@babel/cli" https://www.npmjs.com/package/@babel/cli

That documentation helps clarify that indeed, a scoped module is scoped in terms of directory structure, but also in terms of the repository source, NPM, Git, etc. So maybe you can help clarify the actual directory structure needed.

Given the following NPM package:

import AsyncStorage from '@react-native-community/async-storage';

is the following mock correctly placed:

<PROJECT-ROOT>/node_modules/react-native-community/async-storage/__mocks__/AsyncStorage.js

I'm assuming that the file itself needn't be different in content simply because it's a scoped NPM module. I'm also assuming that the call to mock, jest.mock('@react-native-community/async-storage'), will work the same unless it it a core NPM module.

If the module you are mocking is a Node module (e.g.: lodash), the mock should be placed in the __mocks__ directory adjacent to node_modules

This means that you'd have to place it in <PROJECT-ROOT>/__mocks__ not <PROJECT-ROOT>/node_modules/__mocks__.
Adjacent = __next to__ node_modules, not __in__ node_modules

Scoped modules can be mocked by creating a file in a directory structure that matches the name of the scoped module. For example, to mock a scoped module called @scope/project-name, create a file at __mocks__/@scope/project-name.js, creating the @scope/ directory accordingly.

The mock in your example would therefore need to be placed in <PROJECT-ROOT>/__mocks__/@react-native-community/async-storage.js.

Btw.: This module has a Jest-Integration already: https://react-native-async-storage.github.io/async-storage/docs/advanced/jest

Thanks @schwarmco . I edited the issue to clarify this. If I'm the only one who had this problem I suspect I'm the only one that looked at Jest's documentation first to try to understand how to mock a node package/module for Jest. The documentation feels too helpful by half.

PRs clarifying the docs are always welcome 馃檪

Was this page helpful?
0 / 5 - 0 ratings