Test Utilities
ใช้งาน ReactTestUtils
import ReactTestUtils from 'react-dom/test-utils'; // ES6
var ReactTestUtils = require('react-dom/test-utils'); // ES5 with npm
การอธิบายโดยสรุป
ในการเทส React components โดยใช้การใช้ testing framework ReactTestUtils
จะมาทำให้การเทสนั้นๆสะดวกขึ้น. ที่ Facebook เราใช้ Jest สำหรับการเทส JavaScript. เรียนรู้การเขียนเทสโดยใช้Jest ผ่านทาง เว็บไซต์JestReact Tutorial.
หมายเหตุ:
เราแนะนำให้ใช้ React Testing Library ซึ่งเป็นไลบรารี่ที่ออกแบบมาเพื่อให้ใช้งานและสนับสนุนการเขียนเทสเพื่อทดสอบ components
อีกทางเลือกหนึ่งคือ ใช้ไลบรารี่สำหรับการทดสอบนั้นคือ Enzyme ที่ทาง Airbnbได้ปล่อยออกมา, ซึ่งจะทำให้ง่ายต่อการตรวจสอบ จัดการ หรือ สำรวจ React Components’ output ของคุณ.
act()
mockComponent()
isElement()
isElementOfType()
isDOMComponent()
isCompositeComponent()
isCompositeComponentWithType()
findAllInRenderedTree()
scryRenderedDOMComponentsWithClass()
findRenderedDOMComponentWithClass()
scryRenderedDOMComponentsWithTag()
findRenderedDOMComponentWithTag()
scryRenderedComponentsWithType()
findRenderedComponentWithType()
renderIntoDocument()
Simulate
อ้างอิง
act()
ใช้เพื่อการเตรียม component ก่อนที่จะทำการ assertion(การตรวจสอบ), นำโค้ดไปครอบไว้ด้วย act()
จากนั้นเมื่อมีการ render หรือการอัปเดทเกิดขึ้นจะเกิดขึ้นภายใน act()
call. ซึ่งการเทสแบบนี้จะเป็นการจำลองการทำงานของ React บนเว็บบราวเซอร์
หมายเหตุ
หากคุณใช้
react-test-renderer
, ก็จะสามารถให้act
export ซึ่งลักษณะการทำงานเหมือนกัน
ตัวอย่างเช่น, กำหนดให้มี Counter
component:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: 0};
this.handleClick = this.handleClick.bind(this);
}
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
handleClick() {
this.setState(state => ({
count: state.count + 1,
}));
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={this.handleClick}>
Click me
</button>
</div>
);
}
}
วิธีที่เราจะเทส component นี้ด้วย act
:
import React from 'react';
import ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';import Counter from './Counter';
let container;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
container = null;
});
it('can render and update a counter', () => {
// Test first render and componentDidMount
act(() => { ReactDOM.render(<Counter />, container); }); const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 0 times');
expect(document.title).toBe('You clicked 0 times');
// Test second render and componentDidUpdate
act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); expect(label.textContent).toBe('You clicked 1 times');
expect(document.title).toBe('You clicked 1 times');
});
- อย่างลืมว่า dispatching DOM events จะทำงานก็ต่อเมื่อ DOM container นั้นถูกใส่ไว้ใน
document
. ซึ่งคุณจะสามารถใช้ไลบรารี่ เช่น React Testing Library เพื่อลด boilerplate code ลงได้. - ข้อมูลอื่นๆเพิ่มเติมเกี่ยวกับ
act
จำพวก behave พร้อมตัวอย่างและการใช้งานสามารถอ่านเพิ่มเติมได้จากrecipes
mockComponent()
mockComponent(
componentClass,
[mockTagName]
)
ใส่โมดูลของ component เข้าไปใน method นี้เพื่อทำให้เกิดเป็น component ซึ่งจะมาแทนที่การ render componet แบบปกติ การเรียก component จะเหลือเพียง <div>
(หรือ tag อื่นๆหากมีการกำหนด mockTagName
) รวมไปถึง children component เช่นกัน
หมายเหตุ:
mockComponent()
เป็น legacy API. ดังนั้นเราจึงแนะนำjest.mock()
ดีกว่า
isElement()
isElement(element)
คืนค่า true
หาก element
นั้นเป็น React element.
isElementOfType()
isElementOfType(
element,
componentClass
)
คืนค่า true
หาก element
นั้นเป็น React element และเป็นชนิด componentClass
.
isDOMComponent()
isDOMComponent(instance)
คืนค่า true
หาก instance
เป็น DOM component (เช่น <div>
หรือ <span>
).
isCompositeComponent()
isCompositeComponent(instance)
คืนค่า true
หาก instance
เป็น user-defined component เช่น class หรือ function.
isCompositeComponentWithType()
isCompositeComponentWithType(
instance,
componentClass
)
คืนค่า true
หาก instance
หากเป็น component ซึ่งชนิดของ componet นั้นคือ React componentClass
.
findAllInRenderedTree()
findAllInRenderedTree(
tree,
test
)
ตรวจสอบ component ทั้งหมดใน tree
และ รวบรวม component ที่ test(component)
เป็น true
. ฟังก์ชั่นนี้อาจหากใช้เดี่ยวๆอาจไม่ได้มีประโยชน์เท่าไหร่ ดังนั้นจึงใช้เป็นองค์ประกอบของ test utils อื่นๆ
scryRenderedDOMComponentsWithClass()
scryRenderedDOMComponentsWithClass(
tree,
className
)
ค้นหา DOM elements ของ components ใน rendered tree ซึ่ง DOM components class name ตรงกัน className
.
findRenderedDOMComponentWithClass()
findRenderedDOMComponentWithClass(
tree,
className
)
เหมือนกับ scryRenderedDOMComponentsWithClass()
แต่คาดหวังว่าจะค่าผลลัพธ์ที่ได้เพียงค่าเดียว และ คืนค่าเพียงค่านั้น หรือ throws exception ถ้าหากมีผลลัพธ์อื่นนอกเหนือจากผลลัพธ์นั้น
scryRenderedDOMComponentsWithTag()
scryRenderedDOMComponentsWithTag(
tree,
tagName
)
ค้นหา DOM elements ของ components ใน rendered tree ซึ่ง DOM components tag name matching ตรงกัน tagName
.
findRenderedDOMComponentWithTag()
findRenderedDOMComponentWithTag(
tree,
tagName
)
เหมือน scryRenderedDOMComponentsWithTag()
แต่คาดหวังว่าจะค่าผลลัพธ์ที่ได้เพียงค่าเดียว และ คืนค่าเพียงค่านั้น หรือ throws exception ถ้าหากมีผลลัพธ์อื่นนอกเหนือจากผลลัพธ์นั้น
scryRenderedComponentsWithType()
scryRenderedComponentsWithType(
tree,
componentClass
)
ค้นหา instance ของ component ที่ เป็น componentClass
.
findRenderedComponentWithType()
findRenderedComponentWithType(
tree,
componentClass
)
เหมือนกับ scryRenderedComponentsWithType()
แต่คาดหวังว่าจะค่าผลลัพธ์ที่ได้เพียงค่าเดียว และ คืนค่าเพียงค่านั้น หรือ throws exception ถ้าหากมีผลลัพธ์อื่นนอกเหนือจากผลลัพธ์นั้น
renderIntoDocument()
renderIntoDocument(element)
แสดง React element แบบ DOM node เดี่ยว ในรูปแบบ document. ฟังก์ชั่นนี้ต้องมี DOM. ฟังก์ชั่นนี้มีประสิทธิภาพเทียบได้เท่ากับ:
const domContainer = document.createElement('div');
ReactDOM.render(element, domContainer);
หมายเหตุ:
คุณจะต้องมี
window
,window.document
และwindow.document.createElement
ซึ่งใช้ได้แบบ globally ก่อนที่ คุณจะ importReact
. มิเช่นนั้น React จะคิดว่ามันไม่สามารถ access DOM แล้วจะทำให้ methods เช่นsetState
ใช้งานไม่ได้.
Utilities อื่นๆ
Simulate
Simulate.{eventName}(
element,
[eventData]
)
Simulate เป็น dispatch event บน DOM node ซึ่มีค่า eventData
event dataให้ใช้ได้.
Simulate
มี method สำหรับทุกeventในReact.
การกด element
// <button ref={(node) => this.button = node}>...</button>
const node = this.button;
ReactTestUtils.Simulate.click(node);
การใส่ค่าเข้าไปใน input field แล้วกด ENTER.
// <input ref={(node) => this.textInput = node} />
const node = this.textInput;
node.value = 'giraffe';
ReactTestUtils.Simulate.change(node);
ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
หมายเหตุ
คุณจะต้องกำหนด event property ที่คุณจะใช้ในแต่ละ component เอง (e.g. keyCode, which, etc…) ซึ่ง React ไม่ได้กำหนดให้.