Chào mừng các bạn trở lại với series Học React/Redux qua ví dụ thực tế, trong bài trước chúng ta đã setup xong project và đã viết được những React component đầu tiên. Trong bài học lần này tôi sẽ hướng dẫn các bạn các setup để test các React component. Tôi sẽ hướng dẫn testing một cách cơ bản mà không đi quá sâu vào chủ để testing đâu nhé!
Để test, chúng ta sẽ sử dụng mocha, một test framework, chai môt thư viện dùng để so sánh, và jsdom một thư viện cung cấp cho chúng ta những tính năng truy xuất vào DOM trên node.
Cài đặt
Từ thư mục gốc của project các bạn cài đặt như sau.
npm install --save-dev mocha chai jsdom
Tiếp đến chúng ta cần một file setup để chứa các config. Từ thư mục gốc các bạn tạo file test setup như sau.
mkdir test cd test touch setup.js
Mở file setup.js
và bắt đầu cài đặt môi trường test thôi.
import React from 'react'; | |
import {expect} from 'chai'; | |
import jsdom from 'jsdom'; | |
const document = jsdom.jsdom('<!doctype html><html><body></body></html>'); | |
const window = document.defaultView; | |
global.document = document; | |
global.window = window; | |
Object.keys(window).forEach((key) => { | |
if (!(key in global)) { | |
global[key] = window[key]; | |
} | |
}); | |
global.React = React; | |
global.expect = expect; |
Về cơ bản, chúng ta expose một jsdom document đã được generate và một window object ra global scope, những thứ này sẽ được sử dụng bởi React trong quá trình test. Ngoài ra chúng ta cũng cần phải expose tất cả các thuộc tính của window object để chúng có thể được sử dụng sau. Cuối cùng nhưng cũng không kém phần quan trọng đó là cho phép những object React cũng như expect được truy xuất ở global scope. Điều này giúp chúng ta không phải tốn công import chúng vào mỗi khi muốn test.
Trong file package.json
chúng ta sẽ thêm một script mới để chạy test, script này sẽ dùng mocha như là test framework, sửu dụng file test/setup.js
để cài đặt môi trường và duyệt qua tất cả các file có phần đuôi dạng *.spec.js
trong thư mục src
như là những test files.
... | |
"scripts": { | |
... | |
"test": "mocha --compilers js:babel-core/register --require ./test/setup.js 'src/**/*spec.js'" | |
}, | |
... |
Ngoài ra còn chúng ta còn cần một số thư viên gọn gàng hơn để giúp chúng ta test các React component. Enzyme là một thư viện hỗ trợ chúng ta giả lập trạng thái tại thời điểm test React component. Nào cùng cài đặt nó!
npm install --save-dev react-addons-test-utils enzyme
Bây giờ thì còn chờ gì nữa, bắt tay vào viết test file đầu tiên cho React component của chúng ta nào.
Đặt tay lên bàn phím viết test case thôi!
Trong thư mục src/components
tạo file TrackList.spec.js
để test component TrackList
. Cùng viết các test case cho component trong file này.
import TrackList from './TrackList'; | |
import {shallow} from 'enzyme'; | |
describe('TrackList', () => { | |
it('shows two tracks', () => { | |
const props = { | |
tracks: [{ id: 1, title: 'foo' }, { id: 2, title: 'bar' }] | |
}; | |
const element = shallow(<TrackList {...props} />); | |
expect(element.find('div')).to.have.length(2); | |
}); | |
}); |
Đây là test case tôi viết để test component TrackList
. Như chúng ta đã biết thì khi component này sẽ render ra các div
chứa title của các bài hát, ở đây tôi truyền vào props
là danh sách hai bài hát vì thế nó sẽ render ra hai div
chứa tên bài hát. Khi run test, nó sẽ phải pass.
Cùng run test bằng lệnh npm test
và xem kết quả nào.
Khoan, có điều gì không đúng!
Ơ, hình như có gì đó sai sai, test chạy fail, nào cùng double check lại nhé, test case chúng ta đưa ra là truyền vào danh sách hai bài hát thì render
ra hai div
, sao sai nhỉ?
Ngó lại component TrackList
, à thì ra là nó còn được wrap lại bởi một div
ở bên ngoài. Thay vì tìm div
thì ta phải tìm div
con của div
. Vì thế test case sẽ được sửa lại như sau.
import TrackList from './TrackList'; | |
import {shallow} from 'enzyme'; | |
describe('TrackList', () => { | |
it('shows two tracks', () => { | |
const props = { | |
tracks: [{ id: 1, title: 'foo' }, { id: 2, title: 'bar' }] | |
}; | |
const element = shallow(<TrackList {...props} />); | |
expect(element.find('div > div')).to.have.length(2); | |
}); | |
}); |
Chạy test lại nào.
Tuyệt vời, test pass rồi. Thật ra tôi cố tình viết test fail để cho các bạn thấy mặt mũi cái test fail nó ra thế nào thôi, chứ không phải tui code lởm đâu nhé, haha.
Được đà viết thêm cái test case nữa nào, lần này chúng ta sẽ test xem component có render
ra đúng tên bài hát hay không.
import TrackList from './TrackList'; | |
import {shallow} from 'enzyme'; | |
describe('TrackList', () => { | |
... | |
it('shows track title', () => { | |
const props = { | |
tracks: [{ id: 1, title: 'foo' }] | |
} | |
const element = shallow(<TrackList {...props} />); | |
expect(element.contains('foo')).to.be.true; | |
}) | |
}); |
Chạy test nào, lần này bao pass nhe, tôi tính toán hết rồi.
Ngoài ra, chúng ta có thể thêm script vào package.json
để watch xem trong quá trình develop ở local, bất cứ chỉnh sửa nào làm test fail ta cũng có thể nhìn thấy.
... | |
"scripts": { | |
... | |
"test:watch": "npm run test -- --watch" | |
}, | |
... |
Để chạy, đơn giản nhập vào termial lệnh npm run test:watch
.
Source code trong bài các bạn có thể tìm thấy ở https://github.com/codeaholicguy/react-redux-tutorial/tree/master/testing-setup
Hôm nay đến đây là đủ rồi, tôi sẽ không viết thêm test case nào nữa đâu. Tự do thoải mái sáng tạo thêm test case, nghịch chán chê đi để đợi bài sau nhé, bài sau chúng ta sẽ đụng tới Redux
đấy! Có comment gì đừng quên để lại cho tôi phía bên dưới bài viết nhé, tạm biệt!
Series được tham khảo từ: https://www.robinwieruch.de/the-soundcloud-client-in-react-redux/
Chào anh, anh có thể sửa phần sử dụng mocha được không vì nó đang báo lỗi không support nữa
Bài chia sẻ rất hay. cảm ơn ad
a ơi khi làm theo code e bị lỗi _jsdom2.default.jsdom is not a function
bạn fix như sau:
import jsdom from ‘jsdom’;
const {JSDOM} = jsdom;
const document = new JSDOM(”);
const window = document.window;
Mình chỉnh sửa theo cách của bạn rintran720 thì chạy bình thường nhưng chưa hiểu rõ được tại sao :)
const { URL } = require(“whatwg-url”);
^
Lỗi này là sao v anh?
Có thể là do em thiếu babel preset rồi, em kiểm tra lại xem sao
“test”: “mocha –compilers js:babel-core/register –require ./test/setup.js ‘src/**/*spec.js'”
Đổi thành thế này bác ơi.
“test”: “mocha –compilers js:babel-core/register –require ./test/setup.js src/**/*spec.js”
Cảm ơn haond nhé, cái này áp dụng với môi trường window nhe các bạn :D
Bài viết rất hay, Thanks ad
Mình bị lỗi này, ad help với ;)
Warning: Could not find any test files matching pattern: ‘src/**/*spec.js’
No test files found
npm ERR! Test failed. See above for more details.
Có thể là do bạn chưa setup test với file setup.js, bạn xem kĩ lại bài viết để xem thử thiếu chỗ nào nhé
mình cũng bị tương tự Could not find any test files matching pattern: ‘src/**/*spec.js’
Đã kiểm tra và không thiếu gì cả
https://github.com/codeaholicguy/react-redux-tutorial/tree/master/testing-setup Hai bạn xem qua github của mình nhé, hoặc các bạn có thể đem chi tiết lên gist để mình dễ kiểm tra hơn nhé
Mình cũng bị tương tự, nó không tìm được file để test. Mình đổi thành
“test”: “mocha –compiler ./test/setup.js ./src/**/*.spec.js* –require babel-core/register”
thì result là:
TrackList
1) shows two tracks
0 passing
1 failing
1) TrackList shows two tracks:
ReferenceError: React is not defined
at Context. (dòng này const element = shallow();)