使用axios-mock-adapter对axios请求进行mock
在使用jest和enzyme对react进行单元测试时,如果我们需要对axios的请求进行测试,可以使用axios-mock-adapter。
这里只是拿单元测试举例,正常逻辑里的mock也可以使用,但是既然单元测试都通过了正常逻辑里不用也无所谓了(因为正常逻辑里加了后面也得删...)。
vSwitch.ui.jsx代码如下:(看黄色部分即可)
import React, { useState, useEffect } from "react"; import axios from '../../../request'; import { Form, Input, Select } from 'antd'; import { FetchAvailabilityZoneURL } from "../url"; const { Option } = Select; const TextArea = Input.TextArea; const ReactRender = (props) => { const { type, cellId, db } = props; const { getFieldDecorator } = props.form; const doc = db.getDoc(type, cellId); const vpcDoc = db.getDocByRefId(doc.vpc_id); let vpcName = vpcDoc.name; const onSubmit = (e) => { e.preventDefault(); props.form.validateFields((err, values) => { if (!err) { // 所属vPC始终要用vpc_id的值保存 values.vpc_id = doc.vpc_id; db.updateDoc(type, cellId, values); } }); }; let [allData, setData] = useState(() => { return { availabilityZoneData: [] }; }); useEffect(() => { axios.post(FetchAvailabilityZoneURL, { "multi": true }) .then((response) => { const availabilityZoneData = response.data.ids; setData(allData => ({ ...allData, availabilityZoneData })); }).catch((error) => { }); }, []); return ( <Form onChange={onSubmit} onClick={onSubmit}> <Form.Item label="名称"> {getFieldDecorator('name', { initialValue: doc.name, rules: [{ required: true, message: '请填写名称' }], })(<Input />)} </Form.Item> <Form.Item label="描述"> {getFieldDecorator('description', { initialValue: doc.description })(<TextArea rows={5} />)} </Form.Item> <Form.Item label="所属vPC"> <React.Fragment> {getFieldDecorator('vpc_id', { initialValue: vpcName, rules: [{ required: true, message: '自动关联vPC' }], })(<Input hidden />)} <span>{vpcName}</span> </React.Fragment> </Form.Item> <Form.Item label="IPv4地址范围"> {getFieldDecorator('cidr_block', { initialValue: doc.cidr_block, rules: [{ required: true, message: '请填写IPv4地址范围' }, { pattern: /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/, message: '请填写正确的CIDR(如:192.168.11.0/16)' }], })(<Input />)} </Form.Item> <Form.Item label="可用区"> {getFieldDecorator('availability_zone', { initialValue: doc.availability_zone || undefined, rules: [{ required: true, message: '请选择可用区' }], })( <Select showSearch style={{ width: '100%' }} placeholder="请选择可用区" optionFilterProp="children" filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 } > { allData.availabilityZoneData && allData.availabilityZoneData.map(item => <Option key={item} value={item}>{item}</Option> ) } </Select> )} </Form.Item> </Form> ) }; export default Form.create()(ReactRender);
vSwitch.test.jsx代码如下:(看黄色部分即可)
import MockAdapter from "axios-mock-adapter"; import axios from "../../../request"; import VSwitch from "../component/vSwitch"; import { mount } from 'enzyme'; import { FetchAvailabilityZoneURL } from "../url"; import { getDatabase, getGlobalID } from "../../../database"; describe("vSwitch测试", () => { const mock = new MockAdapter(axios); const vSwitch = new VSwitch(); const db = getDatabase(); // 模仿UI操作,添加一个cell,然后立即调用渲染方法 vSwitch.onAdd("alicloud_vswitch", { id: 1 }); const wrapper = mount(vSwitch.render("alicloud_vswitch", 1)); // 为select下拉框设置默认值 // const component = wrapper.dive(); wrapper.instance().setFieldsValue({ availability_zone: `cn-shanghai-a`, }); it('render', () => { const data = { ids: ["cn-shanghai-a", "cn-shanghai-b", "cn-shanghai-c", "cn-shanghai-d", "cn-shanghai-e", "cn-shanghai-f"] }; mock.onPost(FetchAvailabilityZoneURL).reply( (config) => { return new Promise(function (resolve, reject) { resolve([200, data]); }).then(() => { wrapper.find('#availability_zone .ant-select-selection__rendered').simulate('click'); expect(wrapper.find('.ant-select-dropdown-menu li').length).toBe(6); }); } ); expect(wrapper.find("FormItem").length).toBe(5); expect(wrapper.find("FormItem").first().props().label).toBe('名称'); expect(wrapper.find("FormItem").get(1).props.label).toBe('描述'); expect(wrapper.find("FormItem").get(2).props.label).toBe('所属vPC'); expect(wrapper.find("FormItem").get(3).props.label).toBe('IPv4地址范围'); expect(wrapper.find("FormItem").last().props().label).toBe('可用区'); }); it('onInParent', () => { const vpcCellId = 10; const vpcDoc = db.saveDoc("alicloud_vpc", vpcCellId, { name: "test", cidr_block: "10.10.0.0/16", description: "test" }); // 和vPC建立关系 const vpcCell = { data: { type: "alicloud_vpc", provider: "alicloud" }, id: vpcCellId }; vSwitch.onInParent("alicloud_vswitch", { id: 1 }, vpcCell); const vswtichDoc = db.getDoc("alicloud_vswitch", 1); expect(vswtichDoc.vpc_id).toBe(getGlobalID(vpcDoc)); }); it('onInputChange', () => { wrapper.find('input').at(0).simulate('change', { target: { value: "test_vswitch_name" } }); expect(wrapper.find('input').at(0).prop('value')).toBe('test_vswitch_name'); wrapper.find('input').at(1).simulate('change', { target: { value: "test_vpc_description" } }); expect(wrapper.find('input').at(1).prop('value')).toBe('test_vpc_description'); wrapper.find('input').at(3).simulate('change', { target: { value: "192.168.11.0/16" } }); expect(wrapper.find('input').at(3).prop('value')).toBe('192.168.11.0/16'); wrapper.find('#availability_zone .ant-select-selection__rendered').simulate('click'); wrapper.find('.ant-select-dropdown-menu li').at(0).simulate('click'); expect(wrapper.find('.ant-select-selection-selected-value').prop('title')).toBe('cn-shanghai-a'); }); it('onDelete', () => { // 删除alicloud_vswitch vSwitch.onDelete("alicloud_vswitch", { id: 1 }); const vswtichDoc = db.getDoc("alicloud_vswitch", 1); expect(vswtichDoc).toBeUndefined(); }); });
总的来说就是要在Promise的回调里测试才是有效的。