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

Easy JavaScript Testing with Jest

Greg Jopa
September 20, 2017

Easy JavaScript Testing with Jest

Jest is a JavaScript testing framework that makes it easy to test Node.js apps. It provides a zero-configuration experience and embraces global functions so developers can write less boilerplate and more tests.

Greg Jopa

September 20, 2017
Tweet

More Decks by Greg Jopa

Other Decks in Technology

Transcript

  1. About me I’m Greg Jopa - Software Engineering Manager at

    Cars.com - Previously at YP in Los Angeles - github.com/gregjopa
  2. About this talk - Review how to write testable Node.js

    code - Learn more about Jest and how it makes testing easier - This talk is focused on testing server-side JavaScript - Ask questions anytime
  3. Testing Demo App https://github.com/gregjopa/express-app-testing-demo - Node.js >=6.11.x - Express -

    web app framework - Got - simplified http requests - ejs - templating
  4. Testing Demo App - 2014 vs 2017 2014 2017 Node

    version 0.10.x 6.11.x Test Runner Mocha Jest Assertion library Should.js Jest Mocking Nock Jest Code Coverage Istanbul Jest*
  5. App Design - User Input Flickr Photo Feed Node.js Web

    Server End User form input http request - validate user input - search for photos
  6. App Design - API Response Flickr Photo Feed Node.js Web

    Server End User html content api response - validate response - transform photo data - return html
  7. Testing Strategy - Write tests to build confidence - Test

    in isolation - Need code that’s testable - 1 file does 1 thing and owns it - Sensible interface
  8. Unit tests Arrange, Act, Assert test('should return false for search

    term containing numbers', () => { const tags = 'dogs123'; expect(formValidator.isValidCommaDelimitedList(tags)).toBe(false); });
  9. Integration tests Combine units and test as a group -

    route tests test('should respond with a 200 with valid query parameters', () => { return request(app) .get('/?tags=california&tagmode=all') .expect('Content-Type', /html/) .expect(200) .then(response => { expect(response.text).toMatch( /<div class="panel panel-default search-results">/ ); }); });
  10. Functional tests Testing services outside your codebase describe('flickr public feed

    api', () => { test('should return expected json format', () => { const apiTest = new API({ tags: 'california', tagmode: 'all' }); return got(apiTest).then(response => { expect(response.statusCode).toBe(200);
  11. Writing Testable Node.js code - Separate app functionality from web

    framework - Folder structure - keep test files close - Use module.exports to expose an interface that’s testable
  12. Testable code - module.exports Export an object function isValidCommaDelimitedList(value) {

    } function isValidTagmode(value) { } function hasValidFlickrAPIParams(tags, tagmode) { } module.exports = { isValidCommaDelimitedList, isValidTagmode, hasValidFlickrAPIParams };
  13. Testable code - module.exports Export a function function helper(value) {

    } // functions can have properties too! helper.getInfo = function () { } module.exports = helper;
  14. What is Jest? Jest is a complete and easy to

    set up JavaScript testing solution - Not just for React! - Ready to use tooling (assertions, mocks, coverage) - Fast test runner
  15. Jest - Easy setup - Globals similar to mocha (describe(),

    beforeEach(), afterEach()) - Includes assertion library - expect() - Includes code coverage
  16. Jest - Globals // eslintrc "globals": { "jest": false, "expect":

    false, "describe": false, "test": false, "before": false, "beforeEach": false, "after": false, "afterEach": false },
  17. Jest - Config options // package.json { "scripts": { "start":

    "nodemon app/server.js", "test": "jest --coverage app/__tests__/*.test.js", "test:e2e": "jest --runInBand e2e_tests/*.test.js" }, "jest": { "testEnvironment": "node", "verbose": true } }
  18. Jest is Fast Runs tests in parallel - Cluster of

    Node processes - Uses worker-farm module - Drawback - tests run in different order each time Can be disabled with “jest --runInBand” option
  19. Jest assertion library expect() has “matchers” for validating things -

    resolves() - expect(Promise.resolve('lemon')).resolves.toBe('lemon') - toMatch() - expect(text).toMatch(/<div class="alert alert-danger">/) - toHaveBeenCalledTimes() - expect(helperMock).toHaveBeenCalledTimes(2)
  20. Migrating existing tests to Jest Jest-codemods - Search and replace

    on steroids - Not perfect - still requires manual intervention - Supports migrating from Mocha, Jasmine, Tape, Chai, Should.js
  21. Jest - Mocks - Mock Functions - jest.fn() - Keeps

    track of how many times the function was called - Inject test values - myMock.mockReturnValueOnce(true) - Manual Mocks - override module dependencies
  22. Jest - Mock Function example test('should error when api returns

    500 http status code', () => { // mock the flickr public feed api endpoint and return a 500 error jest.doMock('got', () => { return jest.fn(() => { return Promise.reject('Response code 500 (Internal Server Error)'); }); }); photoModel = require('../../app/photo_model'); return photoModel.getFlickrPhotos('california', 'all').catch(error => { expect(error.toString()).toMatch(/Response code 500/); }); });
  23. Jest - Manual Mock for photo_model.js function getFlickrPhotos(tags) { return

    Promise.resolve([ { title: 'Point Lobos sunset', link: 'http://www.flickr.com/photos/nathanleefer/24437997081/', // more data ... } ]); } module.exports = { getFlickrPhotos };
  24. Jest - Manual Mock example jest.mock('../../app/photo_model'); const app = require('../../app/server');

    describe('index route', () => { afterEach(() => { app.server.close(); }); test('should respond with a 200 with no query parameters', () => { return request(app) .get('/') .expect('Content-Type', /html/) .expect(200)
  25. Jest is strict - Jest won’t exit if resources are

    still being held on to - ex: web server - Mocha does not do this - Jest provides an escape-hatch with --forceExit option
  26. Summary - Jest comes with ready-to-use tools - expect -

    mocking - code coverage - Makes testing easier since you can use one tool - One website for documentation - Cleaner scripts in package.json - Less boilerplate - Jest isn’t for everyone - Uses magic for a better developer experience