使用Jest在React Native中模拟Child组件

3

我有以下的父级屏幕/组件 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()没有模拟我的组件?因为它仍然在尝试渲染并抱怨缺少存储。

我如何正确地使用Jest和React-Native模拟组件(特别是子组件)?

1个回答

2
您的问题与React或Redux无关,而是与JavaScript导入机制有关:
因为PasswordForm在Employees.tsx文件顶部被导入,然后Employees(很可能)在您的测试用例顶部被导入,这使得加载发生的顺序为:PasswordForm> Employees> 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('_ _ mocks _ _'文件夹名称很重要)。请注意,保留html标签。
./__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  

哦,好的。那么在 mocks 文件夹中创建一个文件(它在根目录中吗?)与相同的名称,然后只需从中导出 jest.fn() 即可? - Aleski
我把 mocks 放在我的基础目录中,但它一直告诉我找不到文件(无法找到模块)。 - ericjam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接