如果你的組件正在使用 Jest 快照測試荞驴,下面是一些你必須注意的陷阱。這兩條你可能會遇到在你編寫測試的時候:
- 如果實際的快照測試渲染了一個包含很多子組件的組件脓魏,那么輸出的快照測試將變得太大溶耘。這個本身就存在兩個問題:A) 僅僅通過查看快照并不能準確的發(fā)現(xiàn)快照不同的地方;B) 如果你同時快照測試你的子組件鼻忠,最終會得到重復的快照輸出涵但。
- 如果你實際的快照測試組件渲染了大量子組件,則需要在父組件的快照測試中設(shè)置子組件的所有 props帖蔓。因此矮瘟,你并沒有真正將關(guān)注點放在父組件上,而是設(shè)置子組件所有必要的信息塑娇。如果你再分開測試你的子組件澈侠,工作將變得重復,因為你必須使用相同的 props 設(shè)置來測試他們埋酬。最終你會得到重復的測試設(shè)置哨啃。
如你所見,這兩個問題只適用于渲染多個子組件的父組件奇瘦。因此,如果你可以在快照測試中淺層渲染(shadow render
)父組件劲弦,從而在測試中只關(guān)注父組件耳标;以及不管有沒有渲染了子組件都不用擔心子組件的輸出。
如果你正在使用 Jest 快照測試邑跪,你可能使用 react-test-renderer 渲染你的 React 組件:
import React from 'react';
import renderer form 'react-test-renderer';
import Profile from '.';
describe('Profile', () => {
it('renders', () => {
const component = renderer.create(<Profile />);
const tree = component.toJSON();
expect(tree).toMatchSnapShot();
});
});
如果在 Profile 組件中呈現(xiàn)許多子組件次坡,那么快照測試輸出可能會出現(xiàn)問題1呼猪。不過,您唯一應(yīng)該關(guān)心的是呈現(xiàn)的組件實例砸琅,而不是它們的內(nèi)容:
const Profile = () => (
<>
<Preferences />
<Documents />
<WorkExperience />
<Education />
<Skills />
<PersonalInfo />
</>
);
如果 Profile 組件傳遞大量的 props 給所有的子組件宋距,那么就會出現(xiàn)第二個問題,因為你必須為所有的子組件設(shè)置 props 在你快照測試症脂,即使父組件可能并不關(guān)心它們:
const Profile = ({
...preferencesProps,
...documentsProps,
...workExperienceProps,
...educationProps,
...skillsProps,
...personalInfoProps,
}) => (
<>
<Preferences {...preferencesProps} />
<Documents {...documentsProps} />
<WorkExperience {...workExperienceProps} />
<Education {...educationProps} />
<Skills {...skillsProps} />
<PersonalInfo {...personalInfoProps} />
</>
);
你希望避免上面兩個問題在父組件快照測試的時候谚赎,因為這些問題應(yīng)該在子組件他們自己進行測試。父組件只關(guān)心渲染這些子組件诱篷。
筆記:淺層渲染(Shallow rendering)快照測試對于你整體的測試戰(zhàn)略來說并不是靈丹妙藥壶唤,你可能會對你的組件工作在集成環(huán)境失去信心(例如:父子組件交互)
盡管 React 的測試渲染器提供了 shallow rendering ,但我發(fā)現(xiàn)虛擬子組件的渲染輸出更適合我的測試用例:
import React from 'react';
import renderer from 'react-test-renderer';
import Profile from '.';
jest.mock('./Preferences', () => () => 'Preferences');
jest.mock('./Documents', () => () => 'Documents');
jest.mock('./WorkExperience', () => () => 'WorkExperience');
jest.mock('./Education', () => () => 'Education');
jest.mock('./Skills', () => () => 'Skills');
jest.mock('./PersonalInfo', () => () => 'PersonalInfo');
describe('Profile', () => {
it('renders', () => {
const component = renderer.create(<Profile />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});
你的淺層渲染快照測試輸出可能看起來像下面這樣:
exports[`Profile renders 1`] = `
Array [
"Preferences",
"Documents",
"WorkExperience",
"Education",
"Skills",
"PersonalInfo",
]
`;
與渲染所有子組件來做版本比較相比棕所,它做到了最大程度的簡化闸盔。此外,你也不需要關(guān)心 props 的傳遞琳省。然而迎吵,如果你想測試你的父組件是否傳遞了必須的 props 給它的子組件,你甚至可以用一個虛擬的子組件來測試它:
import React from 'react';
import renderer from 'react-test-renderer';
import Profile from '.';
import PersonalInfo from './PersonalInfo';
jest.mock('./Preferences', () => () => 'Preferences');
jest.mock('./Documents', () => () => 'Documents');
jest.mock('./WorkExperience', () => () => 'WorkExperience');
jest.mock('./Education', () => () => 'Education');
jest.mock('./Skills', () => () => 'Skills');
jest.mock('./PersonalInfo', () => () => 'PersonalInfo');
describe('Profile', () => {
it('renders and passes props', () => {
const component = renderer.create(<Profile />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
expect(component.root.findByType(PersonalInfo).props).toEqual({
name: 'Robin Wieruch',
});
});
});
總而言之针贬,你最終為父組件創(chuàng)建了一個非常輕量級的快照測試击费,而你將在子組件自身更徹底地進行快照測試。
React 官方文檔
測試渲染器 Test Renderer(https://reactjs.org/docs/test-renderer.html
導入
import TestRenderer from 'react-test-renderer'; // ES6
const TestRenderer = require('react-test-renderer'); // ES5 with npm
總覽
這個包提供了一個 React 渲染器(React renderer
)可以將 React 組件渲染為純的 JavaScript 對象坚踩,而不用依賴于 DOM 或本地移動環(huán)境荡灾。
本質(zhì)上,這個包可以使你輕松抓取一個由 React DOM 或 React Native 組件渲染的平臺視圖層級(類似于 DOM 樹)快照瞬铸,而無需使用瀏覽器或 jsdom批幌。
例子:
import TestRenderer from 'react-test-renderer';
function Link(props) {
return <a href={props.page}>{props.children}</a>;
}
const testRenderer = TestRenderer.create(
<Link page="https://www.fackbook.com/">
);
console.log(testRenderer.toJSON());
// { type: 'a',
// props: { href: 'https://www.facebook.com/' },
// children: [ 'Facebook' ] }
你可以使用 Jest 的快照測試特性自動化地保存一份 JSON 樹的復制到一個文件中,并檢查你的測試沒有發(fā)生變化:這里學習到更多嗓节。
你也可以遍歷輸出來找到特殊的節(jié)點荧缘,并對它們進行斷言。
import TestRenderer from 'react-test-renderer';
function MyComponent() {
return (
<div>
<SubComponent foo="bar" />
<p className="my">Hello</p>
</div>
)
}
function SubComponent() {
return (
<p className="sub">Sub</p>
);
}
const testRenderer = TestRenderer.create(<MyComponent />);
const testInstance = testRenderer.root;
expect(testInstance.findByType(SubComponent).props.foo).toBe('bar');
expect(testInstance.findByProps({className: "sub"}).children).toEqual(['Sub']);
參考
TestRenderer.create()
TestRenderer.create(element, options);
使用傳遞的 React 元素創(chuàng)建一個 TestRenderer 實例拦宣。它不使用真正的DOM截粗,但仍然將組件樹完全呈現(xiàn)到內(nèi)存中,因此您可以對其進行斷言鸵隧。返回一個 TestRenderer 實例绸罗。
TestRenderer.act()
TestRenderer.act(callback);
類似于 react-dom/test-utils 里面的 act() 方法,TestRenderer.act 為斷言準備一個組件豆瘫。使用這個版本的 act() 就是封裝調(diào)用 TestRenderer.create and TestRenderer.update珊蟀。
import {create, act} from 'react-test-renderer';
import App from './app.js'; // The component being tested
// render the component
let root;
act(() => {
root = create(<App value={1}/>)
});
// make assertions on root
expect(root.toJSON()).toMatchSnapshot();
// update with some different props
act(() => {
root = root.update(<App value={2}/>);
})
// make assertions on root
expect(root.toJSON()).toMatchSnapshot();
testRenderer.toJSON()
testRenderer.toJSON();
返回一個對象呈現(xiàn)渲染樹??。這個樹僅僅包含平臺特定的節(jié)點外驱,如 <div> 或 <View> 和他們的 props育灸,但是不包含用戶編寫的組件腻窒。這對于快照測試十分方便。
testRenderer.toTree()
和 toJson() 方法唯一的區(qū)別就是它包含用戶編寫的組件磅崭。
......
React 文檔
Shallow Renderer
導入
import ShallowRenderer from 'react-test-renderer/shallow'; // ES6
var ShallowRenderer = require('react-test-renderer/shallow'); // ES5 with npm
總覽
在編寫React的單元測試時儿子,淺層呈現(xiàn)可能會有幫助。淺層呈現(xiàn)允許您呈現(xiàn)一個組件“一層深”砸喻,并斷言關(guān)于其呈現(xiàn)方法返回什么的事實柔逼,而不用擔心子組件的行為,這些子組件沒有實例化或呈現(xiàn)恩够。這并不需要DOM卒落。
例如,如果你擁有如下組件:
function MyComponent() {
return (
<div>
<span className="heading">Title</span>
<Subcomponent foo="bar" />
</div>
);
}
然后你可以斷言:
import ShallowRenderer from 'react-test-renderer/shallow';
// in your test:
const renderer = new ShallowRenderer();
renderer.render(<MyComponent />);
const result = renderer.getRenderOutput();
expect(result.type).toBe('div');
expect(result.props.children).toEqual([
<span className="heading">Title</span>,
<Subcomponent foo="bar" />
shallow 測試當前有一些限制蜂桶,例如不支持 refs儡毕。
提示:我們建議你使用 Enzyme 的 Shallow Rendering API 它在相同的功能上提供了更高級的 API
參考
shallowRenderer.render()
您可以將shallowRenderer視為呈現(xiàn)正在測試的組件的“位置”,并從中提取組件的輸出扑媚。
render()類似于ReactDOM.render()腰湾,但它不需要DOM,只呈現(xiàn)一個層次的深度疆股。這意味著您可以測試與子組件的實現(xiàn)方式隔離的組件费坊。
shallowRenderer.getRenderOutput()
調(diào)用了shallowRenderer.render()之后,您可以使用shallowRenderer.getRenderOutput()獲得淺呈現(xiàn)的輸出旬痹。
然后可以開始斷言關(guān)于輸出的事實附井。