【问题标题】:Spying on function checking when testing React component onClick在测试 React 组件 onClick 时监视功能检查
【发布时间】:2021-03-18 20:16:06
【问题描述】:

我有一个父组件和一个子组件。

父组件:

const ParentComponent = () => {

    const click_button = (role) => {
        document.getElementById(role).innerHTML = role;
    }

    return (
        <div>
            <ChildButton id= 'button_child' name='button_1' onClick={() => {
                click_button('role_1')
            }}/>
            <div>
                <p id="role_1"/>
                <p id="role_2"/>
                <p id="role_3"/>
            </div>
        </div>

    )

}

export default ParentComponent;

子组件

import React from 'react';

const ChildButton = (props) => {

    return (
        <React.Fragment>
            <button onClick={props.onClick}>{props.name}</button>
        </React.Fragment>
    )
}

export default ChildButton;

ParentComponent 的测试之一:

    it('buttons should render correctly', () => {
        const wrapper shallow(<ParentComponent/>);
        const instance = wrapper.instance();
        jest.spyOn(instance, 'click_button');
        expect(instance.click_button).toHaveBeenCalledTimes(0);
        wrapper.find('#button_child').simulate('click');
        expect(instance.click_button).toHaveBeenCalledTimes(1);
    });

我的应用程序使用 jest 和酶进行测试。示例中的点击功能需要在 ParentComponent 中进行测试。但是,当我尝试访问该按钮时,测试失败,这是因为该按钮位于 childButton 组件中。

所以基本上我的任务是如何测试ParentComponent 中的click_button 函数?

上面的例子是空的,酶文档说会是这样。现在我看到人们解决这个问题的唯一方法是“观察”控制台日志,这对我来说似乎有点 hacky?

我试图坚持使用 Enzyme 和 Jest,因为这是我编写单元测试的内容,我希望我的集成测试也能效仿。

感谢您的帮助。

【问题讨论】:

  • 如果你是“集成”一起测试父子,为什么要shallow渲染呢?而且您不应该监视任何东西 - 测试的期望应该是更新相关元素内容。
  • “我想知道 click_button 函数已被调用” - 不,你没有。这在单独测试 Child 时可能是有意义的,您检查作为 prop 传递的函数是否被调用,但是当一起测试 Parent 和 Child 时,您希望检查 Parent 实现正确的行为click_button 是一个实现细节,它甚至在函数之外都无法访问。
  • 好吧,我说错了。我应该如何准确测试 click_button ?谢谢
  • 再次测试行为。当它被点击时,DOM 应该被更新(虽然这不是 React 的做法),所以测试一下。

标签: javascript reactjs testing jestjs enzyme


【解决方案1】:

测试组件的行为而不是实现细节。使用enzymemount()函数一起测试父子组件。 React 函数式组件没有实例,但类组件有实例。

例如

parent.jsx:

import ChildButton from './child';

const ParentComponent = () => {
  const click_button = (role) => {
    document.getElementById(role).innerHTML = role;
  };

  return (
    <div>
      <ChildButton
        id="button_child"
        name="button_1"
        onClick={() => {
          click_button('role_1');
        }}
      />
      <div>
        <p id="role_1" />
        <p id="role_2" />
        <p id="role_3" />
      </div>
    </div>
  );
};

export default ParentComponent;

child.jsx:

import React from 'react';

const ChildButton = (props) => {
  return (
    <React.Fragment>
      <button onClick={props.onClick}>{props.name}</button>
    </React.Fragment>
  );
};

export default ChildButton;

parent.test.jsx:

import React from 'react';
import ParentComponent from './parent';
import { mount } from 'enzyme';

describe('66698493', () => {
  beforeAll(() => {
    const div = document.createElement('div');
    div.setAttribute('id', 'container');
    document.body.appendChild(div);
  });
  it('should change the inner HTML', () => {
    const wrapper = mount(<ParentComponent />, { attachTo: document.getElementById('container') });
    expect(document.getElementById('role_1').innerHTML).toEqual('');
    wrapper.find('button').simulate('click');
    expect(document.getElementById('role_1').innerHTML).toEqual('role_1');
  });
});

测试结果:

 PASS  examples/66698493/parent.test.jsx
  66698493
    ✓ should change the inner HTML (46 ms)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |      100 |     100 |     100 |                   
 child.jsx  |     100 |      100 |     100 |     100 |                   
 parent.jsx |     100 |      100 |     100 |     100 |                   
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        6.067 s

jest.config.js:

module.exports = {
  preset: 'ts-jest/presets/js-with-ts',
  testEnvironment: 'enzyme',
  setupFilesAfterEnv: [
    'jest-enzyme',
  ],
  setupFiles: ['./jest.setup.js'],
  testEnvironmentOptions: {
    enzymeAdapter: 'react16',
  },
};

【讨论】:

  • 感谢非常全面的回答!一切都说得通。度过美好的一天。
猜你喜欢
  • 2019-08-06
  • 2021-08-18
  • 2018-08-18
  • 2021-08-30
  • 2019-12-10
  • 2021-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多