使用Jest

时间:2018-05-31 09:54:40

标签: reactjs unit-testing react-native jest

我有以下父屏幕/组件Employees.tsx

import PasswordForm from '../../components/Forms/PasswordForm'

...
<View style={ stylesheet.modalWrapper }>
    <PasswordForm
        errorMessage={ auth.error }
        isWorking={ auth.isWorking }
        onCancel={ toggleModal }
        onSubmit={ customSubmitHandler }
    />
</View>

<PasswordForm />是一个子组件,它是使用reduxFormconnect的装饰形式,以标准方式导入父级。

PasswordForm.tsx

const PasswordForm = reduxForm({
    form: 'password-form'
})(PasswordFormStatic)

在我的测试中,我对这个子组件<PasswordForm>的功能不感兴趣,所以我想模拟该组件,并确保模拟组件仍然存在于父组件的快照测试中(Employees.tsx)。

jest.mock()我以为会处理这件事。这是Employees.spec.tsx

describe('Employees Scene', () => {
    let wrapper
    const requestAuthToken = jest.fn()

    jest.mock('../../components/Forms/PasswordForm', () => {
        const mockedPasswordForm = () => null
        return mockedPasswordForm
    })

但是,我仍然会收到Invariant Violation: Could not find "store" in either the context or props...的错误,这实际上是对孩子的抱怨。

所以看来jest.mock()这里没有嘲笑我的组件?因为它仍然试图渲染和抱怨缺乏商店。

如何使用React-Native在Jest中正确模拟组件(特别是子项)?

1 个答案:

答案 0 :(得分:2)

你的问题与react或reduc无关,而是与javascript import mecanism相关:

因为PasswordForm是在Employees.tsx文件的顶部导入的,然后(可能)导入了在测试用例顶部的Employees,这使得加载按以下顺序进行:PasswordForm&gt;员工&gt; Employees.spec(因为导入发生在任何其他语句之前)

您在测试用例中创建的模拟在Employees类中是未知的。

Jest提供了一种处理这种情况的方法,我会用一些简单的代码来完成这个问题

首先,让我们重现问题

一个简单的函数返回1

./src/A.js

const fn = () => 1
export default fn

一个简单的函数,使用之前定义的A

./src/B.js

import A from 'A'
const B = () => A() + 1
export default B

最后测试B函数,尝试模拟A,就像你的情况一样

./test/B.test.js

import B from 'B'
test('Try to mock A on the fly', () => {
    jest.mock('../src/A', () => 0)
    expect(B(1)).toBe(1)
})

这导致

FAIL  test\B.test.js
  × Try to mock A on the fly (10ms)

  ● Try to mock A on the fly

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      1
    Received:
      2

      2 | test('Try to mock A on the fly', () => {
      3 |     jest.mock('../src/A', () => 0)
    > 4 |     expect(B(1)).toBe(1)
      5 | })

      at Object.<anonymous> (test/B.test.js:4:18)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.598s

现在,如果您使用jest模拟模块,如此处所述https://facebook.github.io/jest/docs/en/manual-mocks.html

创建新文件

A的模拟(&#39; _ _ mocks _ _&#39;文件夹名称很重要)

./__mocks__/A.mock.js

const A = jest.fn(() => 0)
export default A

并将测试文件修改为

import A from 'A'
import B from 'B'
jest.mock('A')
test('use jest mock for A', () => {
    expect(B(1)).toBe(1)
})

你最终会得到你想要的东西

PASS  test\B.test.js
  √ use jest mock for A (4ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.57s