Using Jest with TypeScript
August 8, 2018 ยท View on GitHub
No testing solution out there is perfect. That said, jest is an excellent unit testing option which provides great TypeScript support.
Note: We assume you start off with a simple node package.json setup. Also all TypeScript files should be in a
srcfolder which is always recommended (even without Jest) for a clean project setup.
Step 1: Install
Install the following using npm:
npm i jest @types/jest ts-jest -D
Explanation:
- Install
jestframework (jest) - Install the types for
jest(@types/jest) - Install the TypeScript preprocessor for jest (
ts-jest) which allows jest to transpile TypeScript on the fly and have source-map support built in. - Save all of these to your dev dependencies (testing is almost always a npm dev-dependency)
Step 2: Configure Jest
Add the following jest.config.js file to the root of your project:
module.exports = {
"roots": [
"<rootDir>/src"
],
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
}
Explanation:
- We always recommend having all TypeScript files in a
srcfolder in your project. We assume this is true and specify this using therootsoption. - The
transformconfig just tellsjestto usets-jestfor ts / tsx files. - The
testRegextells Jest to look for tests in any__tests__folder AND also any files anywhere that use the(.test|.spec).(ts|tsx)extension e.g.asdf.test.tsxetc. - The
moduleFileExtensionstells jest to recognize our file extensions. This is needed as we addts/tsxinto the defaults (js|jsx|json|node).
Step 3: Run tests
Run npx jest from your project root and jest will execute any tests you have.
Optional: Add script target for npm scripts
Add package.json:
{
"test": "jest"
}
- This allows you to run the tests with a simple
npm t. - And even in watch mode with
npm t -- --watch.
Optional: Run jest in watch mode
npx jest --watch
Example
- For a file
foo.ts:
export const sum
= (...a: number[]) =>
a.reduce((acc, val) => acc + val, 0);
- A simple
foo.test.ts:
import { sum } from '../';
test('basic', () => {
expect(sum()).toBe(0);
});
test('basic again', () => {
expect(sum(1, 2)).toBe(3);
});
Notes:
- Jest provides the global
testfunction. - Jest comes prebuilt with assertions in the form of the global
expect.
Example async
Jest has built-in async/await support. e.g.
test('basic',async () => {
expect(sum()).toBe(0);
});
test('basic again', async () => {
expect(sum(1, 2)).toBe(3);
}, 1000 /* optional timeout */);
Example enzyme
Enzyme allows you to test react components with dom support. There are three steps to setting up enzyme:
- Install enzyme, types for enzyme, a better snapshot serializer for enzyme, enzyme-adapter-react for your react version
npm i enzyme @types/enzyme enzyme-to-json enzyme-adapter-react-16 -D - Add
"snapshotSerializers"and"setupTestFrameworkScriptFile"to yourjest.config.js:
module.exports = {
// OTHER PORTIONS AS MENTIONED BEFORE
// Setup Enzyme
"snapshotSerializers": ["enzyme-to-json/serializer"],
"setupTestFrameworkScriptFile": "<rootDir>/src/setupEnzyme.ts",
}
- Create
src/setupEnzyme.tsfile.
import { configure } from 'enzyme';
import * as EnzymeAdapter from 'enzyme-adapter-react-16';
configure({ adapter: new EnzymeAdapter() });
Now here is an example react component and test:
checkboxWithLabel.tsx:
import * as React from 'react';
export class CheckboxWithLabel extends React.Component<{
labelOn: string,
labelOff: string
}, {
isChecked: boolean
}> {
constructor(props) {
super(props);
this.state = { isChecked: false };
}
onChange = () => {
this.setState({ isChecked: !this.state.isChecked });
}
render() {
return (
<label>
<input
type="checkbox"
checked={this.state.isChecked}
onChange={this.onChange}
/>
{this.state.isChecked ? this.props.labelOn : this.props.labelOff}
</label>
);
}
}
checkboxWithLabel.test.tsx:
import * as React from 'react';
import { shallow } from 'enzyme';
import { CheckboxWithLabel } from './checkboxWithLabel';
test('CheckboxWithLabel changes the text after click', () => {
const checkbox = shallow(<CheckboxWithLabel labelOn="On" labelOff="Off" />);
// Interaction demo
expect(checkbox.text()).toEqual('Off');
checkbox.find('input').simulate('change');
expect(checkbox.text()).toEqual('On');
// Snapshot demo
expect(checkbox).toMatchSnapshot();
});
Reasons why we like jest
- Built-in assertion library.
- Great TypeScript support.
- Very reliable test watcher.
- Snapshot testing.
- Built-in coverage reports.
- Built-in async/await support.