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

Painless Testing

Painless Testing

Testing UIs has always been a hard job. In the components era, there are new tools available that transform completely the way we approach testing. One of the hottest is Jest, and we'll see how it provides an all-in-one testing solution that saves us time and headache.

Michele Bertoli

February 09, 2017
Tweet

More Decks by Michele Bertoli

Other Decks in Programming

Transcript

  1. Painless Testing
    @MicheleBertoli

    View full-size slide

  2. Mee-KeH-LeH
    Front End Engineer at Facebook
    Author of React Design Patterns and Best Practices
    Follow me @MicheleBertoli

    View full-size slide

  3. “I'm upgrading a pretty big
    codebase from Jest 0.8.2 to 15.1.1.
    Call me a hero.”
    — Michele Bertoli, Sep 2016

    View full-size slide

  4. “Saddest thing I hear from
    engineers: we aren't writing tests
    right now because we're focusing
    on building features”
    — Dmitrii Abramov, Feb 2017

    View full-size slide

  5. ● Time consuming
    ● Complex to setup and maintain
    ● Browser tests are slow
    ● False negatives
    Testing is hard

    View full-size slide

  6. ● Catch some bugs
    ● Confidence (Move fast™)
    ● Refactoring
    ● Documentation
    Testing is important

    View full-size slide

  7. “Unpopular opinion: component
    unit testing is overrated.”
    — Dan Abramov, Jul 2016

    View full-size slide

  8. “Write tests. Not too many. Mostly
    integration.”
    — Guillermo Rauch, Dec 2016

    View full-size slide

  9. Mike Cohn, Nov 2009

    View full-size slide

  10. Dmitrii Abramov, Dec 2016

    View full-size slide

  11. ● Focus on DX
    ● Works out of the box
    ● Complete product
    ● Used by Facebook
    overview

    View full-size slide

  12. ● Interactive mode
    ● Automatically find tests related to changed files
    ● Run tests in parallel processes
    ● Sandboxed test files and automatic state resets
    FAST

    View full-size slide

  13. ● Create coverage reports
    ● Run your tests within a fake DOM implementation
    ● Integrated manual mocking library
    ALL-IN-ONE

    View full-size slide

  14. ● Error messages are helpful and color coded
    ● Stack traces point to the source of problems
    ● Jest runs previously failed tests first
    ERRORS

    View full-size slide

  15. ● Jest works with any compile-to-JS language
    ● Integrates seamlessly with Babel
    ● TypeScript through ts-jest
    Integrations

    View full-size slide

  16. ● Integrated support for promises and async/await
    ● Can run asynchronous code synchronously
    ASYNC

    View full-size slide

  17. npm install --save-dev jest
    yarn add --dev jest
    // package.json
    "scripts": {
    "test": "jest"
    }
    Getting Started

    View full-size slide

  18. yarn add --dev babel-jest babel-preset-es2015
    // .babelrc
    {
    "presets": ["es2015"]
    }
    Modern javascript

    View full-size slide

  19. ● automock
    ● bail
    ● collectCoverage
    ● notify
    ● testEnvironment
    ● timers
    And many more.
    configuration

    View full-size slide

  20. Writing tests

    View full-size slide

  21. test('Hello, Jest!', () => {
    expect(true).toBe(true)
    })

    View full-size slide

  22. test(name, fn)
    test.only(name, fn)
    describe(name, fn)
    describe.only(name, fn)
    Globals

    View full-size slide

  23. afterAll(fn)
    afterEach(fn)
    beforeAll(fn)
    beforeEach(fn)
    Setup and teardown

    View full-size slide

  24. .toBe(value)
    .toEqual(value)
    .toBeDefined()
    .toBeInstanceOf(Class)
    .toHaveLength(number)
    .toThrow(error)
    expect

    View full-size slide

  25. expect.extend({
    toBeFoo(received) {
    return { pass: received === 'foo' }
    }
    })
    test('foo is foo', () => expect('foo').toBeFoo())
    Custom matchers

    View full-size slide

  26. Partial objects
    test('partial objects', () => {
    const obj = { foo: 'bar', baz: Math.random() }
    expect(obj).toEqual(
    expect.objectContaining({ foo: 'bar' })
    )
    })

    View full-size slide

  27. asymmetric matchers
    test('asymmetric matchers', () => {
    const obj = { foo: 'bar', baz: Math.random() }
    expect(obj).toEqual(
    expect.objectContaining({
    foo: 'bar', baz: expect.any(Number),
    })
    )
    })

    View full-size slide

  28. test('works with promises', () => {
    return getUserName(4).then(
    userName => expect(userName).toEqual('Mark')
    )
    })
    promises

    View full-size slide

  29. test('works with async/await', async () => {
    const userName = await getUserName(4)
    expect(userName).toEqual('Mark')
    })
    Async / await

    View full-size slide

  30. test('spies', () => {
    const spy = jest.fn()
    spy()
    expect(spy).toHaveBeenCalled()
    })
    SPIES

    View full-size slide

  31. MOCK FUNCTIONS
    test('mock functions', () => {
    const mock = jest.fn(() => 'foo')
    expect(mock()).toBe('foo')
    })

    View full-size slide

  32. // __mocks__/path.js
    export default { sep: ':' }
    // spec
    import path from 'path'
    jest.mock('path')
    test('mock path', () => expect(path.sep).toBe(':'))
    Manual mocks

    View full-size slide

  33. const spy = jest.fn()
    const debounced = debounce(spy, 1000)
    debounced('foo')
    example

    View full-size slide

  34. test('timer functions', () => {
    jest.runTimersToTime(999)
    expect(spy).not.toHaveBeenCalled()
    jest.runTimersToTime(1)
    expect(spy).toHaveBeenCalledWith('foo')
    })
    timer FUNCTIONS

    View full-size slide

  35. snapshots
    Capture snapshots of React trees or other serializable
    values to simplify UI testing and to analyze how state
    changes over time.

    View full-size slide

  36. example
    const Button = ({ disabled, text, primary }) => (
    className={
    primary ? 'btn--primary' : 'btn--secondary'
    }
    disabled={disabled}
    >{text}
    )

    View full-size slide

  37. enzyme
    test('enzyme', () => {
    const wrapper = shallow(

    )
    expect(wrapper.prop('disabled')).toBe(true)
    expect(wrapper.hasClass('btn--primary')).toBe(true)
    expect(wrapper.text()).toBe('Click me!')
    })

    View full-size slide

  38. Test renderer
    test('test-renderer', () => {
    const tree = renderer.create(

    ).toJSON()
    expect(tree).toMatchSnapshot()
    })

    View full-size slide

  39. Human-readable
    exports[`test test-renderer 1`] = `
    className="btn--primary"
    disabled={true}>
    Click me!

    `;

    View full-size slide

  40. update
    @@ -1,5 +1,5 @@
    - className="btn--primary"
    + className="button--primary"
    disabled={true}>
    Click me!

    View full-size slide

  41. watch
    Watch Usage
    › Press a to run all tests.
    › Press o to only run tests related to changed files.
    › Press u to update failing snapshots.
    › Press p to filter by a filename regex pattern.
    › Press q to quit watch mode.
    › Press Enter to trigger a test run.

    View full-size slide

  42. enzyme-to-json
    Convert Enzyme wrappers to a format compatible with
    Jest snapshot testing.
    adriantoine/enzyme-to-json

    View full-size slide

  43. example
    test('enzyme-to-json', () => {
    const wrapper = shallow(

    )
    expect(toJson(wrapper)).toMatchSnapshot()
    })

    View full-size slide

  44. CSS MODULES
    {
    "jest": {
    "moduleNameMapper": {
    "\\.css$": "identity-obj-proxy"
    }
    }
    }

    View full-size slide

  45. resolve.root
    {
    "jest": {
    "modulePaths": [
    "/shared/vendor/modules"
    ]
    }
    }

    View full-size slide

  46. Migrating to jest

    View full-size slide

  47. codemods
    Codemods that simplify migrating JavaScript test files
    from Mocha, Tape and AVA to Jest.
    skovhus/jest-codemods

    View full-size slide

  48. Next steps
    Follow @fbjest
    Stars are welcome facebook/jest

    View full-size slide

  49. One more thing

    View full-size slide

  50. “The best testing strategy is not
    writing tests.”
    — Michele Bertoli, Dec 2016

    View full-size slide

  51. snapguidist
    Snapshot testing for React Styleguidist.
    MicheleBertoli/snapguidist

    View full-size slide

  52. Jest packages
    ● jest-haste-map
    ● jest-snapshots
    And many more.

    View full-size slide

  53. react-fix-it
    Automagically generate tests from errors.
    MicheleBertoli/react-fix-it

    View full-size slide

  54. Any question?

    View full-size slide