ReactJs with Testing - part 1
Bài đăng này đã không được cập nhật trong 5 năm
Giới thiệu
Kiểm thử là công việc nhằm cải thiện chất lượng sản phẩm cũng như giúp các lập trình viên có thể kiểm tra các lỗi trong quá trình lập trình. Bài viết này mình sẽ giới thiệu với các bạn cách viết test cho 1 ứng dụng web react.
Giới thiệu về 1 Testing cơ bản
-
Đầu tiên khởi tạo react project với:
npx create-react-app demo-testing
-
Với câu lệnh trên sẽ genarate project. Và trong thư mục src bạn sẽ thấy file
App.test.js
được genarate ra để test cho file App.js-
Chúng ta thử add thêm
console.log(div.textContent)
trong fileApp.test.js
để lấy nội dung trong component App xem sao! -
chạy
yarn test
trên terminal xem kết quả trả về ra sao?
-
Viết 1 đoan test cho nội dung bên trong App component
-
expect(div.textContent).toEqual('Welcome to ReactTo get started, edit src/App.js and save to reload.')
Kết quả trả ra thành công cho câu testcase đầu tiên
Đừng lo lắng j cả. Mình sẽ giải thích cho bạn về cách viết 1 test cơ bản nhất ^^
-
Đầu tiên là
it
. Nó chính là cấu trúc của 1 test cơ bản nhất:Bao gồm 2 tham số:
it('description of the test', 'function containing our tes logic')
Tham số đầu tiên là 1 chuỗi nhằm mô tả mục đích của test này đang muốn test cái j? Tham số thứ 2 là 1 function sẽ chứa các logic để chạy. -
const div = document.createElement('div');
: Đừng nghĩ rằng chúng ta đang tạo ra 1trong browser. Nó sẽ không xuất hiện trong các browser nào cả dù là FireFox or IE, Chorme. Thay vào đó nó sẽ tự động tạ ra 1 fake div nhờ vào thư viện dom (dom library) nó được gọi là JSDOM và nó đang chứa <div> trong bộ nhớ mà không bị trói buộc bởi bất cứ trình duyệt or điều j cả. ^^ -
expect(div.textContent).toEqual('Welcome to ReactTo get started, edit src/App.js and save to reload.')
expect
là 1 function nhằm so sánh các kết quả kỳ vọng và kết quả nhận được. Nếu nó true thì test case này đúng và ngược lạiexpect('value thay we are inspecting').matcher statement(value that we expect to see)
-
value that we are inspecting là tất cả nhưng gì chúng ta muốn test
-
mathcher statement các thức so sánh
-
value that we expect to see là giá trị kỳ vọng nhận được
-
-
ReactDOM.unmountComponentAtNode(div);
: unmountComponentAtNode sẽ xóa component mà ta vừa tạo ra
-
Jest
- Jest hỗ trợ để chạy tự động các test trong app react và dưới đây là các bước hoạt động của việc test với jest
- Khi chúng ta chạy test với câu lệnh
yarn test
- Jest sẽ được chạy lên và nó sẽ tìm tất cả các file với đuôi là
.test.js
- Jest sẽ in các kết quả test ra terminal
- Khi các file thay đổi, Jest sẽ tự động chạy lại các tests.
- Khi chúng ta chạy test với câu lệnh
- Phần đầu mình sẽ hướng dẫn mọi người test với các component trước
-
remove các file không cần thiết trong thư mục src :
App.css, App.test.js, index.css, logo.svg, registerServiceWorker.js App.js
-
Chỉnh sửa file index.js với nội dung như sau:
import React from 'react'; import ReactDOM from 'react-dom'; import App from './components/App'; ReactDOM.render(<App />, document.getElementById('root'));
-
Tạo thư mục
components
trong thư mục src- Tạo file App.jsx và add nội dung file như sau:
import React from 'react'; export default () => <div>App Component</div>
- Tạo file App.jsx và add nội dung file như sau:
-
OK, Giờ mình sẽ tập viết test cho App Component với thằng Jest xem sao nhé.
-
Tạo 1 folder
__tests__
trong thư mụccomponents
để có thể chứa các file test.js giúp test các file components và để dễ quản lý các file test hơn -
Tạo file
App.test.js
trong thư mục__test__
vừa mới tạo để test fileApp.jsx
-
Add nội dung vào file App.test.js
import React from 'react' import ReactDom from 'react-dom' import App from '../App' it('Test App Component', () => { const div = document.createElement('div') ReactDom.render(<App />, div) expect(div.textContent).toEqual('App Component') ReactDom.unmountComponentAtNode(div) })
Toàn những kiến thúc cơ bản mình giới thiệu ở phần trên rồi nhé.
-
Vậy thử test với 1 component được import vào bên trong React xem sao?
- Tạo 1 CommentBox component trong thư mục components
CommentBox.jsx
- Add nội dung file:
import React from 'react' export default () => ( <div> <form> <h4>Comment Box</h4> <textarea /> <div><button>Send Comment</button></div> </form> </div> )
- Tạo 1 CommentBox component trong thư mục components
-
import CommentBox component vào App.jsx
<div> <h1>App Component<h1> <CommentBox /> </div>
-
test thử expect
expect(div.textContent).toEqual('App ComponentComment BoxSend Comment')
-
OK. vậy nó vẫn đúng khi test vs 1 component được import vào ^^
-
Tuy nhiên không, nó chưa chứng minh được điều j cả? ở trong App của tôi hoàn toàn có thể có text Comment BoxSend Comment. Và việc để tôi kiểm tra xem CommentBox có đúng là có nội dung là Comment BoxSend Comment
hay không hoàn toàn không được đảm bảo? Trong khi đó việc test component không chỉ dừng lại ở việc tôi test nội dung. Tôi có thể test xem CommnentBox có textarea
or button
hay không? Vậy để dễ dàng làm được điều đó tôi cần 1 thư viện có tên là Enzyme
, Vậy Enzyme là gi?
Enzyme
enzyme
: nó sẽ giúp hỗ trợ việc rendering component và tìm các element,..
-
Cài đặt:
yarn add --dev enzyme enzyme-adapter-react-16
Chú ý
16
tương ứng với phiên bản React của bạn. VD của tôi là"react": "^16.5.2"
=> tôi sẽ càienzyme-adapter-react16
Thế thằng enzym-adapter-react16 này là gi? Nó sẽ giúp ta config để có thể enzyme khi các file test được chạy thì enzyme có thể được gọi ở bất cứ đâu trong project
- tạo file config
setupTests.js
: như đã nói khi test được chạy thì file setupTests.js sẽ được chạy đầu tiên - add nội dung file:
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
Enzyme.configure({ adapter: new Adapter() })
-
Enzyme Api cung cấp cho chúng ta các method để có viết test
-
Rendering các component có 3 method:
- Static: Render component và trả về text HTML (như phần trên chúng ta test đó)
- Shallow: Trả về duy nhất 1 component nhưng không bao gồm các component con. (Tức là ta chỉ test CommentBox có tồn tại bên trong App hay không? còn nội dung bên trong CommentBox thì không cần quan tâm)
- Full DOm: Render tất cả các component ^^
-
Enzyme còn cung cấp khá nhiều function, method nữa. mọi người có thể vào đây xem https://airbnb.io/enzyme/docs/api/
-
OK, Giờ chúng ta viết thử nhé: Trong file App.test.js chúng ta import shallow từ emzyme và CommentBox component
import { shallow } from 'enzyme'
&&import CommentBox from '../CommentBox';
Tạo test với
it
it('show the comment box component', () => { const wrapped = shallow(<App />) // trả về App component (truy cập zô App component) expect(wrapped.find(CommentBox).length).toEqual(1) // tìm thằng CommentBox và kiểm tra xem nó có tồn tại trong App hay không? wrapped.unmount })
Vậy là tôi đã biết chắc chắn rằng tồn tại 1 thằng CommentBox trong App Phần tiếp theo tôi sẽ test xem
textarea, button
có trong thằng CommentBox hay không?- Tạo file CommentBox.test.js trong thư mục tests
- Add nội dung
import React from 'react' import CommentBox from '../CommentBox' import { mount } from 'enzyme' it('has a text area and a button', () => { const wrapped = mount(<CommentBox />) expect(wrapped.find('textarea').length).toEqual(1) expect(wrapped.find('button').length).toEqual(1) wrapped.unmount() })
Dễ hiểu là khi shallow(ShallowWrapper) rendering component thì mount (ReactWrapper) nó sẽ chọc sâu vào để tìm nội dung bên trong component đó
OK expect của chúng ta hoàn toàn đúng rồi ^^
-
enzyme
cung cấp cho bạn 2 function rất hữu dụng làbeforeEach và afterEach
giúp bạn có thể DRY code hiệu quả VD: Ở trong App của bạn có nhiều component khác. Và bạn cần phải test tất cả nó. Tương ứng với việc trong mỗiit
bạn cần phảishallow
vàunmount
nó. làm code bạn nhìn không DRY và dài. Vì vậy bạn cần dùngbeforeEach và afterEach
(nó như kiểu before vs after của rspec vậy =)))OK thử viết xem sao:
//CommentBox.test.js let wrapped beforeEach(() => { wrapped = mount(<CommentBox />) }) afterEach(() => { wrapped.unmount() }) it('has a text area and a button', () => { expect(wrapped.find('textarea').length).toEqual(1) expect(wrapped.find('button').length).toEqual(1) })
Kết Luận
Ok Ở phần 1 mình chỉ xin giới thiệu với mọi người về cú pháp của test, cách viết test 1 component, Jest, Enzyme. Bài sau mình sẽ hướng dẫn test reducer, action,... Hẹn gặp mọi người ở loạt bài sau ^^
All rights reserved