在使用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的回調里測試才是有效的。
