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

Testing React Applications

Testing React Applications

Max Stoiber

March 01, 2017
Tweet

More Decks by Max Stoiber

Other Decks in Technology

Transcript

  1. Let’s talk about testing

    View Slide

  2. Which types of testing are there?

    View Slide

  3. Unit Testing

    View Slide

  4. Unit

    View Slide

  5. Function
    Components
    Actions
    Reducers

    View Slide

  6. Why should you test?

    View Slide

  7. Catch some bugs before they
    happen

    View Slide

  8. View Slide

  9. Executable Documentation

    View Slide

  10. Write Better Code

    View Slide

  11. // add.js
    export function add(x, y) {
    return x + y;
    }

    View Slide

  12. // add.test.js
    import { add } from './add.js';
    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));
    });
    });

    View Slide

  13. // add.test.js
    import { add } from './add.js';
    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));
    });
    });

    View Slide

  14. // add.test.js
    import { add } from './add.js';
    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));
    });
    });

    View Slide

  15. // add.test.js
    import { add } from './add.js';
    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));
    });
    });

    View Slide

  16. // add.test.js
    import { add } from './add.js';
    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));
    });
    });

    View Slide

  17. Max Stoiber – @mxstbr – mxstbr.com

    View Slide

  18. // add.js
    export function add(x, y) {
    return x + y;
    }

    View Slide

  19. // add.js
    export function add(x, y) {
    return x + y; x * y;
    }

    View Slide

  20. View Slide

  21. Max Stoiber – @mxstbr – mxstbr.com

    View Slide

  22. View Slide

  23. Redux

    View Slide

  24. 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

    View Slide

  25. Actions

    View Slide

  26. // NavBar.actions.js
    export function toggleNav() {
    return { type: "TOGGLE_NAV" };
    }

    View Slide

  27. // NavBar.actions.test.js
    import { toggleNav } from './NavBar.actions';
    describe('NavBar actions', () => {
    });

    View Slide

  28. describe('NavBar actions', () => {
    describe('toggleNav', () => {
    it('should return the correct constant', () => {
    expect(toggleNav()).toEqual({
    type: "TOGGLE_NAV"
    });
    });
    });
    });

    View Slide

  29. describe('NavBar actions', () => {
    describe('toggleNav', () => {
    it('should return the correct constant', () => {
    expect(toggleNav()).toEqual({
    type: "TOGGLE_NAV"
    });
    });
    });
    });
    export function toggleNav() {
    return { type: "TOGGLE_NAV" };
    }

    View Slide

  30. describe('NavBar actions', () => {
    describe('toggleNav', () => {
    it('should return the correct constant', () => {
    expect(toggleNav()).toEqual({
    type: "TOGGLE_NAV"
    });
    });
    });
    });

    View Slide

  31. View Slide

  32. Reducers

    View Slide

  33. // NavBar.reducer.js
    const initialState = {
    open: false
    };
    export default function NavBarReducer(state = initialState, action) {
    switch (action.type) {
    case "TOGGLE_NAV":
    return {
    …state,
    open: !state.open
    };
    default:
    return state;
    }
    }

    View Slide

  34. // NavBar.reducer.js
    const initialState = {
    open: false
    };
    export default function NavBarReducer(state, action) {
    switch (action.type) {
    case "TOGGLE_NAV":
    return Object.assign({}, state, {
    open: !state.open
    });
    default:
    return state;
    }
    }

    View Slide

  35. 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
    });
    });
    });

    View Slide

  36. 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
    });
    });
    });

    View Slide

  37. 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
    });
    });
    });

    View Slide

  38. 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
    });
    });
    });

    View Slide

  39. View Slide

  40. Why Jest?

    View Slide

  41. 1. Performance
    2. Snapshot Testing
    3. Constant improvements

    View Slide

  42. Components

    View Slide

  43. const Button = (props) => (
    className="btn"
    onClick={props.onClick}
    >
    {props.children}

    );

    View Slide

  44. Jest Snapshot Testing

    View Slide

  45. // Button.test.js
    import React from 'react';
    import renderer from 'react-test-renderer';
    import Button from './Button.react';
    describe('', () => {
    it('should render a button with a classname', () => {});
    it('should attach an onclick handler passed in', () => {});
    it('should render its children', () => {});
    });

    View Slide

  46. // Button.test.js
    import React from 'react';
    import renderer from 'react-test-renderer';
    import Button from './Button.react';
    describe('', () => {
    it('should render a button with a classname', () => {});
    it('should attach an onclick handler passed in', () => {});
    it('should render its children', () => {});
    });
    const Button = (props) => (
    className="btn"
    onClick={props.onClick}
    >
    {props.children}

    );

    View Slide

  47. // Button.test.js
    describe('', () => {
    it('should render a button with a classname', () => {
    const tree = renderer.create(

    ).toJSON();
    expect(tree).toMatchSnapshot();
    });
    it('should attach an onclick handler passed in', () => {});
    it('should render its children', () => {});
    });

    View Slide

  48. // Button.test.js.snap
    exports[` should render a button with a classname 1`] = `
    className="btn"
    onClick={undefined} />
    `;

    View Slide

  49. // Button.test.js
    describe('', () => {
    it('should render a button with a classname', () => {});
    it('should attach an onclick handler passed in', () => {
    const tree = renderer.create(
    {}}>
    ).toJSON();
    expect(tree).toMatchSnapshot();
    });
    it('should render its children', () => {});
    });

    View Slide

  50. // Button.test.js
    describe('', () => {
    it('should render a button with a classname', () => {});
    it('should attach an onclick handler passed in', () => {
    const tree = renderer.create(
    {}}>
    ).toJSON();
    expect(tree).toMatchSnapshot();
    });
    it('should render its children', () => {});
    });

    View Slide

  51. exports[` should attach an onclick handler passed in 1`] = `
    className="btn"
    onClick={[Function]} />
    `;

    View Slide

  52. exports[` should attach an onclick handler passed in 1`] = `
    className="btn"
    onClick={[Function]} />
    `;

    View Slide

  53. // Button.test.js
    describe('', () => {
    it('should render a button with a classname', () => {});
    it('should attach an onclick handler passed in', () => {});
    it('should render its children', () => {
    const tree = renderer.create(
    Some text
    ).toJSON();
    expect(tree).toMatchSnapshot();
    });
    });

    View Slide

  54. // Button.test.js
    describe('', () => {
    it('should render a button with a classname', () => {});
    it('should attach an onclick handler passed in', () => {});
    it('should render its children', () => {
    const tree = renderer.create(
    Some text
    ).toJSON();
    expect(tree).toMatchSnapshot();
    });
    });

    View Slide

  55. exports[` should render its children 1`] = `
    className="btn"
    onClick={undefined}>
    Some text

    `;

    View Slide

  56. exports[` should render its children 1`] = `
    className="btn"
    onClick={undefined}>
    Some text

    `;

    View Slide

  57. Quickest Testing Ever

    View Slide

  58. Coverage

    View Slide

  59. View Slide

  60. View Slide

  61. Let’s do some testing!
    git checkout 6-testing
    npm install
    npm run test

    View Slide