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

Oh Snap!

Oh Snap!

Gaining leverage over legacy CLI apps with snapshot testing

Dan Miller

July 06, 2017
Tweet

More Decks by Dan Miller

Other Decks in Programming

Transcript

  1. Oh Snap!
    Gaining leverage over legacy CLI apps with snapshot testing

    Dan Miller
    Rogue Software Engineer
    @jazzdan
    https://dmiller.io

    View full-size slide

  2. @jazzdan
    Overview
    •What are snapshot tests?

    •How do you use them?

    •A tale from production!

    View full-size slide

  3. Who is this person?

    View full-size slide

  4. @jazzdan
    I love testing

    View full-size slide

  5. Snapshot Testing

    View full-size slide

  6. Code Produces Output

    View full-size slide

  7. @jazzdan
    Assert that the output
    doesn’t change

    View full-size slide

  8. Code Produces
    Output

    View full-size slide

  9. Code Produces
    Output

    View full-size slide

  10. @jazzdan
    Why is this especially
    useful for React?

    View full-size slide

  11. @jazzdan
    If the output changed,
    then your UI changed

    View full-size slide

  12. < A />
    < C />
    < D />

    View full-size slide

  13. < A />
    < C />
    < D />

    View full-size slide

  14. < A />
    < B /> < C />
    < D />
    < D />

    View full-size slide

  15. < A />
    < B /> < C />
    < D />
    < D />

    View full-size slide

  16. < A />
    < B /> < C />
    < D />
    < D />

    View full-size slide

  17. Code Produces Output

    View full-size slide

  18. JSX Renders to DOM

    View full-size slide

  19. JSX Renders to
    DOM

    View full-size slide

  20. JSX Renders to
    DOM
    Text!

    View full-size slide

  21. Code Produces
    Serializable
    Output

    View full-size slide

  22. @jazzdan
    Show me the code!

    View full-size slide

  23. 1 test("Link renders correctly", () => {
    2 const tree = renderer
    3 .create(
    4 Queens JS)
    5 .toJSON();
    6 expect(tree).toMatchSnapshot();
    7 });

    View full-size slide

  24. PASS ./Link.test.js
    ✓ renders correctly (15ms)
    Snapshot Summary
    › 1 snapshot written in 1 test suite.
    Test Suites: 1 passed, 1 total
    Tests: 1 passed, 1 total
    Snapshots: 1 added, 1 total
    Time: 0.287s
    Ran all test suites related to changed files.

    View full-size slide

  25. 1 exports[`Link renders correctly 1`] = `
    2 3 className="normal"
    4 href="http://queensjs.com"
    5 onClick={[Function bound _onClick]}>
    6 Queens JS
    7
    8 `;

    View full-size slide

  26. Non-React Uses

    View full-size slide

  27. @jazzdan
    We wrote a
    web application

    View full-size slide

  28. @jazzdan
    We wrote a
    web application
    text editor

    View full-size slide

  29. @jazzdan
    We wrote a
    web application
    text editor
    database

    View full-size slide

  30. @jazzdan
    We wrote a
    web application
    text editor
    database

    compiler

    View full-size slide

  31. App
    Changed daily
    JSON
    Generated quarterly

    View full-size slide

  32. Node CLI
    App
    JSON JSON
    PHP
    SQL

    View full-size slide

  33. Code Produces Output

    View full-size slide

  34. Node CLI
    App
    JSON JSON
    PHP
    SQL

    View full-size slide

  35. Node CLI
    App
    JSON
    PHP
    SQL

    View full-size slide

  36. Node CLI
    App
    JSON JSON
    PHP
    SQL

    View full-size slide

  37. Node CLI
    App
    JSON
    PHP
    SQL
    Intermediate
    Representation

    View full-size slide

  38. Node CLI
    App
    Intermediate
    Representation

    View full-size slide

  39. @jazzdan
    It’s OK if the test fails!

    View full-size slide

  40. @jazzdan
    Tests tell you about
    change in the
    behavior of your
    system
    not necessarily a bug

    View full-size slide

  41. @jazzdan
    Snapshot tests are
    great for detecting
    changes

    View full-size slide

  42. @jazzdan
    Example Uses
    •CLI help menus

    •Error messages

    •Emails

    •CSVs, SVGs, etc

    View full-size slide

  43. Integrating in to your
    test runner

    View full-size slide

  44. @jazzdan
    npm install jest-snapshot

    View full-size slide

  45. // ...
    const toMatchSnapshot = function(received: any, testName?: string) {
    this.dontThrow && this.dontThrow();
    const {currentTestName, isNot, snapshotState}: MatcherState = this;
    if (isNot) {
    throw new Error('Jest: `.not` cannot be used with
    `.toMatchSnapshot()`.');
    }
    if (!snapshotState) {
    throw new Error('Jest: snapshot state must be initialized.');
    }
    const result = snapshotState.match(
    testName || currentTestName || '',
    received,
    );

    View full-size slide

  46. class SnapshotState {
    _counters: Map;
    _dirty: boolean;
    _index: number;
    _updateSnapshot: SnapshotUpdateState;
    _snapshotData: {[key: string]: string};
    _snapshotPath: Path;
    _uncheckedKeys: Set;
    added: number;
    expand: boolean;
    matched: number;
    unmatched: number;
    updated: number;
    }

    View full-size slide

  47. Snapshots built-in

    View full-size slide

  48. @jazzdan
    Thanks!
    Find me over a if
    you love testing too!

    View full-size slide

  49. @jazzdan
    More Resources
    • https://www.selenic.com/blog/?p=663

    • https://glebbahmutov.com/blog/snapshot-testing/

    View full-size slide