Posted 鍓嶇妫灄
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了相关的知识,希望对你有一定的参考价值。
馃懆鈥嶐煂?鍐欏湪鍓嶉潰
涓婄瘒鏂囩珷鎴戜滑宸茬粡浜嗚В浜嗗墠绔崟鍏冩祴璇曠殑鑳屾櫙鍜屽熀纭€鐨?code class="mq-5">jestapi锛屾湰绡囨枃绔犳垜浼氬厛浠嬬粛涓€涓?code class="mq-6">Enzyme锛岀劧鍚庣粨鍚堥」鐩腑鐨勪竴涓湡瀹炵粍浠讹紝鏉ヤ负瀹冪紪鍐欐祴璇曠敤渚嬨€?/p>
馃懆鈥嶐煔€ Enzyme
涓婁竴绡囦腑鎴戜滑鍏跺疄宸茬粡绠€鍗曚粙缁嶄簡enzyme
锛屼絾杩欒繙杩滀笉澶燂紝鍦ㄦ湰绡囩殑缁勪欢娴嬭瘯鐢ㄤ緥缂栧啓涓紝鎴戜滑鏈夊緢澶氬湴鏂硅鐢ㄥ埌瀹冿紝鍥犳杩欓噷涓撻棬鏉ヨ鏄庝竴涓嬨€?/p>
Enzyme
鏄敱Airbnb
寮€婧愮殑涓€涓?code class="mq-15">React鐨?code class="mq-16">javascript娴嬭瘯宸ュ叿锛屼娇React
缁勪欢鐨勮緭鍑烘洿鍔犲鏄撱€?code class="mq-18">Enzyme鐨?code class="mq-19">API鍜?code class="mq-20">jQuery鎿嶄綔DOM
涓€鏍风伒娲绘槗鐢紝鍥犱负瀹冧娇鐢ㄧ殑鏄?code class="mq-22">cheerio搴撴潵瑙f瀽铏氭嫙DOM
锛岃€?code class="mq-24">cheerio鐨勭洰鏍囧垯鏄仛鏈嶅姟鍣ㄧ鐨?code class="mq-25">jQuery銆?code class="mq-26">Enzyme鍏煎澶у鏁版柇瑷€搴撳拰娴嬭瘯妗嗘灦锛屽chai
銆?code class="mq-28">mocha銆?code class="mq-29">jasmine绛夈€?/p>
鈥?/span>馃檵 鍏充簬瀹夎鍜岄厤缃紝涓婁竴灏忚妭宸茬粡鏈夎繃璇存槑锛岃繖閲屽氨涓嶈禈杩颁簡
甯哥敤鍑芥暟
enzyme
涓湁鍑犱釜姣旇緝鏍稿績鐨勫嚱鏁帮紝濡備笅锛?/p>
-
simulate(event, mock)
锛氱敤鏉ユā鎷熶簨浠惰Е鍙戯紝event
涓轰簨浠跺悕绉帮紝mock
涓轰竴涓?event object
锛? -
instance()
锛氳繑鍥炴祴璇曠粍浠剁殑瀹炰緥锛? -
find(selector)
锛氭牴鎹€夋嫨鍣ㄦ煡鎵捐妭鐐癸紝selector
鍙互鏄?CSS
涓殑閫夋嫨鍣紝涔熷彲浠ユ槸缁勪欢鐨勬瀯閫犲嚱鏁帮紝浠ュ強缁勪欢鐨?display name
绛夛紱 -
at(index)
锛氳繑鍥炰竴涓覆鏌撹繃鐨勫璞★紱 -
text()
锛氳繑鍥炲綋鍓嶇粍浠剁殑鏂囨湰鍐呭锛? -
html()
锛氳繑鍥炲綋鍓嶇粍浠剁殑HTML
浠g爜褰㈠紡锛? -
props()
锛氳繑鍥炴牴缁勪欢鐨勬墍鏈夊睘鎬э紱 -
prop(key)
锛氳繑鍥炴牴缁勪欢鐨勬寚瀹氬睘鎬э紱 -
state()
锛氳繑鍥炴牴缁勪欢鐨勭姸鎬侊紱 -
setState(nextState)
锛氳缃牴缁勪欢鐨勭姸鎬侊紱 -
setProps(nextProps)
锛氳缃牴缁勪欢鐨勫睘鎬э紱
娓叉煋鏂瑰紡
enzyme
鏀寔涓夌鏂瑰紡鐨勬覆鏌擄細
-
shallow锛氭祬娓叉煋
锛屾槸瀵瑰畼鏂圭殑Shallow Renderer
鐨勫皝瑁呫€傚皢缁勪欢娓叉煋鎴?铏氭嫙DOM瀵硅薄
锛屽彧浼氭覆鏌撶涓€灞傦紝瀛愮粍浠跺皢涓嶄細琚覆鏌撳嚭鏉ワ紝鍥犺€屾晥鐜囬潪甯搁珮銆備笉闇€瑕?DOM 鐜锛?骞跺彲浠ヤ娇鐢?jQuery
鐨勬柟寮忚闂粍浠剁殑淇℃伅锛? -
render锛氶潤鎬佹覆鏌?/code>锛屽畠灏?
React
缁勪欢娓叉煋鎴愰潤鎬佺殑HTML
瀛楃涓诧紝鐒跺悗浣跨敤Cheerio
杩欎釜搴撹В鏋愯繖娈靛瓧绗︿覆锛屽苟杩斿洖涓€涓?Cheerio
鐨勫疄渚嬪璞★紝鍙互鐢ㄦ潵鍒嗘瀽缁勪欢鐨?html
缁撴瀯锛? -
mount锛氬畬鍏ㄦ覆鏌?/code>锛屽畠灏嗙粍浠舵覆鏌撳姞杞芥垚涓€涓?
鐪熷疄鐨凞OM鑺傜偣
锛岀敤鏉ユ祴璇?DOM API
鐨勪氦浜掑拰缁勪欢鐨勭敓鍛藉懆鏈燂紝鐢ㄥ埌浜?jsdom
鏉ユā鎷熸祻瑙堝櫒鐜銆?
涓夌鏂规硶涓紝shallow
鍜?code class="mq-93">mount鍥犱负杩斿洖鐨勬槸DOM
瀵硅薄锛屽彲浠ョ敤simulate
杩涜浜や簰妯℃嫙锛岃€?code class="mq-96">render鏂规硶涓嶅彲浠ャ€備竴鑸?code class="mq-97">shallow鏂规硶灏卞彲浠ユ弧瓒抽渶姹傦紝濡傛灉闇€瑕佸瀛愮粍浠惰繘琛屽垽鏂紝闇€瑕佷娇鐢?code class="mq-98">render锛屽鏋滈渶瑕佹祴璇曠粍浠剁殑鐢熷懡鍛ㄦ湡锛岄渶瑕佷娇鐢?code class="mq-99">mount鏂规硶銆?/p>
鈥?/span>娓叉煋鏂瑰紡閮ㄥ垎鍙傝€冪殑杩欑瘒鏂囩珷
馃惗 鈥滆俯鍧戜箣璺€濆紑鍚?/span>
缁勪欢浠g爜
棣栧厛锛屾潵鐪嬩笅鎴戜滑闇€瑕佸鍏惰繘琛屾祴璇曠殑缁勪欢閮ㄥ垎鐨勪唬鐮侊細
鈥?/span>鈿狅笍 鍥犱负鐗垫壇鍒板唴閮ㄤ唬鐮侊紝鎵€浠ュ緢澶氬湴鏂归兘鎵撶爜浜嗐€傞噸鍦ㄦ紨绀洪拡瀵逛笉鍚岀被鍨嬬殑娴嬭瘯鐢ㄤ緥鐨勭紪鍐?/p>
import { SearchOutlined } from "@ant-design/icons"
import {
Button,
Col,
DatePicker,
Input,
message,
Modal,
Row,
Select,
Table,
} from "antd"
import { connect } from "dva"
import { Link, routerRedux } from "dva/router"
import moment from "moment"
import PropTypes from "prop-types"
import React from "react"
const { Option } = Select
const { RangePicker } = DatePicker
const { confirm } = Modal
export class MarketRuleManage extends React.Component {
constructor(props) {
super(props)
this.state = {
productID: "",
}
}
componentDidMount() {
// console.log("componentDidMount鐢熷懡鍛ㄦ湡")
}
getTableColumns = (columns) => {
return [
...columns,
{
key: "operation",
title: "鎿嶄綔",
dataIndex: "operation",
render: (_text, record, _index) => {
return (
<React.Fragment>
<Button
type="primary"
size="small"
style={{ marginRight: "5px" }}
onClick={() => this.handleRuleEdit(record)}
>
缂栬緫
</Button>
<Button
type="danger"
size="small"
onClick={() => this.handleRuleDel(record)}
>
鍒犻櫎
</Button>
</React.Fragment>
)
},
},
]
}
handleSearch = () => {
console.log("鐐瑰嚮鏌ヨ")
const { pagination } = this.props
pagination.current = 1
this.handleTableChange(pagination)
}
render() {
// console.log("props11111", this.props)
const { pagination, productList, columns, match } = this.props
const { selectedRowKeys } = this.state
const rowSelection = {
selectedRowKeys,
onChange: this.onSelectChange,
}
const hasSelected = selectedRowKeys.length > 0
return (
<div className="content-box marketRule-container">
<h2>XX褰曞叆绯荤粺</h2>
<Row>
<Col className="tool-bar">
<div className="filter-span">
<label>浜у搧ID</label>
<Input
data-test="marketingRuleID"
style={{ width: 120, marginRight: "20px", marginLeft: "10px" }}
placeholder="璇疯緭鍏ヤ骇鍝両D"
maxLength={25}
onChange={this.handlemarketingRuleIDChange}
></Input>
<Button
type="primary"
icon={<SearchOutlined />}
style={{ marginRight: "15px" }}
onClick={() => this.handleSearch()}
data-test="handleSearch"
>
鏌ヨ
</Button>
</div>
</Col>
</Row>
<Row>
<Col>
<Table
tableLayout="fixed"
bordered="true"
rowKey={(record) => `${record.ruleid}`}
style={{ marginTop: "20px" }}
pagination={{
...pagination,
}}
columns={this.getTableColumns(columns)}
dataSource={productList}
rowSelection={rowSelection}
onChange={this.handleTableChange}
></Table>
</Col>
</Row>
</div>
)
}
MarketRuleManage.prototypes = {
columns: PropTypes.array,
}
MarketRuleManage.defaultProps = {
columns: [
{
key: "xxx",
title: "浜у搧ID",
dataIndex: "xxx",
width: "10%",
align: "center",
},
{
key: "xxx",
title: "浜у搧鍚嶇О",
dataIndex: "xxx",
align: "center",
},
{
key: "xxx",
title: "搴撳瓨",
dataIndex: "xxx",
align: "center",
// width: "12%"
},
{
key: "xxx",
title: "娲诲姩鏈夋晥鏈熷紑濮?,
dataIndex: "xxx",
// width: "20%",
align: "center",
render: (text) => {
return text ? moment(text).format("YYYY-MM-DD HH:mm:ss") : null
},
},
{
key: "xxx",
title: "娲诲姩鏈夋晥鏈熺粨鏉?,
dataIndex: "xxx",
// width: "20%",
align: "center",
render: (text) => {
return text ? moment(text).format("YYYY-MM-DD HH:mm:ss") : null
},
},
],
}
const mapStateToProps = ({ marketRuleManage }) => ({
pagination: marketRuleManage.pagination,
productList: marketRuleManage.productList,
productDetail: marketRuleManage.productDetail,
})
const mapDispatchToProps = (dispatch) => ({
queryMarketRules: (data) =>
dispatch({ type: "marketRuleManage/queryRules", payload: data }),
editMarketRule: (data) =>
dispatch({ type: "marketRuleManage/editMarketRule", payload: data }),
delMarketRule: (data, cb) =>
dispatch({ type: "marketRuleManage/delMarketRule", payload: data, cb }),
deleteByRuleId: (data, cb) =>
dispatch({ type: "marketRuleManage/deleteByRuleId", payload: data, cb }),
})
export default connect(mapStateToProps, mapDispatchToProps)(MarketRuleManage)
绠€鍗曚粙缁嶄竴涓嬬粍浠剁殑鍔熻兘锛氳繖鏄竴涓connect
鍖呰9鐨勯珮闃剁粍浠讹紝椤甸潰灞曠ず濡備笅锛?/p>
鎴戜滑瑕佹坊鍔犵殑娴嬭瘯鐢ㄤ緥濡備笅锛?/p>
1銆侀〉闈㈣兘澶熸甯告覆鏌?/p>
2銆?code class="mq-383">DOM娴嬭瘯锛氭爣棰樺簲璇ヤ负XX褰曞叆绯荤粺
3銆佺粍浠剁敓鍛藉懆鏈熷彲浠ヨ姝e父璋冪敤
4銆佺粍浠跺唴鏂规硶handleSearch
锛堝嵆鈥滄煡璇⑩€濇寜閽笂缁戝畾鐨勪簨浠讹級鍙互琚甯歌皟鐢?/p>
5銆佷骇鍝?ID 杈撳叆妗嗗唴瀹规洿鏀瑰悗锛?code class="mq-389">state涓?code class="mq-390">productID鍊间細闅忎箣鍙樺寲
6銆?code class="mq-392">MarketRuleManage缁勪欢搴旇鎺ュ彈鎸囧畾鐨?code class="mq-393">props鍙傛暟
娴嬭瘯椤甸潰蹇収
鏄庣‘浜嗛渶姹傦紝璁╂垜浠紑濮嬬紪鍐欑涓€鐗堢殑娴嬭瘯鐢ㄤ緥浠g爜锛?/p>
import React from "react"
import { mount, shallow } from "enzyme"
import MarketRuleManage from "../../../src/routes/marketRule-manage"
describe("XX褰曞叆绯荤粺椤甸潰", () => {
// 浣跨敤 snapshot 杩涜 UI 娴嬭瘯
it("椤甸潰搴旇兘姝e父娓叉煋", () => {
const wrapper = shallow(<MarketRuleManage />)
expect(wrapper).toMatchSnapshot()
})
})
鎵цnpm run test
:
鈥?/span>
npm run test
瀵瑰簲鐨勮剼鏈槸jest --verbose
Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(MarketRuleManage)".鎰忔€濆氨鏄垜浠渶瑕佺粰connect
鍖呰9鐨勭粍浠朵紶閫掍竴涓?code class="mq-427">store銆?/p>
缁忚繃涓€鐣悳绱紝鎴戝湪stackoverflow[1]鎵惧埌浜嗙瓟妗堬紝闇€瑕佷娇鐢?code class="mq-431">redux-mock-store涓殑configureMockStore
鏉ユā鎷熶竴涓亣鐨?code class="mq-433">store銆傛潵璋冩暣涓€涓嬫祴璇曚唬鐮侊細
import React from "react"
鉃?span class="mq-440">import { Provider } from "react-redux"
鉃?span class="mq-443">import configureMockStore from "redux-mock-store"
import { mount, shallow } from "enzyme"
import MarketRuleManage from "../../../src/routes/marketRule-manage"
鉃?span class="mq-452">const mockStore = configureMockStore()
鉃?span class="mq-453">const store = mockStore({
鉃?nbsp;marketRuleManage: {
鉃?nbsp; pagination: {},
鉃?nbsp; productList: [],
鉃?nbsp; productDetail: {},
鉃?nbsp; },
鉃晑)
鉃?span class="mq-454">const props = {
鉃?nbsp; match: {
鉃?nbsp; url: "/",
鉃?nbsp; },
鉃晑
describe("XX褰曞叆绯荤粺椤甸潰", () => {
// 浣跨敤 snapshot 杩涜 UI 娴嬭瘯
it("椤甸潰搴旇兘姝e父娓叉煋", () => {
鉃?nbsp; const wrapper = shallow(<Provider store={store}>
鉃?nbsp; <MarketRuleManage {...props} />
鉃?nbsp; </Provider>)
expect(wrapper).toMatchSnapshot()
})
})
鍐嶆杩愯npm run test
锛?img data-ratio="0.264750378214826" src="/img?url=https://mmbiz.qpic.cn/mmbiz_png/DByMFBAKmy5eRibevqRborvPJodTxwfpVMwYg06MPTKBZXkS6CKTwllzyyrHJ7oTNEEVzB947tc7JOw6dfwhAbA/640?wx_fmt=png" data-type="png" data-w="1322" _width="368px" class="mq-472" alt="閭d簺骞撮敊杩囩殑React缁勪欢鍗曞厓娴嬭瘯锛堜笅锛?>ok锛岀涓€鏉℃祴璇曠敤渚嬮€氳繃浜嗭紝骞朵笖鐢熸垚浜嗗揩鐓х洰褰?code class="mq-473">__snapshots__銆?/p>
娴嬭瘯椤甸潰DOM
鎴戜滑鎺ョ潃寰€涓嬶紝鏉ョ湅绗簩鏉℃祴璇曠敤渚嬶細DOM
娴嬭瘯锛氭爣棰樺簲璇ヤ负XX褰曞叆绯荤粺
銆?/p>
淇敼娴嬭瘯浠g爜锛?/p>
import React from "react"
import { Provider } from "react-redux"
import configureMockStore from "redux-mock-store"
import { mount, shallow } from "enzyme"
import MarketRuleManage from "../../../src/routes/marketRule-manage"
const mockStore = configureMockStore()
const store = mockStore({
marketRuleManage: {
pagination: {},
productList: [],
productDetail: {},
},
})
const props = {
match: {
url: "/",
},
}
describe("XX褰曞叆绯荤粺椤甸潰", () => {
// 浣跨敤 snapshot 杩涜 UI 娴嬭瘯
it("椤甸潰搴旇兘姝e父娓叉煋", () => {
const wrapper = shallow(<Provider store={store}>
<MarketRuleManage {...props} />
</Provider>)
expect(wrapper).toMatchSnapshot()
})
// 瀵圭粍浠惰妭鐐硅繘琛屾祴璇?/span>
it("鏍囬搴斾负'XX褰曞叆绯荤粺'", () => {
const wrapper = shallow(<Provider store={store}>
<MarketRuleManage {...props} />
</Provider>)
expect(wrapper.find("h2").text()).toBe("XX褰曞叆绯荤粺")
})
})
杩愯npm run test
锛?img data-ratio="0.36789297658862874" src="/img?url=https://mmbiz.qpic.cn/mmbiz_png/DByMFBAKmy5eRibevqRborvPJodTxwfpViaTjkn2fze0ImqbpBD98Igm63TK2M4dUiaKVunhzm71xlZYkicCzjb5sQ/640?wx_fmt=png" data-type="png" data-w="1196" _width="368px" class="mq-540" alt="閭d簺骞撮敊杩囩殑React缁勪欢鍗曞厓娴嬭瘯锛堜笅锛?>绾冲凹锛?code class="mq-541">Method 鈥渢ext鈥?is meant to be run on 1 node. 0 found instead.鎵句笉鍒?code class="mq-542">h2鏍囩锛?/p>
鎴戜滑鍦ㄥ紑绡囦粙缁?code class="mq-544">enzyme鏃讹紝鐭ラ亾瀹冩湁涓夌娓叉煋鏂瑰紡锛岄偅杩欓噷鎴戜滑鏀逛负mount
璇曡瘯銆傚啀娆¤繍琛?code class="mq-546">npm run test锛?img data-ratio="0.3739565943238731" src="/img?url=https://mmbiz.qpic.cn/mmbiz_png/DByMFBAKmy5eRibevqRborvPJodTxwfpVsjKJuwOfichdj77lxfOSPicCibhUPqOcpJBbWriaqRKXMmuCK3P3Ap2XCA/640?wx_fmt=png" data-type="png" data-w="1198" _width="368px" class="mq-547" alt="閭d簺骞撮敊杩囩殑React缁勪欢鍗曞厓娴嬭瘯锛堜笅锛?>婕備寒锛屽張鍑烘潵涓€涓柊鐨勯敊璇細Invariant Violation: You should not use <Link> outside a <Router>
涓€椤挎悳绱紝鍐嶆鍦?span class="mq-550">stackoverflow[2]鎵惧埌浜嗙瓟妗堬紙涓嶅緱涓嶈 stackoverflow 鐪熼锛夛紝鍥犱负鎴戠殑椤圭洰涓敤鍒颁簡璺敱锛岃€岃繖閲屾槸闇€瑕佸寘瑁呬竴涓嬬殑锛?/p>
import { BrowserRouter } from 'react-router-dom';
import Enzyme, { shallow, mount } from 'enzyme';
import { shape } from 'prop-types';
// Instantiate router context
const router = {
history: new BrowserRouter().history,
route: {
location: {},
match: {},
},
};
const createContext = () => ({
context: { router },
childContextTypes: { router: shape({}) },
});
export function mountWrap(node) {
return mount(node, createContext());
}
export function shallowWrap(node) {
return shallow(node, createContext());
}
杩欓噷鎴戞妸杩欓儴鍒嗕唬鐮佹彁鍙栧埌浜嗕竴涓崟鐙殑routerWrapper.js
鏂囦欢涓€?/p>
鐒跺悗鎴戜滑淇敼涓嬫祴璇曚唬鐮侊細
import React from "react"
import { Provider } from "react-redux"
import configureMockStore from "redux-mock-store"
import { mount, shallow } from "enzyme"
import MarketRuleManage from "../../../src/routes/marketRule-manage"
鉃?span class="mq-610">import {
鉃?nbsp; mountWrap,
鉃?nbsp; shallowWithIntlWrap,
鉃?nbsp; shallowWrap,
鉃晑 from "../../utils/routerWrapper"
const mockStore = configureMockStore()
const store = mockStore({
marketRuleManage: {
pagination: {},
productList: [],
productDetail: {},
},
})
const props = {
match: {
url: "/",
},
}
鉃?span class="mq-623">const wrappedShallow = () =>
shallowWrap(
<Provider store={store}>
<MarketRuleManage {...props} />
</Provider>
)
鉃?span class="mq-636">const wrappedMount = () =>
mountWrap(
<Provider store={store}>
<MarketRuleManage {...props} />
</Provider>
)
describe("XX褰曞叆绯荤粺椤甸潰", () => {
// 浣跨敤 snapshot 杩涜 UI 娴嬭瘯
it("椤甸潰搴旇兘姝e父娓叉煋", () => {
馃敡 const wrapper = wrappedShallow()
expect(wrapper).toMatchSnapshot()
})
// 瀵圭粍浠惰妭鐐硅繘琛屾祴璇?/span>
it("鏍囬搴斾负'XX褰曞叆绯荤粺'", () => {
馃敡 const wrapper = wrappedMount()
expect(wrapper.find("h2").text()).toBe("XX褰曞叆绯荤粺")
})
})
鈥?/span>鈿狅笍 娉ㄦ剰浠g爜涓殑鍥炬爣锛屸灂 浠h〃鏂板浠g爜锛岎煍?浠h〃浠g爜鏈変慨鏀?/p>
杩愯npm run test
锛?img data-ratio="0.25925925925925924" src="/img?url=https://mmbiz.qpic.cn/mmbiz_png/DByMFBAKmy5eRibevqRborvPJodTxwfpVUpJwmXPeIAh33MVLxf9Lht4cKAHz7IRNvPYMOClVf4q2BQ7P54b3cA/640?wx_fmt=png" data-type="png" data-w="1188" _width="368px" class="mq-663" alt="閭d簺骞撮敊杩囩殑React缁勪欢鍗曞厓娴嬭瘯锛堜笅锛?>
鎶ラ敊TypeError: window.matchMedia is not a function
锛岃繖鍙堟槸鍟ラ敊璇晩锛侊紒
鏌ラ槄鐩稿叧璧勬枡锛?code class="mq-667">matchMedia鏄寕杞藉湪window
涓婄殑涓€涓璞★紝琛ㄧず鎸囧畾鐨勫獟浣撴煡璇㈠瓧绗︿覆瑙f瀽鍚庣殑缁撴灉銆傚畠鍙互鐩戝惉浜嬩欢銆傞€氳繃鐩戝惉锛屽湪鏌ヨ缁撴灉鍙戠敓鍙樺寲鏃讹紝灏辫皟鐢ㄦ寚瀹氱殑鍥炶皟鍑芥暟銆?/p>
鏄剧劧jest
鍗曞厓娴嬭瘯闇€瑕佸matchMedia
瀵硅薄鍋氫竴涓?code class="mq-672">mock銆傜粡杩囨悳绱紝鍦?span class="mq-673">stackoverflow[3]杩欓噷鎵惧埌浜嗙瓟妗堬細
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
鎶婁笂杩颁唬鐮佸啓鍒颁竴涓崟鐙殑matchMedia.js
鏂囦欢涓紝鐒跺悗鍦ㄤ笂闈㈢殑routerWrapper.js
鏂囦欢涓紩鍏ワ細
import { mount, shallow } from "enzyme"
import { mountWithIntl, shallowWithIntl } from "enzyme-react-intl"
import { shape } from "prop-types"
import { BrowserRouter } from "react-router-dom"
鉃?span class="mq-716">import "./matchMedia"
// Instantiate router context
const router = {
history: new BrowserRouter().history,
route: {
location: {},
match: {},
},
}
const createContext = () => ({
context: { router },
childContextTypes: { router: shape({}) },
})
// ...
姝ゆ椂閲嶆柊杩愯npm run test
锛?/p>
娴嬭瘯鐢熷懡鍛ㄦ湡
鏉ョ湅绗笁鏉℃祴璇?case锛氱粍浠剁敓鍛藉懆鏈熷彲浠ヨ姝e父璋冪敤
浣跨敤spyOn
鏉?code class="mq-742">mock缁勪欢鐨?code class="mq-743">componentDidMount銆傛坊鍔犳祴璇曚唬鐮侊細
// 娴嬭瘯缁勪欢鐢熷懡鍛ㄦ湡
it("缁勪欢鐢熷懡鍛ㄦ湡", () => {
const componentDidMountSpy = jest.spyOn(
MarketRuleManage.prototype,
"componentDidMount"
)
const wrapper = wrappedMount()
expect(componentDidMountSpy).toHaveBeenCalled()
componentDidMountSpy.mockRestore()
})
杩愯npm run test
:鐢ㄤ緥椤哄埄閫氳繃锝?/p>
鈥?/span>璁板緱瑕佸湪鐢ㄤ緥鏈€鍚庡
mock
鐨勫嚱鏁拌繘琛?code class="mq-760">mockRestore()
娴嬭瘯缁勪欢鐨勫唴閮ㄥ嚱鏁?span class="mq-763">
鎺ョ潃鏉ョ湅绗洓鏉℃祴璇?case锛氱粍浠跺唴鏂规硶handleSearch
锛堝嵆鈥滄煡璇⑩€濇寜閽笂缁戝畾鐨勪簨浠讹級鍙互琚甯歌皟鐢ㄣ€?/p>
娣诲姞娴嬭瘯浠g爜锛?/p>
// 娴嬭瘯缁勪欢鐨勫唴閮ㄥ嚱鏁?/span>
it("缁勪欢鍐呮柟娉昲andleSearch鍙互琚甯歌皟鐢?, () => {
const wrapper = wrappedMount()
const instance = wrapper.instance()
const spyFunction = jest.spyOn(instance, "handleSearch")
instance.handleSearch()
expect(spyFunction).toHaveBeenCalled() // handleSearch琚皟鐢ㄤ簡涓€娆?/span>
spyFunction.mockRestore()
})
鎵цnpm run test
:Cannot spy the handleSearch property because it is not a function; undefined given instead锛?/p>
娌″姙娉曪紝鍙兘鎼滀竴涓嬶紝瀵绘眰绛旀锛岄鍏堝湪stackoverflow[4]寰楀埌浜嗗涓嬫柟妗堬細shallowWithIntl()鏉ュ寘瑁逛竴涓嬬粍浠讹紝鐒跺悗琚寘瑁圭殑缁勪欢闇€瑕佺敤dive()
涓€涓嬨€?/p>
鎴戠珛鍗充慨鏀逛簡浠g爜锛屽啀娆¤繍琛?code class="mq-788">npm run test锛岀粨鏋滀緷鐒舵槸涓€鏍风殑銆?/p>
娌″姙娉曪紝鎺ョ潃鎼滅储锛屽湪enzyme 鐨?365issue[5]鐪嬪埌浜嗕技涔庡緢鎺ヨ繎鐨勭瓟妗堬細jest.spyOn()涔嬪悗瀵圭粍浠惰繘琛屽己鍒舵洿鏂帮細wrapper.instance().forceUpdate()
鍜?code class="mq-795">wrapper.update()銆?/p>
鎺ョ潃淇敼浠g爜銆佽皟璇曪紝渚濈劧鏃犳晥銆?/p>
鎴戯紝閮侀椃浜嗐€傘€傘€?/p>
涓棿涔熸壘浜嗗緢澶氭柟妗堬紝浣嗛兘娌$敤銆?/p>
杩欐椂姝eソ鍦ㄥ唴閮ㄦ枃妗d笂鐪嬪埌浜嗕竴涓叾浠?BU 澶т浆鍐欑殑鍗曞厓娴嬭瘯鎬荤粨锛屼簬鏄氨鍘氱潃鑴哥毊鍘绘壘澶т浆鑱婁簡鑱婏紝鏋滀笉鍏剁劧锛岃繖鎷涘緢鍑戞晥锛屼竴璇偣閱掓ⅵ涓汉锛氫綘鐨勭粍浠惰connect
鍖呰9锛屾槸涓€涓珮闃剁粍浠讹紝闇€瑕佹嬁instance
涔嬪墠鍋氫笅find
鎿嶄綔锛岃繖鏍锋墠鑳芥嬁鍒扮湡瀹炵粍浠剁殑瀹炰緥銆?/p>
鎰熻阿瀹屽ぇ浣紝鎴戠珛鍗冲幓瀹炶返锛?/p>
// 娴嬭瘯缁勪欢鐨勫唴閮ㄥ嚱鏁?/span>
it("缁勪欢鍐呮柟娉昲andleSearch鍙互琚甯歌皟鐢?, () => {
const wrapper = wrappedMount()
const instance = wrapper.find("MarketRuleManage").instance()
const spyFunction = jest.spyOn(instance, "handleSearch")
instance.handleSearch()
expect(spyFunction).toHaveBeenCalled() // handleSearch琚皟鐢ㄤ簡涓€娆?/span>
spyFunction.mockRestore()
})
杩笉鍙婂緟鐨?code class="mq-816">npm run test:鍐欏畬杩欎釜鐢ㄤ緥锛屾垜涓嶇鍙嶆€濓細灏忎紮瀛愶紝鍩虹杩樻槸涓嶅お琛屽晩
杩樻槸瑕佸鍐欏瀹炶返鎵嶈鍟婏紒
娴嬭瘯缁勪欢 state
搴熻瘽灏戣锛屾垜浠潵鐪嬬浜旀潯娴嬭瘯鐢ㄤ緥锛氫骇鍝?ID 杈撳叆妗嗗唴瀹规洿鏀瑰悗锛?code class="mq-824">state涓?code class="mq-825">productID鍊间細闅忎箣鍙樺寲
娣诲姞娴嬭瘯浠g爜锛?/p>
// 娴嬭瘯缁勪欢state
it("浜у搧ID杈撳叆妗嗗唴瀹规洿鏀瑰悗锛宻tate涓璸roductID浼氶殢涔嬪彉鍖?, () => {
const wrapper = wrappedMount()
const inputElm = wrapper.find("[data-test='marketingRuleID']").first()
const userInput = 1111
inputElm.simulate("change", {
target: { value: userInput },
})
// console.log(
// "wrapper",
// wrapper.find("MarketRuleManage").instance().state.productID
// )
const updateProductID = wrapper.find("MarketRuleManage").instance().state
.productID
expect(updateProductID).toEqual(userInput)
})
杩欓噷鍏跺疄鏄ā鎷熺敤鎴风殑杈撳叆琛屼负锛岀劧鍚庝娇鐢?code class="mq-847">simulate鐩戝惉杈撳叆妗嗙殑change
浜嬩欢锛屾渶缁堝垽鏂?code class="mq-849">input鐨勬敼鍙樻槸鍚﹁兘鍚屾鍒?code class="mq-850">state涓€?/p>
鈥?/span>杩欎釜鐢ㄤ緥鍏跺疄鏄湁鐐?code class="mq-854">BDD鐨勬剰鎬濅簡
鎴戜滑杩愯npm run test
锛?img data-ratio="0.389413988657845" src="/img?url=https://mmbiz.qpic.cn/mmbiz_png/DByMFBAKmy5eRibevqRborvPJodTxwfpVYhmNblld6GqScKlL9Tu0RgzL0RH0BKp0NHAv9icLc3gzq6cMOUjV4SQ/640?wx_fmt=png" data-type="png" data-w="1058" _width="368px" class="mq-857" alt="閭d簺骞撮敊杩囩殑React缁勪欢鍗曞厓娴嬭瘯锛堜笅锛?>鐢ㄤ緥椤哄埄閫氳繃锝?/p>
娴嬭瘯缁勪欢 props
缁堜簬鏉ュ埌浜嗘渶鍚庝竴涓祴璇曠敤渚嬶細MarketRuleManage
缁勪欢搴旇鎺ュ彈鎸囧畾鐨?code class="mq-863">props鍙傛暟
娣诲姞娴嬭瘯浠g爜锛?/p>
// 娴嬭瘯缁勪欢props
it("MarketRuleManage缁勪欢搴旇鎺ユ敹鎸囧畾鐨刾rops", () => {
const wrapper = wrappedMount()
// console.log("wrapper", wrapper.find("MarketRuleManage").instance())
const instance = wrapper.find("MarketRuleManage").instance()
expect(instance.props.match).toBeTruthy()
expect(instance.props.pagination).toBeTruthy()
expect(instance.props.productList).toBeTruthy()
expect(instance.props.productDetail).toBeTruthy()
expect(instance.props.queryMarketRules).toBeTruthy()
expect(instance.props.editMarketRule).toBeTruthy()
expect(instance.props.delMarketRule).toBeTruthy()
expect(instance.props.deleteByRuleId).toBeTruthy()
expect(instance.props.columns).toBeTruthy()
})
鎵цnpm run test
锛?/p>
鍒拌繖閲岋紝鎴戜滑鎵€鏈夌殑娴嬭瘯鐢ㄤ緥灏辨墽琛屽畬浜嗭綖
鎴戜滑鎵ц鐨勮繖 6 鏉$敤渚嬪熀鏈彲浠ユ瘮杈冨叏闈㈢殑娑电洊 1.濡傛灉瑙夊緱杩欑瘒鏂囩珷杩樹笉閿欙紝鏉ヤ釜鍒嗕韩銆佺偣璧炪€佸湪鐪?/strong>涓夎繛鍚э紝璁╂洿澶氱殑浜轰篃鐪嬪埌锝?/p>
3.鐗规畩闃舵锛屽甫濂藉彛缃╋紝鍋氬ソ涓汉闃叉姢銆?/p>
React
鐨?code class="mq-879">缁勪欢鍗曞厓娴嬭瘯浜嗭紝褰撶劧鍥犱负鎴戜滑杩欓噷鐢ㄧ殑鏄?code class="mq-880">dva锛岄偅涔堥毦鍏嶄篃瑕佸model
杩涜娴嬭瘯锛岃繖閲屾垜鏀句竴涓嬩竴涓ぇ浣殑dva-example-user-dashboard 鍗曞厓娴嬭瘯[6]锛岄噷闈㈠凡缁忓垪涓剧殑姣旇緝璇︾粏浜嗭紝鎴戝氨涓嶇彮闂ㄥ紕鏂т簡銆?/p>
馃寛 鐖卞績涓夎繛