Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testing React.js Applications

Max Stoiber
January 15, 2016

Testing React.js Applications

Max Stoiber

January 15, 2016
Tweet

More Decks by Max Stoiber

Other Decks in Technology

Transcript

  1. Testing React.js Applications Max Stoiber - @mxstbr

  2. Max Stoiber Max Stoiber – @mxstbr – mxstbr.com Freelance Front-End

    Developer @mxstbr
  3. Max Stoiber – @mxstbr – mxstbr.com

  4. TYPES Max Stoiber – @mxstbr – mxstbr.com

  5. SYSTEM TESTING Max Stoiber – @mxstbr – mxstbr.com STRESS TESTING

    PERFORMANCE TESTING USABILITY TESTING UNIT TESTING
  6. Max Stoiber – @mxstbr – mxstbr.com UNIT TESTING UNIT TESTING

    SYSTEM TESTING STRESS TESTING PERFORMANCE TESTING USABILITY TESTING
  7. Max Stoiber – @mxstbr – mxstbr.com UNIT

  8. Max Stoiber – @mxstbr – mxstbr.com FUNCTION COMPONENT ACTIONS STORES

  9. WHY? Max Stoiber – @mxstbr – mxstbr.com

  10. CATCH BUGS BEFORE THEY HAPPEN Max Stoiber – @mxstbr –

    mxstbr.com
  11. EXECUTABLE DOCUMENTATION Max Stoiber – @mxstbr – mxstbr.com

  12. SAVE TIME Max Stoiber – @mxstbr – mxstbr.com

  13. WRITE BETTER CODE Max Stoiber – @mxstbr – mxstbr.com

  14. HOW? Max Stoiber – @mxstbr – mxstbr.com

  15. MOCHA Max Stoiber – @mxstbr – mxstbr.com

  16. Max Stoiber – @mxstbr – mxstbr.com

  17. MJACKSON/EXPECT Max Stoiber – @mxstbr – mxstbr.com

  18. Max Stoiber – @mxstbr – mxstbr.com

  19. Max Stoiber – @mxstbr – mxstbr.com // add.js export function

    add(x, y) { return x + y; }
  20. 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)); }); });
  21. 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)); }); });
  22. 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)); }); });
  23. 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)); }); });
  24. 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)); }); });
  25. 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)); }); });
  26. Max Stoiber – @mxstbr – mxstbr.com

  27. Max Stoiber – @mxstbr – mxstbr.com // add.js export function

    add(x, y) { return x + y; }
  28. Max Stoiber – @mxstbr – mxstbr.com // add.js export function

    add(x, y) { return x + y; x * y; }
  29. Max Stoiber – @mxstbr – mxstbr.com

  30. Max Stoiber – @mxstbr – mxstbr.com

  31. REDUX Max Stoiber – @mxstbr – mxstbr.com

  32. 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
  33. ACTIONS Max Stoiber – @mxstbr – mxstbr.com

  34. Max Stoiber – @mxstbr – mxstbr.com // NavBar.actions.js import {

    TOGGLE_NAV } from './NavBar.constants.js'; export function toggleNav() { return { type: TOGGLE_NAV }; }
  35. 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', () => { });
  36. Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>

    { describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
  37. Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>

    { describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
  38. Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>

    { describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
  39. Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>

    { describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
  40. Max Stoiber – @mxstbr – mxstbr.com describe('NavBar actions', () =>

    { describe('toggleNav', () => { it('should return the correct constant', () => { expect(toggleNav()).toEqual({ type: TOGGLE_NAV }); }); }); });
  41. Max Stoiber – @mxstbr – mxstbr.com

  42. REDUCER Max Stoiber – @mxstbr – mxstbr.com

  43. 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; } }
  44. 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', () => {}); });
  45. 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 }); }); });
  46. 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 }); }); });
  47. 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 }); }); });
  48. 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 }); }); });
  49. 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 }); }); });
  50. 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 }); }); });
  51. 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 }); }); });
  52. Max Stoiber – @mxstbr – mxstbr.com

  53. Max Stoiber – @mxstbr – mxstbr.com

  54. AIRBNB/ENZYME Max Stoiber – @mxstbr – mxstbr.com

  55. AIRBNB/ENZYME Max Stoiber – @mxstbr – mxstbr.com

  56. 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;
  57. Max Stoiber – @mxstbr – mxstbr.com <Button onClick={this._click}>Click me!</Button>

  58. Max Stoiber – @mxstbr – mxstbr.com <button>Click me!</button>

  59. 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', () => {}); });
  60. 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', () => {}); });
  61. SHALLOW RENDERING Max Stoiber – @mxstbr – mxstbr.com

  62. ONE LEVEL DEEP Max Stoiber – @mxstbr – mxstbr.com

  63. Max Stoiber – @mxstbr – mxstbr.com <div> <span className=“heading">Title</span> <Subcomponent

    /> </div>
  64. Max Stoiber – @mxstbr – mxstbr.com <div> <span class=“heading">Title</span> <div></div>

    </div> NORMAL RENDERING
  65. Max Stoiber – @mxstbr – mxstbr.com <div> <span class=“heading">Title</span> <Subcomponent

    /> </div> SHALLOW RENDERING
  66. 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', () => {}); });
  67. Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>

    { it('renders a <button>', () => { const renderedComponent = shallow( <Button></Button> ); expect( renderedComponent.find("button").node ).toExist(); }); });
  68. Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>

    { it('renders a <button>', () => { const renderedComponent = shallow( <Button></Button> ); expect( renderedComponent.find("button").node ).toExist(); }); });
  69. Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>

    { it('renders a <button>', () => { const renderedComponent = shallow( <Button></Button> ); expect( renderedComponent.find("button").node ).toExist(); }); });
  70. Max Stoiber – @mxstbr – mxstbr.com describe('<Button />', () =>

    { it('renders a <button>', () => { const renderedComponent = shallow( <Button></Button> ); expect( renderedComponent.find("button").node ).toExist(); }); });
  71. 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); }); });
  72. 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); }); });
  73. 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); }); });
  74. 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); }); });
  75. 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); }); });
  76. 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(); }); });
  77. 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(); }); });
  78. 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(); }); });
  79. 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(); }); });
  80. 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(); }); });
  81. Max Stoiber – @mxstbr – mxstbr.com

  82. @mxstbr Max Stoiber – @mxstbr – mxstbr.com HTTPS://GITHUB.COM/MXSTBR/REACT-TESTING