首页 文章

如何通过Jest测试React PropTypes?

提问于
浏览
26

我'm writing Jest tests for my React code and hoping to make use of/test the PropType checks. I am quite new to the Javascript universe. I'使用npm来安装 react-0.11.2 并且有一个简单的:

var React = require('react/addons');

在我的测试中 . 我的测试看起来非常类似于jest / react教程示例,其代码如下:

var eventCell = TestUtils.renderIntoDocument(
  <EventCell
    slot={slot}
    weekId={weekId}
    day={day}
    eventTypes={eventTypes}
    />
);

var time = TestUtils.findRenderedDOMComponentWithClass(eventCell, 'time');
expect(time.getDOMNode().textContent).toEqual('19:00 ');

但是,似乎没有触发 EventCell 组件中的PropType检查 . 我知道检查只在开发模式下运行,但后来我也认为通过npm获取 react 给了你开发版本 . 当我使用watchify构建组件时,检查会在浏览器中触发 .

我错过了什么?

5 回答

  • 6

    根本问题是How to test console.log?

    简短的回答是你应该在测试期间更换 console.{method} . 常见的方法是使用spies . 在这种特殊情况下,您可能希望使用stubs来阻止输出 .

    以下是使用Sinon.js的示例实现(Sinon.js提供了独立的 Spy ,存根和模拟):

    import {
        expect
    } from 'chai';
    import DateName from './../../src/app/components/DateName';
    import createComponent from './create-component';
    import sinon from 'sinon';
    
    describe('DateName', () => {
        it('throws an error if date input does not represent 12:00:00 AM UTC', () => {
            let stub;
    
            stub = sinon.stub(console, 'error');
    
            createComponent(DateName, {date: 1470009600000});
    
            expect(stub.calledOnce).to.equal(true);
            expect(stub.calledWithExactly('Warning: Failed propType: Date unix timestamp must represent 00:00:00 (HH:mm:ss) time.')).to.equal(true);
    
            console.error.restore();
        });
    });
    

    在此示例中, DataName 组件在使用不表示精确日期(12:00:00 AM)的时间戳值初始化时将引发错误 .

    我正在使用 console.error 方法(这是Facebook warning 模块在内部使用它来生成错误) . 我确保已经调用了一次存根,并且只有一个参数表示错误 .

  • 4

    Intro

    @ Gajus的答案肯定帮助了我(所以, thanks Gajus ) . 但是,我想我会提供一个答案:

    • 使用更多 up-to-date React (v15.4.1)

    • 使用 Jest (React附带)

    • 允许对单个道具进行 multiple prop values 测试

    • more generic

    Summary

    就像Gajus和其他人在其他地方提出的方法一样,我建议的基本方法也是 determine whether or not console.error is used by React in response to an unacceptable test prop value . 具体而言,此方法涉及对每个测试道具值执行以下操作:

    • mocking and clearing console.error (以确保事先调用 console.error 不会干扰),

    • creating the component using the test prop value 正在考虑中,并且

    • confirming whether or not console.error was fired 如预期的那样 .

    The testPropTypes Function

    以下代码可以放在测试中,也可以作为单独的导入/必需模块/文件放置:

    const testPropTypes = (component, propName, arraysOfTestValues, otherProps) => {
        console.error = jest.fn();
        const _test = (testValues, expectError) => {
            for (let propValue of testValues) {
                console.error.mockClear();
                React.createElement(component, {...otherProps, [propName]: propValue});
                expect(console.error).toHaveBeenCalledTimes(expectError ? 1 : 0);
            }
        };
        _test(arraysOfTestValues[0], false);
        _test(arraysOfTestValues[1], true);
    };
    

    Calling the Function

    任何检查 propTypes 的测试都可以 call testPropTypes 使用三个或四个 parameters

    • component ,由道具修改的React component ;

    • propName ,字符串 name of the prop 正在测试中;

    • arraysOfTestValues ,要测试的道具的 all the desired test values 数组数组:

    • 第一个子数组包含所有 acceptable 测试道具值,而

    • 第二个子数组包含所有 unacceptable 测试道具值;和

    • 可选, otherProps ,包含此组件的 prop name/value pairs for any other required props 的对象 .

    需要 otherProps 对象以确保React不会对 console.error 进行无关的调用,因为其他必需的道具无意中丢失了 . 只需为任何所需道具包含一个可接受的值,例如: {requiredPropName1: anyAcceptableValue, requiredPropName2: anyAcceptableValue} .

    Function Logic

    该功能执行以下操作:

    • sets up a mock of console.error 这是React用于报告不正确类型的道具的内容 .

    • 对于 each sub-array 测试道具值,在每个子阵列中提供 loops through each test prop value 以测试道具类型:

    • 两个子数组中的第一个应该是 acceptable test prop values 的列表 .

    • 第二个应该是 unacceptable test prop values .

    • 在每个单独的测试支柱值的循环内, the console.error mock is first cleared ,以便可以假定检测到的任何错误消息来自此测试 .

    • component is then created using the test prop value 的一个实例以及当前未测试的任何其他必要的道具 .

    • 最后,检查 see whether a warning has been triggered ,如果您的测试尝试使用不合适或缺少的道具创建组件,则应该进行检查 .

    Testing for Optional versus Required Props

    请注意,从React的角度来看,将 null (或 undefined )赋值给prop值,基本上与不为该prop提供任何值相同 . 根据定义,这对于可选的道具是可接受的,但对于所需的道具是不可接受的 . 因此, by placing null in either the array of acceptable or unacceptable values you test whether that prop is optional or required respectively .

    Example Code

    MyComponent.js(只是 propTypes ):

    MyComponent.propTypes = {
        myProp1: React.PropTypes.number,      // optional number
        myProp2: React.PropTypes.oneOfType([  // required number or array of numbers
            React.PropTypes.number,
            React.PropTypes.arrayOf(React.PropTypes.number)
        ]).isRequired
    

    MyComponent.test.js:

    describe('MyComponent', () => {
    
        it('should accept an optional number for myProp1', () => {
            const testValues = [
                [0, null],   // acceptable values; note: null is acceptable
                ['', []] // unacceptable values
            ];
            testPropTypes(MyComponent, 'myProp1', testValues, {myProp2: 123});
        });
    
        it('should require a number or an array of numbers for myProp2', () => {
            const testValues = [
                [0, [0]], // acceptable values
                ['', null] // unacceptable values; note: null is unacceptable
            ];
            testPropTypes(MyComponent, 'myProp2', testValues);
        });
    });
    

    Limitation of This Approach (IMPORTANT)

    目前在如何使用这种方法方面存在一些重大限制,如果过度使用,可能会成为一些难以追踪的测试错误的来源 . this other SO question/answer解释了这些限制的原因和影响 . 总之,对于简单的道具类型,例如 myProp1 ,您可以根据需要测试尽可能多的不可接受的非测试道具值,只要它们全部是不同的数据类型 . 对于某些复杂的道具类型,例如 myProp2 ,您只能测试任何类型的单个不可接受的非 null prop值 . 请参阅其他问题/答案以进行更深入的讨论 .

  • 2

    模拟 console.error 不适合用于单元测试! @AndrewWillems在上面的评论中链接到another SO question,该评论描述了这种方法的问题 .

    查看this issue on facebook/prop-types,了解该库抛出而不是记录propType错误的能力(在撰写本文时,它不受支持) .

    我已经发布了一个帮助程序库,以便在平均时间内提供该行为,check-prop-types . 你可以像这样使用它:

    import PropTypes from 'prop-types';
    import checkPropTypes from 'check-prop-types';
    
    const HelloComponent = ({ name }) => (
      <h1>Hi, {name}</h1>
    );
    
    HelloComponent.propTypes = {
      name: PropTypes.string.isRequired,
    };
    
    let result = checkPropTypes(HelloComponent.propTypes, { name: 'Julia' }, 'prop', HelloComponent.name);
    assert(`result` === null);
    
    result = checkPropTypes(HelloComponent.propTypes, { name: 123 }, 'prop', HelloComponent.name);
    assert(`result` === 'Failed prop type: Invalid prop `name` of type `number` supplied to `HelloComponent`, expected `string`.');
    
  • 30

    新包jest-prop-type-error很容易添加,并且在 PropType 错误上失败:

    安装途径:

    yarn add -D jest-prop-type-error
    

    然后将以下内容添加到 jest 部分的 package.jsonsetupFiles 中:

    "setupFiles": [
      "jest-prop-type-error"
    ]
    
  • 1

    由于ReactJS只会向控制台发送警告但实际上不会抛出错误,我会以这种方式测试prop值:

    var myTestElement = TestUtils.renderIntoDocument(
    <MyTestElement height={100} /> );
    
    it("check MyTestElement props", function() {
    
       expect( typeof myTestElement.props.height ).toEqual ( 'number' );
    
    });
    

相关问题