在Jest中为React表单编写单元测试

时间:2016-11-22 20:30:46

标签: unit-testing reactjs jestjs enzyme

我的表格如下:

import React from 'react/lib/ReactWithAddons';
import { server } from '../data/server';
export const Report = React.createClass({
    mixins: [React.addons.LinkedStateMixin],

    sendReport(event) {
        event.preventDefault();
        var data = {
            ac: this.ab.checked,
            cp: this.cp.checked,
            nr: this.nr.checked,
            il: this.il.checked,
            message: this.message.value,
            name: this.name.value,
            affiliation: this.affiliation.value,
            email: this.email.value,
            address: this.address.value,
            city: this.city.value,
            country: this.country.value,
            zipcode: this.zipcode.value,
            phone: this.phone.value,
        };
        server.report(this.props.params.id, data,() => {  .....  });
    },

    render: function() {
        return (
            <form  onSubmit={this.sendReport}>
                <div><input id='reason' ref={(ref) => this.ab = ref} name='reason'  type='radio' value='ab'  required /></div>
                <div><input id='reason' ref={(ref) => this.cp = ref} name='reason' type='radio' value='cp' /></div>
                <div><input id='reason' ref={(ref) => this.nr = ref} name='reason' type='radio' value='nr'  /></div>
                <div><input id='reason' ref={(ref) => this.il = ref} name='reason' type='radio' value='il'  /></div>
                <div><textarea ref={(ref) => this.message = ref}  name='message' className="form-control" type='textarea' rows="4" cols="50"  required/></div>
                <div><input id='name' ref={(ref) => this.name = ref} name='name' className="form-control" type='text'  required /></div>
                <div><input id='affiliation' ref={(ref) => this.affiliation = ref}  name='affiliation' className="form-control" type='text' required /></div>
                <div><input id='email' ref={(ref) => this.email = ref} name='email' className="form-control" type='email' required /></div>
                <div><input id='address' ref={(ref) => this.address = ref} name='address' className="form-control" type='text'  required /></div>
                <div><input id='city' ref={(ref) => this.city = ref} name='city' className="form-control" type='text'  required /></div>
                <div><select id='country' ref={(ref) => this.country = ref} name='country' className="form-control" defaultValue=""  required >
                    <option value="">Choose country</option>
                    <option value="Canada" >Canada</option> 
                    .... 
                    </select></div>
                <div><input id='zipcode' ref={(ref) => this.zipcode = ref} name='zipcode' className="form-control" type='text'  required /></div>
                <div><input id='phone' ref={(ref) => this.phone = ref} name="phone" type='text'  pattern="[0-9]*" className="form-control" title= "Numbers Only" required /></div>
                <div><button id='send' type="submit" >Send</button></div>
            </form>
        );
    }
});

以下是我为此编写单元测试的方法:

import { Report } from '../src/components/report';
import { server } from '../src/data/server';
import { shallow } from 'enzyme';
import React from 'react/lib/ReactWithAddons';
import { shallowToJson } from 'enzyme-to-json';
import ReactTestUtils from 'react-addons-test-utils';

describe('Report form', () => {
    const component = shallow(<Report params={{ id: '1033083fe' }} />);
    const sendReport = jest.fn();

    it('sends the form correctrly', ()=> {
        var data = {cp:true, message: 'testmessage', name:'testname', affiliation:'testaaa', email:'sss@test.com', address:'test address', city:'testcity', country:'testcountry', zipcode:'12345', phone: '0987654321'}
        const button = component.find('button');
        const cp = component.find('#cp');
        const message = component.find('#message');
        const name = component.find('#name');
        const affiliation = component.find('#affiliation');
        const email = component.find('#email');
        const address = component.find('#address');
        const city = component.find('#city');
        const country = component.find('#country');
        const zipcode = component.find('#zipcode');
        const phone = component.find('#phone');

        component.setState({ phone: '0987654321' });
        expect(component.find('#phone').length).toEqual(1);

        ## cp.simulate('change', { target: { value: true } });
        ## message.simulate('change', { target: { value: 'testmessage' } });
        name.simulate('change', { target: { value: 'testname' } });
        affiliation.simulate('change', { target: { value: 'testaaa' } });
        email.simulate('change', { target: { value: 'sss@test.com' } });
        address.simulate('change', { target: { value: 'test address' } });
        city.simulate('change', { target: { value: 'testcity' } });
        country.simulate('change', { target: { value: 'testcountry' } });
        zipcode.simulate('change', { target: { value: '12345' } });
        phone.simulate('change', { target: { value: '0987654321' } });
        button.simulate('click');

        expect(sendReport).toBeCalledWith(data);        
        expect(shallowToJson(component)).toMatchSnapshot();
    });
});

目标是检查表单是否正确地将数据发送到sendreport()方法(单击send按钮后)。所有字段都是必填字段。 'cp'和message字段的模拟会返回此错误:

Method “props” is only meant to be run on a single node. 0 found instead.

所以我不得不评论他们。但是我会得到这个错误:

expect(jest.fn()).toBeCalledWith(expected)

Expected mock function to have been called with:
  [{cp:true, message: 'testmessage', name:'testname', affiliation:'testaaa', email:'sss@test.com', address:'test address', city:'testcity', country:'testcountry', zipcode:'12345', phone: '0987654321'}]
But it was not called.

1 个答案:

答案 0 :(得分:0)

我假设server是您导入反应组件文件的外部模块,如下所示:

import server from 'server'

然后你需要在你的测试文件中模拟它,就像这样

import server from '../src/data/server'
jest.mock('../src/data/server', ()=> ({server: {report: jest.fn()}}))

在您的测试中,您可以预期会调用server.report

expect(server.report.mock).toBeCalledWith(data); 

要查找只有一个元素,请使用closest而不是find,因为后者始终会返回一个元素数组,而您无法使用prop。如果你使用find,你需要像component.find.first('button')这样做,这与component.closest('button')

相同