【问题标题】:Jest mock async function from default import来自默认导入的 Jest 模拟异步函数
【发布时间】:2019-02-25 18:18:50
【问题描述】:

我正在尝试模拟一个作为默认导出导出的异步函数,但我得到的只是 TypeError: Cannot read property 'then' of undefined

我要模拟的是 config.js

const configureEnvironment = async (nativeConfig) => {
    return { await whatever() }
}

我正在测试的文件是 Scene.js

import configureEnvironment from './config';

class Scene extends React.Component {
    constructor(props) {
        nativeConfig = {};
        configureEnfironment(nativeConfig).then((config) => {
            // Do stuff
        }
    }
}

而我的测试文件是Scene.test.js

let getScene = null;
const configureEnvironmentMock = jest.fn();

describe('Scene', () => {
    jest.mock('./config', () => configureEnvironmentMock);

    const Scene = require('./Scene').default;

    getScene = (previousState) => {
        return shallow(
            <Scene prevState={previousState}>
                <Fragment />
            </Scene>,
        );
    };

    it('calls configureEnvironment with the nativeConfig', async () => {
        expect.assertions(1);
        const nativeConfig = {};

        getScene(nativeConfig);

        expect(configureEnvironmentMock).toHaveBeenCalledWith(nativeConfig);
    });
});

但是,运行测试的结果是:

TypeError: Cannot read property 'then' of undefined

我知道问题出在我模拟 configureEnvironment 的过程中,但我无法让它工作。

我还尝试模拟如下函数:

jest.mock('./config', () => {
    return {
        default: configureEnvironmentMock,
    };
});

但结果是:

TypeError: (0 , _config2.default) is not a function

【问题讨论】:

    标签: javascript reactjs unit-testing react-native jestjs


    【解决方案1】:

    模拟模块默认导出的一种简洁明了的方法是将jest.spyOnmockImplementation 等函数结合使用。


    这是一个基于上面代码 sn-ps 的工作示例:

    config.js

    const whatever = async () => 'result';
    
    const configureEnvironment = async (nativeConfig) => await whatever();
    
    export default configureEnvironment;
    

    场景.js

    import * as React from 'react';
    import configureEnvironment from './config';
    
    export class Scene extends React.Component {
      constructor(props) {
        super(props);
        configureEnvironment(props.prevState).then((config) => {
          // Do stuff
        });
      }
      render() {
        return null;
      }
    }
    

    Scene.test.js

    import React, { Fragment } from 'react';
    import { shallow } from 'enzyme';
    
    import { Scene } from './Scene';
    import * as config from './config';
    
    describe('Scene', () => {
    
      const mock = jest.spyOn(config, 'default'); // spy on the default export of config
      mock.mockImplementation(() => Promise.resolve('config')); // replace the implementation
    
      const getScene = (previousState) => {
        return shallow(
          <Scene prevState={previousState}>
            <Fragment />
          </Scene>,
        );
      };
    
      it('calls configureEnvironment with the nativeConfig', async () => {
        expect.assertions(1);
        const nativeConfig = {};
    
        getScene(nativeConfig);
    
        expect(mock).lastCalledWith(nativeConfig);  // SUCCESS
      });
    });
    

    【讨论】:

    • 完美运行。对我来说关键是能够以import * as config from './config'; 导入,然后可以监视默认导出。
    • 我得到'无法监视默认属性,因为它不是函数;而是给定的对象'。我想这只有在导出是一个函数时才有效
    • @Marc 是的,这种方法适用于默认导出为函数时
    • 如何将其用于命名导出?
    【解决方案2】:

    你可以用玩笑来嘲笑任何东西,像这样 jest.mock('@material-ui/core/withWidth', () => ({ __esModule: true, isWidthUp: jest.fn((a, b) => true), default: jest.fn(fn => fn => fn) }))

    【讨论】:

    • 这个测试后你如何恢复它?
    猜你喜欢
    • 2018-03-20
    • 2019-04-16
    • 2021-08-11
    • 2021-07-17
    • 2019-05-05
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    • 2019-03-13
    相关资源
    最近更新 更多