React 测试使用 react shallow-renderer 对输入进行更改

React test onChange on input using react shallow-renderer

提问人:Vight 提问时间:4/1/2021 最后编辑:Lin DuVight 更新时间:4/2/2021 访问量:2332

问:

我正在尝试使用 onChange 道具测试 React 的 searchForm 组件。

const SearchForm = () => {
  const [value, setValue] = useState('');

  return (
    <form className={styles.searchForm}>
      <input
        value={value}
        onChange={(e) => setValue(e.target.value)} // test this line
        className={styles.searchForm__input}
      />
      <button type="submit" aria-label="Search" className={styles.searchForm__button} />
    </form>
  );
};

这是我的测试示例:

import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow';
import SearchForm from '../index';

const setUp = () => {
  const renderer = new ShallowRenderer();
  renderer.render(<SearchForm />);
  return renderer.getRenderOutput();
};

describe('render form component', () => {

  it('handle onChange in form input field', () => {
    const result = setUp();
    expect(result).toMatchSnapshot();
  });
});

此测试通过,但 JEST 说这行代码(使用 onChange)已被发现。

我找到了如何启动onChange:

result.props.children[0].props.onChange();

这启动了原始道具,但我在 e.target 上遇到错误 - 无法读取未定义的属性。 我觉得我需要以某种方式模拟 setValue,但我不知道如何。我是 JEST 的新手。 也许这可以通过更好的方式使用 react-test-renderer 来完成。

reactjs jestjs react-hooks react-test-renderer

评论

0赞 superhawk610 4/2/2021
onChange期望将事件作为其第一个参数;您可以创建一个模拟事件,然后像 一样使用它。const mockEvent = { target: { value: 'input value' } }result.props.children[0].props.onChange(mockEvent)
0赞 Vight 4/2/2021
谢谢。但是我找不到如何正确测试它。现在我正在测试它,就像这个测试失败,因为值没有改变。虽然我可以使用技巧并在 .toBe 中将“t”替换为“”。我只是想为自己澄清一下在这种情况下如何使用笑话。const mockEv = { target: { value: 't' } }; result.props.children[0].props.onChange(mockEv); expect(result.props.children[0].props.value).toBe('t');

答:

2赞 Lin Du 4/2/2021 #1

这是解决方案:

index.tsx:

import React, { useState } from 'react';

export const SearchForm = () => {
  const [value, setValue] = useState('');

  return (
    <form>
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <button type="submit" aria-label="Search" />
    </form>
  );
};

index.test.tsx:

import React from 'react';
import TestRenderer, { act } from 'react-test-renderer';
import ShallowRenderer from 'react-test-renderer/shallow';
import { SearchForm } from './';

describe('66907704', () => {
  it('should handle onChange event', () => {
    const testRenderer = TestRenderer.create(<SearchForm />);
    const testInstance = testRenderer.root;
    expect(testInstance.findByType('input').props.value).toEqual('');
    const mEvent = { target: { value: 'teresa teng' } };
    act(() => {
      testInstance.findByType('input').props.onChange(mEvent);
    });
    expect(testInstance.findByType('input').props.value).toEqual('teresa teng');
  });

  it('should handle onChange event when use shallow render', () => {
    const shallowRenderer = ShallowRenderer.createRenderer();
    shallowRenderer.render(<SearchForm />);
    let tree = shallowRenderer.getRenderOutput();
    let input = tree.props.children[0];
    const mEvent = { target: { value: 'teresa teng' } };
    input.props.onChange(mEvent);
    tree = shallowRenderer.getRenderOutput();
    input = tree.props.children[0];
    expect(input.props.value).toEqual('teresa teng');
  });
});

单元测试结果:

 PASS  examples/66907704/index.test.tsx (6.636 s)
  66907704
    ✓ should handle onChange event (10 ms)
    ✓ should handle onChange event when use shallow render (1 ms)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |     100 |      100 |     100 |     100 |                   
 index.tsx |     100 |      100 |     100 |     100 |                   
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        7.443 s

软件包版本:

"jest": "^26.6.3",
"react": "^16.14.0",