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
4
710
Testing React.js Applications
Max Stoiber
January 15, 2016
Tweet
Share
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
160
Styling React Applications
mxstbr
2
700
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
M&A 後の統合をどう進めるか ─ ナレッジワーク × Poetics が実践した組織とシステムの融合
kworkdev
PRO
1
410
We Built for Predictability; The Workloads Didn’t Care
stahnma
0
130
あたらしい上流工程の形。 0日導入からはじめるAI駆動PM
kumaiu
5
760
15 years with Rails and DDD (AI Edition)
andrzejkrzywda
0
170
日本語テキストと音楽の対照学習の技術とその応用
lycorptech_jp
PRO
1
420
(金融庁共催)第4回金融データ活用チャレンジ勉強会資料
takumimukaiyama
0
120
Introduction to Sansan, inc / Sansan Global Development Center, Inc.
sansan33
PRO
0
3k
~Everything as Codeを諦めない~ 後からCDK
mu7889yoon
3
270
Bill One急成長の舞台裏 開発組織が直面した失敗と教訓
sansantech
PRO
1
290
仕様書駆動AI開発の実践: Issue→Skill→PRテンプレで 再現性を作る
knishioka
2
590
Deno・Bunの標準機能やElysiaJSを使ったWebSocketサーバー実装 / ラーメン屋を貸し切ってLT会! IoTLT 2026新年会
you
PRO
0
290
Context Engineeringが企業で不可欠になる理由
hirosatogamo
PRO
3
410
Featured
See All Featured
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
231
22k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
21k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
380
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
Art, The Web, and Tiny UX
lynnandtonic
304
21k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
63
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.1k
Darren the Foodie - Storyboard
khoart
PRO
2
2.3k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
88
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.2k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
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