【问题标题】:ReactJS Unit Testing - TypeError: this.props.onChange is not a functionReactJS 单元测试-TypeError:this.props.onChange 不是函数
【发布时间】:2017-08-23 19:58:37
【问题描述】:

我正在使用涉及 Login 的 karma+jasmine 对 React 组件进行单元测试。测试总是抛出错误

? LoginForm test > ValidatedInput test > should validate password

TypeError:this.props.onChange 不是函数

 at ValidatedInput.handleChangeValue (src/components/ValidatedInput.js:14:24)
 at node_modules/enzyme/build/ShallowWrapper.js:844:23
 at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-test-renderer/lib/shallow/Transaction.js:143:20)
 at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactDefaultBatchingStrategy.js:62:26)
 at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactUpdates.js:97:27)
 at ReactShallowRenderer.unstable_batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:130:25)
 at performBatchedUpdates (node_modules/enzyme/build/ShallowWrapper.js:103:21)
 at node_modules/enzyme/build/ShallowWrapper.js:843:13
 at withSetStateAllowed (node_modules/enzyme/build/Utils.js:284:3)
 at ShallowWrapper.simulate (node_modules/enzyme/build/ShallowWrapper.js:840:42)
 at Object.<anonymous> (src/__tests__/login-test.js:93:37)
 at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
 at process._tickCallback (internal/process/next_tick.js:109:7)

以下是我的文件:

LoginForm.js 渲染组件

<ValidatedInput
    name={'userId'}
    type={'text'}
    title={'User ID'}
    value={this.state.userId}
    placeholder={'Enter User ID'}
    onChange={this.handleUserIdChange}
    onComponentMounted={this.handleRegisterFormFields}
    validations={/^[0-9]{5,10}$/}
    validationError={'This is not valid user Id'}
    isRequired={true}
/>

我在构造函数中绑定了 handleUserIdChange 并在类体中定义为

handleUserIdChange(value) {
    this.setState({ userId : value });
}

ValidatedInput.js

import React, { Component } from 'react';

class ValidatedInput extends Component {
    constructor(props) {
        super(props);

        this.handleChangeValue = this.handleChangeValue.bind(this);
        this.isValid = this.isValid.bind(this);
        this.validateInput = this.validateInput.bind(this);
    }

    /**********************************************/
    // referred function //
    handleChangeValue(e) {
        this.props.onChange(e.target.value);
        var isValidField = this.isValid(e.target);
    }
    /**********************************************/    
    isValid(input) {
        if (input.getAttribute('required') !== null && input.value === "") {
            input.classList.add('Error');
            input.nextSibling.textContent = this.props.validationError;
            return false;
        } else {
            input.classList.remove('Error');
            input.nextSibling.textContent =  '';
        }

        if(input.value !== "") {
            if(!this.validateInput(input.value)) {
                input.classList.add('Error');
                input.nextSibling.textContent = this.props.validationError;
                return false;
            } else {
                input.classList.remove('Error');
                input.nextSibling.textContent =  '';
            }
        }
            return true;
    }

    validateInput(value) {
        var regularExpressionToBeMatched = this.props.validations;
        return regularExpressionToBeMatched.test(value);
    }

    componentDidMount() {
        if (this.props.onComponentMounted) {
            this.props.onComponentMounted(this);
        }
    }

    render () {
        console.log(this.props.onChange);
        return (
            <div className="form-group">
                <div className="col-5 text-center">
                    <label htmlFor={this.props.name}>{this.props.title}</label>
                </div>
                <div className="col-5 text-center">
                    <input
                        className="form-input text-center"
                        type={this.props.type}
                        ref={this.props.name}
                        name={this.props.name}
                        value={this.props.value}
                        required={this.props.isRequired}
                        placeholder={this.props.placeholder}
                        onChange={this.handleChangeValue}
                    />
                    <span className='Error'></span>
                </div>
            </div>
        );
    }
}

export default ValidatedInput;

以下是测试代码:

