Testing React.js Applications

48619fc17b3ab68472aebd56c0106278?s=47 Max Stoiber
January 15, 2016

Testing React.js Applications

48619fc17b3ab68472aebd56c0106278?s=128

Max Stoiber

January 15, 2016
Tweet

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