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
Max Stoiber
January 15, 2016
Technology
4
700
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
380
Introduction to React.js
mxstbr
1
160
Styling React Applications
mxstbr
2
700
Scaling React.js Applications (short version)
mxstbr
2
420
Scaling React.js Applications
mxstbr
0
420
Offline is the new Black
mxstbr
3
1.1k
Exploring ES6
mxstbr
1
330
Other Decks in Technology
See All in Technology
手軽に作れる電卓を作って イベントソーシングに親しもう CQRS+ESカンファレンス2026
akinoriakatsuka
0
290
コミュニティが持つ「学びと成長の場」としての作用 / RSGT2026
ama_ch
2
260
2025-12-27 Claude CodeでPRレビュー対応を効率化する@機械学習社会実装勉強会第54回
nakamasato
4
1.4k
会社紹介資料 / Sansan Company Profile
sansan33
PRO
11
390k
AWSと生成AIで学ぶ!実行計画の読み解き方とSQLチューニングの実践
yakumo
2
520
アウトプットはいいぞ / output_iizo
uhooi
0
110
RALGO : AIを組織に組み込む方法 -アルゴリズム中心組織設計- #RSGT2026 / RALGO: How to Integrate AI into an Organization – Algorithm-Centric Organizational Design
kyonmm
PRO
3
1.3k
BidiAgent と Nova 2 Sonic から考える音声 AI について
yama3133
2
160
Claude Codeを使った情報整理術
knishioka
20
12k
All About Sansan – for New Global Engineers
sansan33
PRO
1
1.3k
AIと融ける人間の冒険
pujisi
0
120
Oracle Database@Azure:サービス概要のご紹介
oracle4engineer
PRO
3
360
Featured
See All Featured
Building a Scalable Design System with Sketch
lauravandoore
463
34k
[RailsConf 2023] Rails as a piece of cake
palkan
58
6.2k
What does AI have to do with Human Rights?
axbom
PRO
0
1.9k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
1
420
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
7.9k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
34
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
0
120
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
1.8k
4 Signs Your Business is Dying
shpigford
187
22k
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