Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Testing React.js Applications
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Max Stoiber
January 15, 2016
Technology
720
4
Share
Testing React.js Applications
Max Stoiber
January 15, 2016
More Decks by Max Stoiber
See All by Max Stoiber
Testing React Applications
mxstbr
3
340
Styling Intro
mxstbr
3
390
Introduction to React.js
mxstbr
1
170
Styling React Applications
mxstbr
2
720
Scaling React.js Applications (short version)
mxstbr
2
430
Scaling React.js Applications
mxstbr
0
430
Offline is the new Black
mxstbr
3
1.1k
Exploring ES6
mxstbr
1
340
Other Decks in Technology
See All in Technology
Introduction to Bill One Development Engineer
sansan33
PRO
0
410
申請待ちゼロへ!AWS × Entra IDで実現した「権限付与」のセルフサービス化
mhrtech
2
300
Databricksを用いたセキュアなデータ基盤構築とAIプロダクトへの応用.pdf
pkshadeck
PRO
0
320
LLM とプロンプトエンジニアリング/チューターを定義する / LLMs and Prompt Engineering, and Defining Tutors
ks91
PRO
0
390
シン・リスコフの置換原則 〜現代風に考えるSOLIDの原則〜
jinwatanabe
0
210
ふりかえりがなかった職能横断チームにふりかえりを導入してみて学んだこと 〜チームのふりかえりを「みんなで未来を考える場」にするプロローグ設計〜
masahiro1214shimokawa
0
400
プロダクトを触って語って理解する、チーム横断バグバッシュのすすめ / 20260411 Naoki Takahashi
shift_evolve
PRO
1
280
Sansan Engineering Unit 紹介資料
sansan33
PRO
1
4.2k
Proxmox超入門
devops_vtj
0
210
NOSTR, réseau social et espace de liberté décentralisé
rlifchitz
0
180
Azure Static Web Apps の自動ビルドがタイムアウトしやすくなった状況に対応した件/global-azure2026
thara0402
0
230
建設的な現実逃避のしかた / How to practice constructive escapism
pauli
4
330
Featured
See All Featured
Prompt Engineering for Job Search
mfonobong
0
260
Technical Leadership for Architectural Decision Making
baasie
3
320
Exploring anti-patterns in Rails
aemeredith
3
310
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Automating Front-end Workflow
addyosmani
1370
200k
How GitHub (no longer) Works
holman
316
150k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.9k
A better future with KSS
kneath
240
18k
Become a Pro
speakerdeck
PRO
31
5.9k
Music & Morning Musume
bryan
47
7.1k
Skip the Path - Find Your Career Trail
mkilby
1
100
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Transcript
Testing React.js Applications Max Stoiber - @mxstbr
Max Stoiber Max Stoiber – @mxstbr – mxstbr.com Freelance Front-End
Developer @mxstbr
Max Stoiber – @mxstbr – mxstbr.com
TYPES Max Stoiber – @mxstbr – mxstbr.com
SYSTEM TESTING Max Stoiber – @mxstbr – mxstbr.com STRESS TESTING
PERFORMANCE TESTING USABILITY TESTING UNIT TESTING
Max Stoiber – @mxstbr – mxstbr.com UNIT TESTING UNIT TESTING
SYSTEM TESTING STRESS TESTING PERFORMANCE TESTING USABILITY TESTING
Max Stoiber – @mxstbr – mxstbr.com UNIT
Max Stoiber – @mxstbr – mxstbr.com FUNCTION COMPONENT ACTIONS STORES
WHY? Max Stoiber – @mxstbr – mxstbr.com
CATCH BUGS BEFORE THEY HAPPEN Max Stoiber – @mxstbr –
mxstbr.com
EXECUTABLE DOCUMENTATION Max Stoiber – @mxstbr – mxstbr.com
SAVE TIME Max Stoiber – @mxstbr – mxstbr.com
WRITE BETTER CODE Max Stoiber – @mxstbr – mxstbr.com
HOW? Max Stoiber – @mxstbr – mxstbr.com
MOCHA Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com
MJACKSON/EXPECT Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com // add.js export function
add(x, y) { return x + y; }
Max Stoiber – @mxstbr – mxstbr.com // add.test.js import {
add } from './add.js'; import expect from 'expect'; describe('add()', () => { it('adds two numbers', () => { expect(add(2, 3)).toEqual(5); }); it('doesnt add the third number', () => { expect(add(2, 3, 5)).toEqual(add(2, 3)); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('add()', () => {
it('adds two numbers', () => { expect(add(2, 3)).toEqual(5); }); it('doesnt add the third number', () => { expect(add(2, 3, 5)).toEqual(add(2, 3)); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('add()', () => {
it('adds two numbers', () => { expect(add(2, 3)).toEqual(5); }); it('doesnt add the third number', () => { expect(add(2, 3, 5)).toEqual(add(2, 3)); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('add()', () => {
it('adds two numbers', () => { expect(add(2, 3)).toEqual(5); }); it('doesnt add the third number', () => { expect(add(2, 3, 5)).toEqual(add(2, 3)); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('add()', () => {
it('adds two numbers', () => { expect(add(2, 3)).toEqual(5); }); it('doesnt add the third number', () => { expect(add(2, 3, 5)).toEqual(add(2, 3)); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('add()', () => {
it('adds two numbers', () => { expect(add(2, 3)).toEqual(5); }); it('doesnt add the third number', () => { expect(add(2, 3, 5)).toEqual(add(2, 3)); }); });
Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com // add.js export function
add(x, y) { return x + y; }
Max Stoiber – @mxstbr – mxstbr.com // add.js export function
add(x, y) { return x + y; x * y; }
Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com
REDUX Max Stoiber – @mxstbr – mxstbr.com
NavBar ├── NavBar.react.js # React component │ ├── NavBar.actions.js #
Actions ├── NavBar.constants.js # Constants ├── NavBar.reducer.js # Reducer │ ├── NavBar.actions.test.js # Actions tests └── NavBar.reducer.test.js # Reducer tests Max Stoiber – @mxstbr – mxstbr.com
ACTIONS Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com // NavBar.actions.js import {
TOGGLE_NAV } from './NavBar.constants.js'; export function toggleNav() { return { type: TOGGLE_NAV }; }
Max Stoiber – @mxstbr – mxstbr.com // NavBar.actions.test.js import {
toggleNav } from './NavBar.actions'; import { TOGGLE_NAV } from './NavBar.constants'; import expect from ‘expect'; describe('NavBar actions', () => { });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>
{ describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>
{ describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>
{ describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>
{ describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>
{ describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
Max Stoiber – @mxstbr – mxstbr.com
REDUCER Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com // NavBar.reducer.js import {
TOGGLE_NAV } from ‘./NavBar.constants.js'; const initialState = { open: false }; export default function NavBarReducer(state = initialState, action) { switch (action.type) { case TOGGLE_NAV: return Object.assign({}, state, { open: !state.open }); default: return state; } }
Max Stoiber – @mxstbr – mxstbr.com // NavBar.reducer.test.js import expect
from 'expect'; import NavBarReducer from './NavBar.reducer'; import { TOGGLE_NAV } from './NavBar.constants'; import { toggleNav } from './NavBar.actions'; describe('NavBarReducer', () => { it('returns the initial state', () => {}); it('handles the toggleNav action', () => {}); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBarReducer', () => {
it('returns the initial state', () => { expect(NavBarReducer(undefined, {})).toEqual({ open: false }); }); it('handles the toggleNav action', () => { expect(NavBarReducer(undefined, toggleNav())).toEqual({ open: true }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBarReducer', () => {
it('returns the initial state', () => { expect(NavBarReducer(undefined, {})).toEqual({ open: false }); }); it('handles the toggleNav action', () => { expect(NavBarReducer(undefined, toggleNav())).toEqual({ open: true }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBarReducer', () => {
it('returns the initial state', () => { expect(NavBarReducer(undefined, {})).toEqual({ open: false }); }); it('handles the toggleNav action', () => { expect(NavBarReducer(undefined, toggleNav())).toEqual({ open: true }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBarReducer', () => {
it('returns the initial state', () => { expect(NavBarReducer(undefined, {})).toEqual({ open: false }); }); it('handles the toggleNav action', () => { expect(NavBarReducer(undefined, toggleNav())).toEqual({ open: true }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBarReducer', () => {
it('returns the initial state', () => { expect(NavBarReducer(undefined, {})).toEqual({ open: false }); }); it('handles the toggleNav action', () => { expect(NavBarReducer(undefined, toggleNav())).toEqual({ open: true }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBarReducer', () => {
it('returns the initial state', () => { expect(NavBarReducer(undefined, {})).toEqual({ open: false }); }); it('handles the toggleNav action', () => { expect(NavBarReducer(undefined, toggleNav())).toEqual({ open: true }); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('NavBarReducer', () => {
it('returns the initial state', () => { expect(NavBarReducer(undefined, {})).toEqual({ open: false }); }); it('handles the toggleNav action', () => { expect(NavBarReducer(undefined, toggleNav())).toEqual({ open: true }); }); });
Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com
AIRBNB/ENZYME Max Stoiber – @mxstbr – mxstbr.com
AIRBNB/ENZYME Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com // Button.react.js import React
from 'react'; class Button extends React.Component { render() { return ( <button className="btn" onClick={this.props.onClick}> { this.props.children } </button> ); } } export default Button;
Max Stoiber – @mxstbr – mxstbr.com <Button onClick={this._click}>Click me!</Button>
Max Stoiber – @mxstbr – mxstbr.com <button>Click me!</button>
Max Stoiber – @mxstbr – mxstbr.com // Button.test.js import Button
from './Button.react'; import expect from 'expect'; import { shallow } from 'enzyme'; import React from 'react'; describe('<Button />', () => { it('renders a <button>', () => {}); it('renders text', () => {}); it('handles clicks', () => {}); });
Max Stoiber – @mxstbr – mxstbr.com // Button.test.js import Button
from './Button.react'; import expect from 'expect'; import { shallow } from 'enzyme'; import React from 'react'; describe('<Button />', () => { it('renders a <button>', () => {}); it('renders text', () => {}); it('handles clicks', () => {}); });
SHALLOW RENDERING Max Stoiber – @mxstbr – mxstbr.com
ONE LEVEL DEEP Max Stoiber – @mxstbr – mxstbr.com
Max Stoiber – @mxstbr – mxstbr.com <div> <span className=“heading">Title</span> <Subcomponent
/> </div>
Max Stoiber – @mxstbr – mxstbr.com <div> <span class=“heading">Title</span> <div></div>
</div> NORMAL RENDERING
Max Stoiber – @mxstbr – mxstbr.com <div> <span class=“heading">Title</span> <Subcomponent
/> </div> SHALLOW RENDERING
Max Stoiber – @mxstbr – mxstbr.com // Button.test.js import Button
from './Button.react'; import expect from 'expect'; import { shallow } from 'enzyme'; import React from 'react'; describe('<Button />', () => { it('renders a <button>', () => {}); it('renders text', () => {}); it('handles clicks', () => {}); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders a <button>', () => { const renderedComponent = shallow( <Button></Button> ); expect( renderedComponent.find("button").node ).toExist(); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders a <button>', () => { const renderedComponent = shallow( <Button></Button> ); expect( renderedComponent.find("button").node ).toExist(); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders a <button>', () => { const renderedComponent = shallow( <Button></Button> ); expect( renderedComponent.find("button").node ).toExist(); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders a <button>', () => { const renderedComponent = shallow( <Button></Button> ); expect( renderedComponent.find("button").node ).toExist(); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders text', () => { const text = "Click me!"; const renderedComponent = shallow( <Button>{ text }</Button> ); expect( renderedComponent.contains(text) ).toEqual(true); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders text', () => { const text = "Click me!"; const renderedComponent = shallow( <Button>{ text }</Button> ); expect( renderedComponent.contains(text) ).toEqual(true); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders text', () => { const text = "Click me!"; const renderedComponent = shallow( <Button>{ text }</Button> ); expect( renderedComponent.contains(text) ).toEqual(true); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders text', () => { const text = "Click me!"; const renderedComponent = shallow( <Button>{ text }</Button> ); expect( renderedComponent.contains(text) ).toEqual(true); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('renders text', () => { const text = "Click me!"; const renderedComponent = shallow( <Button>{ text }</Button> ); expect( renderedComponent.contains(text) ).toEqual(true); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('handles clicks', () => { const onClickSpy = expect.createSpy(); const renderedComponent = shallow( <Button onClick={onClickSpy} /> ); renderedComponent.find('button').simulate('click'); expect(onClickSpy).toHaveBeenCalled(); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('handles clicks', () => { const onClickSpy = expect.createSpy(); const renderedComponent = shallow( <Button onClick={onClickSpy} /> ); renderedComponent.find('button').simulate('click'); expect(onClickSpy).toHaveBeenCalled(); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('handles clicks', () => { const onClickSpy = expect.createSpy(); const renderedComponent = shallow( <Button onClick={onClickSpy} /> ); renderedComponent.find('button').simulate('click'); expect(onClickSpy).toHaveBeenCalled(); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('handles clicks', () => { const onClickSpy = expect.createSpy(); const renderedComponent = shallow( <Button onClick={onClickSpy} /> ); renderedComponent.find('button').simulate('click'); expect(onClickSpy).toHaveBeenCalled(); }); });
Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>
{ it('handles clicks', () => { const onClickSpy = expect.createSpy(); const renderedComponent = shallow( <Button onClick={onClickSpy} /> ); renderedComponent.find('button').simulate('click'); expect(onClickSpy).toHaveBeenCalled(); }); });
Max Stoiber – @mxstbr – mxstbr.com
@mxstbr Max Stoiber – @mxstbr – mxstbr.com HTTPS://GITHUB.COM/MXSTBR/REACT-TESTING