手动模拟

    Manual mocks are defined by writing a module in a subdirectory immediately adjacent to the module. For example, to mock a module called user in the models directory, create a file called user.js and put it in the models/__mocks__ directory. Note that the __mocks__ folder is case-sensitive, so naming the directory __MOCKS__ will break on some systems. For example, to mock a module called user in the models directory, create a file called user.js and put it in the models/__mocks__ directory. Note that the __mocks__ folder is case-sensitive, so naming the directory __MOCKS__ will break on some systems.

    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 (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'). There’s no need to explicitly call jest.mock('module_name').

    Scoped modules (also known as ) can be mocked by creating a file in a directory structure that matches the name of the scoped module. 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.

    When a manual mock exists for a given module, Jest’s module system will use that module when explicitly calling jest.mock('moduleName'). However, when automock is set to true, the manual mock implementation will be used instead of the automatically created mock, even if jest.mock('moduleName') is not called. To opt out of this behavior you will need to explicitly call jest.unmock('moduleName') in tests that should use the actual module implementation. However, when automock is set to , the manual mock implementation will be used instead of the automatically created mock, even if jest.mock('moduleName') is not called. To opt out of this behavior you will need to explicitly call jest.unmock('moduleName') in tests that should use the actual module implementation.

    Here’s a contrived example where we have a module that provides a summary of all the files in a given directory. In this case, we use the core (built in) fs module. In this case, we use the core (built in) fs module.

    FileSummarizer.js

    1. 'use strict';
    2. const fs = require('fs');
    3. function summarizeFilesInDirectorySync(directory) {
    4. return fs.readdirSync(directory).map(fileName => ({
    5. directory,
    6. fileName,
    7. }));
    8. }
    9. exports.summarizeFilesInDirectorySync = summarizeFilesInDirectorySync;

    Since we’d like our tests to avoid actually hitting the disk (that’s pretty slow and fragile), we create a manual mock for the fs module by extending an automatic mock. Our manual mock will implement custom versions of the fs APIs that we can build on for our tests: Our manual mock will implement custom versions of the fs APIs that we can build on for our tests:

    __mocks__/fs.js

    Now we write our test. Now we write our test. Note that we need to explicitly tell that we want to mock the fs module because it’s a core Node module:

    __tests__/FileSummarizer-test.js

    1. 'use strict';
    2. jest.mock('fs');
    3. describe('listFilesInDirectorySync', () => {
    4. const MOCK_FILE_INFO = {
    5. '/path/to/file1.js': 'console.log("file1 contents");',
    6. '/path/to/file2.txt': 'file2 contents',
    7. beforeEach(() => {
    8. // Set up some mocked out file info before each test
    9. require('fs').__setMockFiles(MOCK_FILE_INFO);
    10. });
    11. test('includes all files in the directory in the summary', () => {
    12. const FileSummarizer = require('../FileSummarizer');
    13. const fileSummary =
    14. FileSummarizer.summarizeFilesInDirectorySync('/path/to');
    15. expect(fileSummary.length).toBe(2);
    16. });
    17. });

    To ensure that a manual mock and its real implementation stay in sync, it might be useful to require the real module using in your manual mock and amending it with mock functions before exporting it.

    The code for this example is available at examples/manual-mocks.

    If you’re using ES module imports then you’ll normally be inclined to put your import statements at the top of the test file. But often you need to instruct Jest to use a mock before modules use it. For this reason, Jest will automatically hoist jest.mock calls to the top of the module (before any imports). To learn more about this and see it in action, see . But often you need to instruct Jest to use a mock before modules use it. For this reason, Jest will automatically hoist jest.mock calls to the top of the module (before any imports). To learn more about this and see it in action, see this repo.

    If some code uses a method which JSDOM (the DOM implementation used by Jest) hasn’t implemented yet, testing it is not easily possible. This is e.g. the case with window.matchMedia(). If some code uses a method which JSDOM (the DOM implementation used by Jest) hasn’t implemented yet, testing it is not easily possible. This is e.g. the case with window.matchMedia(). Jest returns TypeError: window.matchMedia is not a function and doesn’t properly execute the test.

    In this case, mocking matchMedia in the test file should solve the issue:

    This works if window.matchMedia() is used in a function (or method) which is invoked in the test. This works if window.matchMedia() is used in a function (or method) which is invoked in the test. If window.matchMedia() is executed directly in the tested file, Jest reports the same error. In this case, the solution is to move the manual mock into a separate file and include this one in the test before the tested file: In this case, the solution is to move the manual mock into a separate file and include this one in the test before the tested file:

    1. import './matchMedia.mock'; // Must be imported before the tested file
    2. import {myMethod} from './file-to-test';
    3. describe('myMethod()', () => {
    4. // Test the method here...
    5. });