如何测试功能组件中定义的方法,该方法与DOM元素交互且没有参数

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (13)

我一直有麻烦我的一个按钮获得100%的测试覆盖率(A反应的官能组件。)点击基本上当它时,它执行一些代码,然后还是来自这个调用另一个方法onClickresetButtons。此方法将在应用程序中找到所有类似的按钮并删除一个类。这是一种先发制人的行为,因此一次只能有一个按钮active

到目前为止,我已经测试了点击使用.simulate,传递了一个模拟domElement。然后测试该domElement.classList.add方法是否被调用'active'

显然这是一个以DOM为中心的操作,我发现很难测试resetButtons组件中的方法。特别是考虑到它没有任何方法。

我已经尝试resetButtons在组件外部定义方法,然后将其导出,以便jest测试可以导入它。但是我一直无法测试该方法,因为它似乎希望它是间谍或模拟,而不是方法本身。(Matcher error: received value must be a mock or spy function

这是功能组件的反应:

import React from 'react';
import PropTypes from 'prop-types';
import classes from './MainButton.module.scss';

const MainButton = (props) => {
  const resetButtons = () => {
    const elements = document.getElementsByClassName('mainButton');
    for (let i = 0; i < elements.length; i += 1) {
      elements[i].classList.remove('active');
    }
  };

  const handleClick = (event) => {
    if (!event.target.classList.contains('active')) {
      resetButtons();
      event.target.classList.add('active');
      props.setVisualState(props.className.split('-')[0]);
    }
  };

  return (
    <button
      onClick={handleClick}
      type="button"
      className={`${classes.mainButton} ${props.className}`}
    >
      {props.children}
    </button>
  );
};

MainButton.propTypes = {
  children: PropTypes.node,
  className: PropTypes.string,
  setVisualState: PropTypes.func.isRequired,
};

MainButton.defaultProps = {
  children: 'Button',
  className: '',
};

export default MainButton;

这是测试

import React from 'react';
import { shallow } from 'enzyme';
import MainButton from './MainButton';

describe('MainButton', () => {
  const domElement = { classList: { contains: jest.fn(), remove: jest.fn(), add: jest.fn() } };
  const setVisualStateMock = jest.fn();
  const mainButton = shallow(<MainButton setVisualState={setVisualStateMock} />);

  it(' is rendered properly', () => {
    expect(mainButton).toMatchSnapshot();
  });

  describe('when clicked', () => {
    beforeEach(() => {
      mainButton.find('button').simulate('click', { target: domElement });
    });

    it('it runs `classlist.add` to assign `active` class', () => {
      expect(domElement.classList.add).toHaveBeenCalledWith('active');
    });

    it('it runs set visual state to update `Allergen` container `state`', () => {
      expect(setVisualStateMock).toHaveBeenCalled();
    });
  });
});

目前,覆盖率报告报告的覆盖率为92%,但是分支处于50,并且导致问题的elements[i].classList.remove('active');线路在第9行(线路。

我知道90%我应该继续前进,但这是我想要弄清楚的。感觉像是把头转过来会让我受到更好的考验。

希望你们能帮忙!

提问于
用户回答回答于

您应该能够挂载多个MainButtons,单击一个并期望其他人domElement.classList.remove调用它们。

但是,用户konqi的正确之处在于React提供了更好的操作元素/组件的方法。

你可以替换这个测试:

expect(domElement.classList.add).toHaveBeenCalledWith('active');

使用测试来检查按钮是否具有(或没有)activeclassName(而不是检查该函数是否使用正确的参数调用)。有了这个测试,如果你愿意,你可以像konqi建议的那样重构它。

用户回答回答于

自己在DOM中徘徊是一种反模式。那是React的工作。target.classList.add你应该拥有一个状态属性来保存你输入当前处于活动状态的状态,而不是与你一起操作dom 。然后,虽然渲染你可以说className={isActiveInput ? "active": null}

因为状态不是特定于您的MainButton组件,所以您可以提升状态。如果你在父母的某个地方有状态,你不必粗略地按类名搜索DOM元素并自己操纵dom。

简单地说,React的规则是:你定义事物应该是什么样子,React注意你的定义在dom中成为现实。如果你自己操纵DOM - 你做错了。

完成所有这些操作后,您将毫无问题地进行测试,因为所有您需要做的就是提供正确的状态和道具,这很容易,并检查您的回调是否在onClick上触发。

编辑:高级版本将使用上下文,但我会先解决状态提升。

所属标签

可能回答问题的人

  • 天使的炫翼

    15 粉丝531 提问35 回答
  • 旺仔小小鹿

    社区 · 运营 (已认证)

    48 粉丝0 提问27 回答
  • 富有想象力的人

    2 粉丝0 提问26 回答
  • 发条丶魔灵1

    6 粉丝525 提问25 回答

扫码关注云+社区

领取腾讯云代金券