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 full-size slide

  2. Which types of testing are there?

    View full-size slide

  3. Unit Testing

    View full-size slide

  4. Function
    Components
    Actions
    Reducers

    View full-size slide

  5. Why should you test?

    View full-size slide

  6. Catch some bugs before they
    happen

    View full-size slide

  7. Executable Documentation

    View full-size slide

  8. Write Better Code

    View full-size slide

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

    View full-size slide

  10. // 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 full-size slide

  11. // 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 full-size 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 full-size 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 full-size 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 full-size slide

  15. Max Stoiber – @mxstbr – mxstbr.com

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. Max Stoiber – @mxstbr – mxstbr.com

    View full-size slide

  19. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  23. 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 full-size slide

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

    View full-size slide

  25. // 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 full-size slide

  26. // 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 full-size slide

  27. 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 full-size slide

  28. 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 full-size slide

  29. 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 full-size slide

  30. 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 full-size slide

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

    View full-size slide

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

    );

    View full-size slide

  33. Jest Snapshot Testing

    View full-size slide

  34. // 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 full-size slide

  35. // 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 full-size slide

  36. // 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 full-size slide

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

    View full-size slide

  38. // 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 full-size slide

  39. // 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  42. // 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 full-size slide

  43. // 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 full-size slide

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

    `;

    View full-size slide

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

    `;

    View full-size slide

  46. Quickest Testing Ever

    View full-size slide

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

    View full-size slide