Step 2.4
Testing TypeScript code with jest. jest is a test framework made by Facebook and is very popular in the React and the wider JS ecosystem. We will work on implementing simple unit tests here in this exercise.
jest Features
- Multi-threaded and isolated test runner
- Provides a "fake" browser environment if needed (window, document, DOM, etc).
- Snapshots: show API or large object changes along side code changes in pull requests
- Code coverage is integrated (--coverage)
- Very clear error messages of where the test failures occur
- By default, will simulate a "good enough" browser environment called JSDOM
How to use jest
- using
create-react-appor other project generators, jest should already be preconfigured. Runnpm testusually will trigger it! - needs
jest.config.js jsdommight not have enough API from real browsers, for those cases, polyfills are required. Place these insidejest.setup.jsand hook up the setup file injest.config.js- in order to use
enzymelibrary to test React Components, more config bits are needed insidejest.setup.js
What does a test look like?
// describe(), it() and expect() are globally exported, so they don't need to be imported when jest runs these tests
describe('Something to be tested', () => {
it('should describe the behavior', () => {
expect(true).toBe(true);
});
});
Test React Components by using enzyme
- use
enzymetomount()the component (as oppose to rendering) - the
mount()function will return a wrapper that can be inspected - the wrapper has functionality like
find(), simulating clicks, etc.
import React from 'react';
import { mount } from 'enzyme';
import { TestMe } from './TestMe';
describe('TestMe Component', () => {
it('should have a non-clickable component when the origina InnerMe is clicked', () => {
const wrapper = mount(<TestMe name="world" />);
wrapper.find('#innerMe').simulate('click');
expect(wrapper.find('#innerMe').text()).toBe('Clicked');
});
});
Advanced Topics
Mocking
Mocking functions is a large part of what makes jest a powerful testing library. jest actually intercepts module inclusion process in node.js allowing it to mock entire modules if needed. There are many ways to mock as you can imagine in a language as flexible as JS. We only look at the simplest case but there's a lot of depth here.
To mock a function:
it('some test function', () => {
const mockCallback = jest.fn(x => 42 + x);
mockCallback(1);
mockCallback(2);
expect(mockCallback.mock.calls.length).toBe(2);
});
Read more about jest mocking here: https://jestjs.io/docs/en/mock-functions.html
Async Testing
callback
it('tests callback functions', (done) => {
someFunctionThatCallsDone(done));
})
promise
it('tests promise functions', () => {
return someFunctionThatReturnsPromise());
})
(recommended) async / await
it('tests async functions', async () => {
expect(await someFunction()).toBe(5);
});
Demo
jest basics
In this repo, we can start an inner loop development of tests with the command: npm test
Take a look at code inside demo/src:
-
index.tsis exports a few functions for a counter as well as a test for squaring numbers but demonstrates out jest uses mocks -
multiply.tsis a contrived example of a function that is exported -
index.spec.tsis the test file: note how tests are re-run on save to test file changes as well as source code changes undersrc
testing React applications
You can also test React Components with jest with the help of a partner library called enzyme. Take a look at the test below:
import { mount } from 'enzyme';
describe('Foo Component Tests', () => {
it('allows us to set props', () => {
const wrapper = mount(<Foo bar="baz" />);
expect(wrapper.props().bar).toBe('baz');
wrapper.setProps({ bar: 'foo' });
expect(wrapper.props().bar).toBe('foo');
});
});
mount does a full mount of the component. You can use the enzyme wrapper to simulate clicks, etc.:
wrapper.find('button').simulate('click');
Exercise
Basic Testing
-
Run the tests by running
npm testat the root of the bootcamp project -
Look at the
stack.tsfor a sample implementation of a stack -
Follow the instructions inside the
stack.spec.tsfile to complete the two tests
Enzyme Testing
-
Open up
exercise/src/TestMe.spec.tsx -
Fill in the blank for the missing test using
enzymeconcepts introduced from the demo -
Run tests with
npm test