【问题标题】:Testing a function called on an object with Jest in React Native在 React Native 中使用 Jest 测试在对象上调用的函数
【发布时间】:2018-05-27 22:12:06
【问题描述】:

编辑

当前示例,

  it('CALLED THE canOpenURL FUNCTION', () => {
    const wrapper = mount(<ResourceCardComponent {...mockProps} />);
    const canOpenURLSpy = jest.spyOn(Linking, 'canOpenURL');
    wrapper.find('TouchableOpacity').simulate('click');
    expect(canOpenURLSpy).toHaveBeenCalled();
    canOpenURLSpy.mockReset();
    canOpenURLSpy.mockRestore();
  });

错误

expect(jest.fn()).toHaveBeenCalled() 期望的模拟函数 被调用了。

问题

我正在使用JestEnzyme 来测试使用React Native 制作的类。这个类里面有一个函数,当它被触发时,它使用链接库来调用canOpenUrlopenUrl。我可以模拟已安装组件上的单击事件,但我无法知道我可以实际测试多少。

我的目标是检查Linking.canOpenUrl 是否曾经触发过。

示例

组件内部的函数是这样的,

  onPressLink() {
    console.log('HEY THIS FUNCTION FIRED WOOT WOOT');
    Linking.canOpenURL(this.props.url).then((supported) => {
      if (supported) {
        Linking.openURL(this.props.url);
      }
    });
  }

我可以像这样模拟这种发射,

describe('onPressLink has been called!', () => {
  it('It clicks the mock function onPressLink!', (done) => {
    const wrapper = mount(<MyComponent {...mockProps} />);
    const onPressLink = jest.fn();
    const a = new onPressLink();
    wrapper.find('TouchableOpacity').first().simulate('click');
    expect(onPressLink).toHaveBeenCalled();
    done();
  });
});

现在确实有效,但我的目标是使用这样的东西,

expect(Linking.canOpenUrl).toHaveBeenCalled();

但我不断收到此错误,

TypeError:无法读取未定义的属性“_isMockFunction”

当前代码试图检查这个函数是否被触发过。在使用模拟方法单击的父函数内部,

  it('calls canOpenURL', () => {
    const wrapper = mount(<MyComponent {...mockProps} />);
    const canOpenURL = jest.spyOn(wrapper.instance, 'onPressLink');
    wrapper.find('TouchableOpacity').simulate('click');
    expect('Linking.canOpenUrl').toHaveBeenCalled();
  });

问题

检查Linking.canOpenURL 在其父函数执行时是否被触发的正确方法是什么?

【问题讨论】:

    标签: react-native jestjs enzyme


    【解决方案1】:

    (自 Jest 19.0.0+ 起)

    您可以使用jest.spyOn() 监视链接模块方法。

    (1) 告诉 jest 监视模块方法:

    const spy = jest.spyOn(Linking, 'canOpenURL');
    

    (2) 做完所有需要测试后,检查spy:

    expect(spy).toHaveBeenCalled();
    

    (3) 清理并停止对模块方法的窥探

    spy.mockReset();
    spy.mockRestore();
    

    如果您不希望测试使用方法的实际实现,您可以像这样伪造它们:

    jest.spyOn(Linking, 'canOpenURL').mockImplementation(() => Promise.resolve());
    

    传递给 mockImplementation 的函数将是您希望该方法在调用时执行的任何操作。

    参考https://facebook.github.io/jest/docs/en/jest-object.html#jestspyonobject-methodname


    使用异步模块方法的实际实现时,承诺可能在您测试时尚未解决。在对它进行任何断言之前,您需要确保在您的方法实现中解决了任何 Promise。

    解决这个问题的一种方法是使用 async/await,如下所示:

    it('...', async () => {
      // Wait for promise to resolve before moving on
      await wrapper.instance().onPressLink();
    
      // make your assertions
      expect(...);
    });
    

    另一种选择是使用expect().resolvesavailable since Jest 20.0.0,您可以在其中等待expect() 的参数中的某个promise 以某个值解析,然后再对该值进行断言。

    expect(somePromiseThatEventuallyResolvesWithValue).resolves.toBe(Value);
    

    【讨论】:

    • 请在顶部查看我的编辑。谢谢你的帮助。但这似乎不起作用。当使用这个确切的方法时,我们得到了这个,expect(jest.fn()).toHaveBeenCalled() - 预期的模拟函数已经被调用。
    • @wuno 您是否尝试过使用 mockImplementation?在我看来,这是一个典型的异步问题。您在承诺解决之前进行测试。你为什么不尝试异步/等待呢? it('should...', async () =&gt; { await wrapper.instance().onPressLink(); /* then test afterward */ })
    • 我实际上已经解决了它。您介意将此添加到下一个人的答案中吗?由于它返回一个承诺,它看起来像这样,预期值是(使用 ===):true 接收:{“_40”:0,“_55”:true,“_65”:1,“_72”:null}所以我添加了 resolve 并且它起作用了,expect(linkOpen).resolves.toBe(true);
    【解决方案2】:

    我以最简单的方式完成了:

    间谍步骤:

    1. 使用 jest 为原始函数制作间谍对象
    2. 调用带有/不带参数的原始函数
    3. 断言应该使用有效参数调用的函数
    4. 重置模拟
    5. 恢复模拟

    这里是示例

    DefaultBrowser.ts 这是实际的类。

    import { Linking } from 'react-native';
    
    export const openDefaultBrowser = async url => {
      if (await Linking.canOpenURL(url)) {
        Linking.openURL(url);
      }
    };
    

    DefaultBrowser.test.ts是测试用例类。

    import { openDefaultBrowser } from '../DefaultBrowser';
    import { Linking } from 'react-native';
    
    describe('openDefaultBrowser with validate and open url', () => {
      it('validate url', async () => {
        const spy = jest.spyOn(Linking, 'canOpenURL');
        openDefaultBrowser('https://www.google.com');
        expect(spy).toBeCalledWith('https://www.google.com');
        spy.mockReset();
        spy.mockRestore();
      });
    
      it('open url', async () => {
        const spy = jest.spyOn(Linking, 'openURL');
        openDefaultBrowser('https://www.google.com');
        expect(spy).toBeCalledWith('https://www.google.com');
        spy.mockReset();
        spy.mockRestore();
      });
    });
    

    希望对你有所帮助。

    【讨论】:

    • 我们通常会先检查提供的 URL 是否支持。如果它是受支持的 URL,那么我们继续打开它。测试“openURL”调用的第二个测试不会通过,因为“canOpenURL”返回一个promise。如果我错了,请赐教。
    猜你喜欢
    • 2017-07-09
    • 1970-01-01
    • 2023-01-04
    • 2022-01-19
    • 2021-02-13
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多