it('should validate userId', () => {
    const component = shallow( <ValidatedInput
            name={'userId'}
            type={'text'}
            title={'User Id'}
            value={'001251623'}
            placeholder={'Enter User Id'}
            validations={/^[0-9]{5,10}$/}
            validationError={'This is not valid user Id'}
            isRequired={true}
    />);
    const handleChangeValue = spyOn(component.instance(), 'handleChangeValue');
    component.find('input').simulate('change', {target: { value: '00125' } });
    // expect(component.state().value).equals("00125");
    expect(handleChangeValue.calledWith('00125'));
});

我已广泛查看所有资源。该应用程序运行良好,并且 ValidatedInput 中的 console.log(this.props.onChange) 显示 bound handleUserIdChange。请提出解决方法或更改。 谢谢。

编辑 1

LoginForm.js

class LoginForm extends Component {
    constructor(props) {
        super(props);
        this.state = {
            userId : '',
            password : '',
            loginType : ['Customer', 'Payer', 'Super-User'],
            userLoggedInAs : ['Customer'],
            userType : '',
            FieldsRegister : [],
            serverMessage : '',
        }
        this.handleClearForm = this.handleClearForm.bind(this);
        this.handleSubmitForm = this.handleSubmitForm.bind(this);
        this.handleUserIdChange = this.handleUserIdChange.bind(this);
        this.handlePasswordChange = this.handlePasswordChange.bind(this);
        this.handleUserTypeChangeSelect = this.handleUserTypeChangeSelect.bind(this);
        this.handleRegisterFormFields = this.handleRegisterFormFields.bind(this);
    }

    handleUserIdChange(value) {
        this.setState({ userId : value });
    }
...

编辑 2

it('should validate userId', () => {
            const component = shallow( <ValidatedInput
                    name={'userId'}
                    type={'text'}
                    title={'User Id'}
                    value={'001251623'}
                    placeholder={'Enter User Id'}
                    validations={/^[0-9]{5,10}$/}
                    validationError={'This is not valid user Id'}
                    isRequired={true}
                    onChange={handleUserIdChange()}
            />);
            const handleChangeValue = spyOn(component.instance(), 'handleChangeValue');
            component.find('input').simulate('change', {target: { value: '00125' } });
            // expect(component.state().value).equals("00125");
            expect(handleChangeValue.calledWith('00125'));
        });

【问题讨论】:

    标签: javascript reactjs unit-testing


    【解决方案1】:

    在您的示例中,&lt;ValidateInput&gt; 组件具有 onChange 属性:

    <ValidatedInput
        ...
        onChange={this.handleUserIdChange}
    

    但在您的测试中却没有:

            const component = shallow( <ValidatedInput
                    name={'userId'}
                    type={'text'}
                    title={'User Id'}
                    value={'001251623'}
                    placeholder={'Enter User Id'}
                    validations={/^[0-9]{5,10}$/}
                    validationError={'This is not valid user Id'}
                    isRequired={true}
                    ---> Missing the onChange={..} <---
            />);
    

    【讨论】:

    • 这是在类的定义中,而不是在组件的实例中。关于应该去那里的函数 - 我不确定你想测试什么,但你可以(至少)传递一个空函数......
    • 我刚刚编辑了我的问题。我正在传递一个句柄来更改 ValidatedInput 中 userId 的值。你现在能建议吗?但错误仍然存​​在。
    • 您仍然没有更改测试代码中的任何内容。你的测试有 undefinedprop.onChange 所以当你的 handleChangeValue 函数试图运行 this.props.onChange(e.target.value) 你实际上是运行 undefined(e.target.value),这是错误的。
    • 我已经更新了测试。现在看起来合适吗?空函数(如 () )是什么意思?
    • 基本上,您要确保在更改字段值时调用了onChange 回调,因此您应该测试一下。我不确定你如何在测试系统中测试这个特定的东西。
    猜你喜欢
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    • 1970-01-01
    • 2019-11-20
    • 1970-01-01
    相关资源
    最近更新 更多