Enzyme/Mocha:如何通过从 child 组件触发 onChange 事件来测试 React 组件功能

Enzyme/Mocha: How to test a react component function by firing an onChange event from a child component

我正在使用 enzyme/mocha 来测试我的 React 组件。

我有一个正在测试的 parent 组件。

let wrapper = mount(<Parent />);

并且这个 parent 在它的渲染函数中有一个 child 组件

render: function() {
    <Child onChange={this.foo} />
},
foo: function() {
    console.log("I was called");
}

我希望触发 child 的 onChange 函数,以便我可以测试 parent 的 foo 函数。

到目前为止,我还没有找到执行此操作的方法 - 我已经阅读了有关 sinon 和存根的内容,但这主要是关于拦截函数而不是触发它们。

下面测试

shallow(<Parent />).instance().foo();

是一个弱测试,因为它不测试连接我的 child 和 parent 的代码行,以防我没有为我的 [=33= 编写单元测试],它也不测试 child 的 onChange 功能。恕我直言 - 如果将我的组件分解为 parents/children 意味着可测试性降低 - 那么这个框架有问题

任何帮助将不胜感激,谢谢

试着把你的测试分成几个部分。例如...

首先,测试预期的功能是否已传递给您的子组件:

import { shallow } from 'enzyme';

const actual = shallow(<Parent />);
const expected = <Child onChange={actual.instance().foo} />

expect(actual.matchesElement(expected)).true;

当我正在测试的组件中几乎没有渲染时,我喜欢使用上面的简单 matchesElement 方法,但您也可以使用 find 选择器来查找 Child 实例然后测试它。

然后单独测试你的 foo 函数:

import { shallow } from 'enzyme';

const actual = shallow(<Parent />).instance().foo();
const expected = 'expected return of foo'

expect(actual).equals(expected);

您可以单独测试 Child 组件以及它如何处理它的 onChange 属性。

这里使用了一些酶 API:

另见:

这是我在很多测试中所做的事情。我发现最适合我的方法是手动调用 child 组件的 onChange 处理程序,并根据预期结果发生的行为做出断言。

假设您有一个如下所示的 Parent 组件:

import React from 'react';
import Child from './child';

export default class extends React.Component {
    render() {
        return (
            <div>
                <Child onChange={this.foo} />
            </div>
        );
    }

    foo() {
        console.log('bar');
    }
}

传递给 child 的 onChange 属性将在调用时记录字符串 'bar'。这是我们要测试的行为。为此,我们需要执行以下步骤:

  1. Stub console.log 使用你选择的模拟库(我将在这个例子中使用 Sinon)

  2. 创建 Parent 组件的浅实例,并获取对其 Child 的引用。

  3. 手动调用 Child 的 onChange 属性。

  4. 断言 console.log 被调用了一次,并且只有一个参数:'bar'

下面是我的做法(使用 mocha 和 chai):

import Foo from './foo';

import React from 'react';
import {shallow} from 'enzyme';

import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import chai, {expect} from 'chai';

describe('Foo', () => {
    let renderedElement;

    function renderComponent() {
        const componentElement = React.createElement(Foo);

        renderedElement = shallow(componentElement);
    }

    before(() => {
        chai.use(sinonChai);
    });

    it('should log the string "bar" when the child component is changed', () => {
        //step 1
        sinon.stub(console, 'log');

        //step 2
        renderComponent();
        const childComponent = renderedElement.props().children;

        //step 3
        childComponent.props.onChange();

        //step 4
        expect(console.log).to.have.callCount(1);
        expect(console.log).to.be.calledWith('bar');

        //clean up
        console.log.restore();
    });
});

我喜欢这种方法的原因是因为它测试组件 行为 而不是简单地测试它是否作为 prop 传递给它恰好等于另一个函数。