$30 off During Our Annual Pro Sale. View Details »

Jest can do whaaat?

Robin Pokorny
November 01, 2017

Jest can do whaaat?

Jest is React’s best testing companion. It also brought several concepts to mainstream JavaScript testing: zero configuration, first-class mocking, and snapshots. With the rapid release of speed improvements, it’s easy to miss a new useful feature. I will present some lesser-known possibilities of recent Jest versions I’ve learned during experimenting, reading (and writing) the docs, and browsing the code.

Code: https://github.com/robinpokorny/jest-can-do-whaaat

Presented at React Open Source: https://www.meetup.com/preview/React-Open-Source/events/244027983

Resources:
- Example code: https://github.com/robinpokorny/jest-can-do-whaaat
- Jest Snapshots and Beyond (https://youtu.be/HAuXJVI_bUs) by Rogelio Guzman (recording)
- Writing snapshot plugins (https://github.com/facebook/jest/tree/master/packages/pretty-format#writing-plugins) in the docs
- Effective Snapshot Testing (https://blog.kentcdodds.com/effective-snapshot-testing-e0d1a2c28eca) by Kent C. Dodds
- Async testing in Jest (https://www.youtube.com/watch?v=bw10S2BK-5w) (recording)
- Snapshot testing in Jest (https://www.youtube.com/watch?v=yUlfFMhVfZo) (recording)
- Async testing Koa with Jest (https://hackernoon.com/async-testing-koa-with-jest-1b6e84521b71)

Robin Pokorny

November 01, 2017
Tweet

More Decks by Robin Pokorny

Other Decks in Technology

Transcript

  1. JEST
    can do
    whaaat?
    React Open Source Berlin
    1 November 2017
    @robinpokorny

    View Slide

  2. JEST
    can do
    whaaat?
    React Open Source Berlin
    1 November 2017
    @robinpokorny
    Slides accompany a talk.
    Here, the talk is missing.
    For the full experience

    see the recording.
    I welcome any feedback!
    INFO

    View Slide

  3. WHAT IS JEST
    delightful, zero configuration testing platform
    Jasmine’s and Expect’s successor
    practical utilities for awesome DX
    http:/
    /facebook.github.io/jest/

    View Slide

  4. SNAPSHOT TESTING

    View Slide

  5. {JSON} A

    View Slide

  6. {JSON}
    {JSON}
    A
    B

    View Slide

  7. {JSON}
    {JSON}
    A
    B
    !=
    !

    View Slide

  8. TEST
    describe('method', () => {
    test('works', () => {
    const full = {
    number: 1975,
    bool: true,
    string: 'Hello, Vanek',
    promise: Promise.resolve('Better job'),
    symbol: Symbol('brewery'),
    [Symbol.for(‘brewmaster')]: 'Next beer!',

    };
    expect(full).toMatchSnapshot();
    expect(1936).toMatchSnapshot();
    });
    });

    View Slide

  9. SNAPSHOT
    // Jest Snapshot v1, https: //goo.gl/fbAQLP
    exports[`method works 1`] = `
    Object {
    "bool": true,

    "undefined": undefined,
    Symbol(brewmaster): "Next beer!",
    }
    `;
    exports[`method works 2`] = `1936`;

    View Slide

  10. SNAPSHOT
    `
    Object {
    "bool": true,
    "func": [Function],
    "map": Map {
    "position1" => "workman",
    "position2" => "stockkeeper",
    },
    "null": null,
    "number": 1975,
    "promise": Promise {},

    View Slide

  11. SNAPSHOT
    "set": Set {
    "think",
    "write",
    "snitch",
    },
    "string": "Hello, Vanek",
    "symbol": Symbol(brewery),
    "undefined": undefined,
    Symbol(brewmaster): "Next beer!",
    }
    `

    View Slide

  12. TEST
    describe('method', () => {
    test('works', () => {
    const full = { … };
    expect(full).toMatchSnapshot('new name');
    });
    });
    SNAPSHOT
    exports[`new name 1`] = `…`

    View Slide

  13. TEST
    test('mock function', () => {
    const fn = jest.fn();
    fn('Vanek');
    fn('Ferdinand', 'Vanek');
    expect(fn).toHaveBeenCalledWith('Vanek');
    expect(fn).toHaveBeenCalledWith('Ferdinand', 'Vanek');
    expect(fn).toHaveBeenCalledTimes(2);
    // vs
    expect(fn.mock.calls).toMatchSnapshot();
    });

    View Slide

  14. SNAPSHOT
    exports[`method mock function 1`] = `
    Array [
    Array [
    "Vanek",
    ],
    Array [
    "Ferdinand",
    "Vanek",
    ],
    ]
    `;

    View Slide

  15. ?

    View Slide

  16. SNAPSHOT
    exports[`component with defaults`] = `
    style={
    Object {
    "backgroundColor": "black",
    "display": "flex",
    "flexDirection": “column",
    }
    }>


    View Slide

  17. TEST
    SNAPSHOT
    exports[`method immutable 1`] = `
    Immutable.Map {
    "a": 1,
    "b": 2,
    }
    `;
    expect(Immutable.Map({ a: 1, b: 2 })).toMatchSnapshot();

    View Slide

  18. const plugin = {
    test(val) {
    return val && val.isPlay;
    },
    serialize(val, config, indent, depth, refs, printer) {
    const name = val.constructor.name;
    const newIndent = indent + config.indent;
    return (
    `Play <${val.title}>: ` +
    printer(val.content, config, newIndent, depth ++, refs)
    );
    }
    };
    SERIALISER

    View Slide

  19. SERIALISER
    expect.addSnapshotSerializer(plugin);
    // package.json
    {
    ...
    "jest": {
    "snapshotSerializers": ["plugin.js"]
    }
    }
    or

    View Slide

  20. TEST
    test('play', () => {
    const play = {
    isPlay: true,
    title: 'Audience',
    content: { scenes: 1 }
    };
    expect([ play ]).toMatchSnapshot();
    });

    View Slide

  21. SNAPSHOT
    exports[`method play 1`] = `
    Array [
    Play : Object {
    "scenes": 1,
    },
    ]
    `;

    View Slide

  22. TEST
    test('diff', () => {
    const play = {
    title: 'Audience',
    characters: 2
    };
    expect(play).toMatchSnapshot();
    expect({ ...play, characters: 3 }).toMatchSnapshot();
    });

    View Slide

  23. SNAPSHOT
    exports[`diff 1`] = `
    Object {
    "characters": 2,
    "title": "Audience",
    }
    `;
    exports[`diff 2`] = `
    Object {
    "characters": 3,
    "title": "Audience",
    }
    `;

    View Slide

  24. const { toMatchDiffSnapshot } = require('snapshot-diff');
    expect.extend({ toMatchDiffSnapshot });
    test('diff', () => {
    const play = {
    title: 'Audience',
    characters: 2
    };
    expect(play)
    .toMatchDiffSnapshot({ ...play, characters: 3 });
    });

    View Slide

  25. SNAPSHOT
    exports[`diff 1`] = `
    "Snapshot Diff:
    - First value
    + Second value
    Object {
    - \\"characters \\": 2,
    + \\"characters \\": 3,
    \\"title \\": \\"Audience \\",
    }"
    `;

    View Slide

  26. structures
    concurrent or after
    whole
    algorithms
    write before
    part
    TDD SNAPSHOTS

    inside codebase

    View Slide

  27. watch

    View Slide

  28. $ jest --watch
    $ npm test -- --watch

    View Slide

  29. understands dependencies
    filter by Path or Test name
    Update snapshots
    failed re-run first

    View Slide

  30. // moduleA.spec.js
    const moduleA = require('./moduleA');
    test('moduleA', () => {
    expect(moduleA()).toBe(true);
    });
    // moduleA.js
    const moduleB = require('./moduleB');
    DEPS

    View Slide

  31. View Slide

  32. View Slide

  33. in JEST
    ASYNC testing

    View Slide

  34. test('promise', done => {
    Promise.resolve(7)
    .then(n => {
    expect(n).toBe(7);
    })
    .then(done)
    .catch(done.fail);
    });
    CALLBACK

    View Slide

  35. PROMISES
    test('promises', () => {
    Promise.resolve(8).then(n => {
    expect(n).toBe(7);
    });
    return Promise.resolve(7).then(n => {
    expect(n).toBe(7);
    });
    });

    View Slide

  36. View Slide

  37. View Slide

  38. REJECTION
    test('reject', () => {
    return Promise.reject(0).catch(n => {
    expect(n).toBe(0);
    });
    });

    View Slide

  39. REJECTION
    test('reject', () => {
    return Promise.reject(0).catch(n => {
    expect(n).toBe(0);
    });
    });
    test('reject', () => {
    return Promise.resolve(7).catch(n => {
    expect(n).toBe(0);
    });
    });

    View Slide

  40. REJECTION
    test('reject', () => {
    expect.assertions(1);
    return Promise.resolve(7)
    .then(() => {
    throw new Error('Not rejected!');
    })
    .catch(n => {
    expect(n).toBe(0);
    });
    });

    View Slide

  41. View Slide

  42. ASYNC

    AWAIT
    test('async', async () => {
    const n = await Promise.resolve(7)
    const m = await Promise.resolve(42)
    expect(n).toBe(7)
    expect(m).toBe(42)
    })

    View Slide

  43. ASYNC

    AWAIT
    test('async', async () => {
    const n = Promise.resolve(7)
    const m = await Promise.resolve(42)
    expect(n).toBe(7)
    expect(m).toBe(42)
    })

    View Slide

  44. View Slide

  45. ASYNC
    REJECTION
    test('async rejection', async () => {
    try {
    await Promise.reject(0);
    } catch (e) {
    expect(e).toBe(0);
    }
    });

    View Slide

  46. ASYNC
    REJECTION
    test('async rejection', async () => {
    try {
    await Promise.resolve(7);
    } catch (e) {
    expect(e).toBe(0);
    }
    });

    View Slide

  47. ASYNC
    REJECTION
    test('async rejection', async () => {
    try {
    await Promise.resolve(0);
    expect(true).toBe(false);
    } catch (e) {
    expect(e).toBe(0);
    }
    });

    View Slide

  48. .RESOLVES

    & .REJECTS
    test('resolves/rejects', async () => {
    await expect(Promise.resolve(7)).resolves.toBe(7);
    await expect(Promise.reject(0)).rejects.not.toBe(7);
    });

    View Slide

  49. View Slide

  50. JEST
    can do
    whaaat?
    will do

    View Slide

  51. MOCK
    NAME
    test('mockName', () => {
    const mockFn = jest.fn();
    expect(mockFn).toHaveBeenCalled();
    });

    View Slide

  52. View Slide

  53. MOCK
    NAME
    test('mockName', () => {
    const mockFn = jest.fn();
    expect(mockFn).toHaveBeenCalled();
    });
    test('mockName', () => {
    const mockFn = jest.fn().mockName('mockedFunction');
    expect(mockFn).toHaveBeenCalled();
    });

    View Slide

  54. GIF not supported in PDF
    INFO

    View Slide

  55. $ jest packages/moduleA
    $ jest packages/moduleA --passWithNoTests

    View Slide

  56. by @kentcdodds
    GIF not supported in PDF
    INFO

    View Slide

  57. RELATED
    • github.com/robinpokorny/jest-can-do-whaaat
    • Jest Snapshots and Beyond by Rogelio Guzman (recording)
    • Writing snapshot plugins in the docs
    • Effective Snapshot Testing by Kent C. Dodds
    • Async testing in Jest (recording)
    • Snapshot testing in Jest (recording)
    • Async testing Koa with Jest
    Full links in the description
    INFO

    View Slide

  58. JEST
    can do
    whaaat?
    @robinpokorny
    Help others to go

    View Slide