首页 > 解决方案 > 开玩笑地模拟和监视导入的异步函数

问题描述

我想弄清楚如何在 Jest 中模拟导入的属性函数

这是我的组件AboutScreen.js

import React from 'react';
import { Constants, WebBrowser } from 'expo';
import { View, Text } from 'react-native';

const AboutScreen = () => { 
return (
  <View>
    <Text testId={"t-and-c"} onPress={() => WebBrowser.openBrowserAsync('tcUrl')}>
Terms & conditions
    </Text>
  </View>
  );
};


export default AboutScreen;

我在 AboutScreen.test.js 中的测试如下所示

import React from 'react';
import { shallow } from 'enzyme';
import config from '../../config';
import AboutScreen from '../AboutScreen';
import { Constants, WebBrowser } from 'expo';
const { termsAndConditionsUrl, privacyPolicyUrl } = config;

jest.mock('expo', () => ({
  Constants: {
    manifest: {
        version: '0.0.1',
        releaseChannel: 'PROD',
    },
  WebBrowser: {
    openBrowserAsync: jest.fn()
    }
  },
 }));

it('click on terms and conditions link', () => {
   const mock = jest.spyOn(WebBrowser, 'openBrowserAsync'); 
   mock.mockImplementation(() => Promise.resolve());
   // above statement return 'Cannot spyOn on a primitive value; undefined given' 
   // WebBrowser.openBrowserAsync = jest.fn(); --> This returns `WebBroser undefined
   const wrapper = shallow(<AboutScreen />);
   wrapper.find({ testId: 't-and-c' }).simulate('click');
   expect(mock).lastCalledWith('abc');
   // expect(WebBrowser.openBrowserAsync).toHaveBeenCalledWith('tcUrl);
});

我能够模拟Constants.manifest.version但无法弄清楚如何模拟“浏览器”对象中的函数。

标签: react-nativemockingjestjs

解决方案


你很近。


您当前正在模拟WebBrowser成为内部的属性Constants,因此需要像这样将其移出:

jest.mock('expo', () => ({
  Constants: {
    manifest: {
      version: '0.0.1',
      releaseChannel: 'PROD',
    }
  },
  WebBrowser: {
    openBrowserAsync: jest.fn()
  }
}));

另一个问题是simulate使用shallow. 从文档的Common Gotchas部分:

尽管名称暗示这模拟了一个实际事件,但.simulate()实际上会根据你给它的事件来定位组件的道具。例如,.simulate('click')将实际获取onClick道具并调用它。

...并且由于您的组件没有onClick属性调用.simulate('click')最终什么都不做。

来自 Airbnb 开发人员的这篇文章建议直接调用 props 并避免simulate.

您可以onPress像这样直接调用道具来调用:

wrapper.find({ testId: 't-and-c' }).props().onPress();

所以所有的工作测试看起来像这样:

import React from 'react';
import { shallow } from 'enzyme';
import config from '../../config';
import AboutScreen from '../AboutScreen';
import { Constants, WebBrowser } from 'expo';
const { termsAndConditionsUrl, privacyPolicyUrl } = config;

jest.mock('expo', () => ({
  Constants: {
    manifest: {
      version: '0.0.1',
      releaseChannel: 'PROD',
    }
  },
  WebBrowser: {
    openBrowserAsync: jest.fn()
  }
}));

it('click on terms and conditions link', () => {
  const mock = jest.spyOn(WebBrowser, 'openBrowserAsync');
  mock.mockImplementation(() => Promise.resolve());

  const wrapper = shallow(<AboutScreen />);

  wrapper.find({ testId: 't-and-c' }).props().onPress();
  expect(mock).toHaveBeenCalledWith('tcUrl'); // Success!
});

推荐阅读