johnny-dreamguns
10/7/2019 - 10:10 PM

Testing React Applications with Jest

Testing React Applications with Jest

A regression is step backwards to a less developed state

Regression testing is checking that the new features haven’t broken the existing features

Test files are committed alongside the app code

Without tests:

  • Have to test every single page works feature by feature
  • Manually testing becomes very expensive

Advantages to testing:

  • Prevents regression
  • Reduces manual regressions
  • Verify obscure data input tests
  • Allows developers to focus on current tasks

Disadvantages:

  • More code to write
  • More tools to learn
  • Additional dependencies to the application
  • Tests that work on local machine may not work on continuous integration machine
  • Have to use tests correctly for them to be of value

Unit Test:

  • Tests a single function or service
  • Test runner required

Component Test:

  • Tests an individual part of an application, e.g. a dropdown
  • Verifies the correct appearance of a component
  • Strong defence against regression
  • Verifies change to component output in response to change in state
  • Doesn’t verify interactions between components

Snapshot Test:

  • Just protects a component from regressing
  • Subtype of component test
  • Automatically generated by Jest
  • Verifies output matches a past record

End to end Test:

  • End user testing
  • Measures functionality of the whole system, imitating user clicks
  • Runs in a Headless browser
  • Best assurance that the app works

Performance Test:

  • How long a block of code takes to execute
  • Can identify bottlenecks in performance
  • Difference in performance between different devices

Coverage:

  • How much of codebase is covered by tests

Jest

  • Test runner
  • Installed by npm
  • Made by React team Expect
  • Optional assertion library that can be plugged into Jest

Enzyme

  • Works with Jest
  • Not a test runner
  • Has tools to test React components
  • Takes component Dom tree HTML so you can check structure

Jasmine/Mocha

  • Jest is built on top of Jasmine/Mocha
  • Jest adds mocking and snapshot testing
  • Superior assertion library

Jest vs Mocha

  • Both run tests, check if all tests pass or not
  • Both can run Asynchronous tests
  • Jest includes spies as default
  • Jest includes snapshot testing
  • Jest includes module mocking

Jest vs Jest CLI

  • Jest is the test runner
  • Jest CLI is a tool you use to configure Jest

NPM Scripts control Jest using commands such as test, test-watch, test-e2e test-update, test-prod

Tests are ‘run’ by CI, devs use ‘Watch’

Creating an npm script ‘test’ is what will run by the CI

Jest looks for directory with name tests

Jest looks for files with suffixes *.test.js or *.spec.js

Tests in own folder: Easy to distinguish what is testing and what is the app code

Tests amongst the code: Can’t name test files whatever you like Possible to isolate tests based on name

Test block, common to use ‘It should … ‘

Watch mode watches for changes in files

BeforeAll runs a block of code before all it statements

BeforeEach runs a block of code before each it statements

AfterEach runs after each it statement

AfterAll runs after all it statements

.skip ignores a test

.only skips the other tests in a file

Async testing: Invoke the done callback passed to the test Return a promise from a test Pass an async function to describe

Mocking: Reduce dependencies, so faster execution Prevent side effects during testing Mock specific data required for a test

Mocks: Duplicate of an object with no internal workings Can be automatically or manually created Same API as original but no side effects Can also add more advanced features as spies

Mocks have all the same methods as the original object Any method that returns a promise will still do so Complex values returned by a method have to be mocked too

Mock functions: Are also known as spies Calling the mocked function has no side effects Number of calls is recorded Can check which arguments were passed in Can load mock function with return values Return value from mock function will approximate original

Mocks files must reside in a directory mocks in the folder of the mocked module NPM modules and local modules can be mocked

Snapshot testing is used to catch regression. They are easy to use but also too easy to ignore

Testing React Components:

  • verify output has not regressed
  • Ensure rare corner cases work
  • Ensure side effects occur but don’t execute them
  • Verify user interactions are handled

Components may or may not

  • Have lifecycle methods
  • Have internal state
  • Generate side effects (api calls etc)

Most testable components have:

  • No internal state
  • No side effects, best to use sagas or thunks for this
  • No lifecycle hooks

Redux and Jest:

  • Components don’t generate side effects
  • Connect component limits us to dispatching actions
  • Actions on their own don’t do anything until caught by a thunk or a reducer or a saga or middleware
  • Presentation components are handled by snapshots
  • Container components can be isolated as the actions they dispatch don’t do anything
  • React redux components don’t have internal state

Testing Container Components:

  • Unit tests verify container
  • Test container successfully maps state to props
  • Testing that interactions trigger actions

Testing presentation components:

  • Use snapshots

React Test Renderer

  • Takes React component and outputs the resulting HTML without Dom
  • Useful for getting output HTML for snapshot testing

Enzyme

  • also outputs HTML without Dom
  • Also allows you to test clicks, keyboard input etc

Mocks not needed for React Redux components

Testing Stateful React components:

  • Mock dependencies
  • Use spies to verify side effects eg api calls
  • Mock call to API and check how it was called to check it works ok
  • Check side effects are happening without them happening
  • Move logic from lifecycle methods to services
  • Prevent regression using snapshots
  • Inject values by writing mocks for services
  • Make stateless components