开发者问题收集

如何使用 Jest、Enzyme for React-Native 在单元测试中模拟事件

2017-02-16
22725

我试图弄清楚如何在 React-Native 应用中使用 Jest 测试“onPress”事件,以确保调用正确的函数。

我查阅了文档和 Google,但在 React-Native 中找不到解决方案。

这是我发现的应该适用于带有 enzyme 的 React-Native 的内容:

const mockFunc = jest.fn();
const component = mount(<MyComponent onPress={mockFunc} />);
component.simulate('press');
expect(mockFunc).toHaveBeenCalled();

但这不起作用。似乎 mount 不起作用,我得到了这个输出:

ReferenceError: document is not defined

我尝试使用 shallow ,但当我查看函数的输出时, TouchableOpacity 没有被渲染……而且你已经猜到了,它也不起作用。不知道该怎么办。

有人找到在 React-Native 上测试事件的方法吗?

谢谢

3个回答

Enzyme 不支持 React-Native,因为它的渲染方式不同,并且不使用 DOM。这就是您收到错误 ReferenceError:文档未定义 的原因。您可以查看 此问题 以了解更多信息。React 团队目前正在努力在 react-test-renderer 中公开 .find() 方法来模拟组件上的操作。然后它应该适用于 React/React-native,而无需 DOM 环境。

您可以采取一种黑客手段(这就是我们在公司所做的),即渲染一个自定义组件,该组件扩展 TouchableOpacity 并映射 onClick 以调用 onPress 。类似这样的内容:

const mockPressable = (name) => {
  const RealComponent = require.requireActual(name);

  class Component extends RealComponent {

    render() {
      return React.createElement(
        RealComponent.displayName || RealComponent.name,
        { ...this.props, onClick: this.props.onPress },
        this.props.children
      );
    }

  }

  return Component;
};


jest.mock('TouchableOpacity', () => mockPressable('TouchableOpacity'));

并且在您的测试代码中,您调用 component.simulate('click')

这是一种黑客行为,我不确定这样做的后果是什么,但它对我们的用例有效。

Lucas
2017-02-23

您应该改用 shallow ,然后调用 .dive()

const mockFunc = jest.fn();
const component = shallow(<MyComponent onPress={mockFunc} />);    
component.dive().simulate('press');
expect(mockFunc).toHaveBeenCalled();
msmaromi
2018-02-09

我能够在 React Native 中运行您在问题中描述的测试。这是我的配置:

package.json

"scripts": {
  ...
  "test": "node_modules/jest/bin/jest.js",
}

"devDependencies": {
  ...
  "enzyme": "^3.1.0",
  "enzyme-adapter-react-16": "^1.0.1",
  "enzyme-to-json": "^3.1.2",
  "jest": "^21.2.1",
  "jest-enzyme": "^4.0.0",
  "jest-expo": "~21.0.0",
}

"jest": {
  "preset": "jest-expo",
  "setupFiles": [
    "./test/jestSetup.js"
  ],
  "snapshotSerializers": [
    "./node_modules/enzyme-to-json/serializer"
  ]
}

test/jestSetup.js

import { configure, shallow, render, mount } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

configure( { adapter: new Adapter() } )

// enzyme
global.shallow = shallow
global.render = render
global.mount = mount

示例组件:

import React from 'react'
import { Button } from 'react-native'

const CancelButton = ( props ) =>
  <Button
    { ...props }
    onPress={ () => { props.navigation.goBack() } }
    title="Cancel"
  />

export { CancelButton }

示例测试

import React from 'react'
import { CancelButton } from '../CancelButton'

test( 'onPress', () => {
  const goBackFunc = jest.fn()

  const navigation = {
    goBack: goBackFunc,
  }

  const component = shallow(
    <CancelButton
      navigation={ navigation }
    />
  )

  component.simulate( 'press' )
  expect( goBackFunc ).toHaveBeenCalled()
} )

.babelrc

{
  "presets": ["babel-preset-expo"],
  "env": {
    "development": {
      "plugins": ["transform-react-jsx-source"]
    }
  }
}
Javid Jamae
2017-10-08