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
src
folder which is always recommended (even without Jest) for a clean project setup.
Install the following using npm:
npm i jest @types/jest ts-jest typescript -D
Explanation:
Install jest
framework (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.
Install the TypeScript compiler ('typescript') which is prerequisite for 'ts-jest'.
Save all of these to your dev dependencies (testing is almost always a npm dev-dependency)
Add the following jest.config.js
file to the root of your project:
module.exports = {"roots": ["<rootDir>/src"],"testMatch": ["**/__tests__/**/*.+(ts|tsx|js)","**/?(*.)+(spec|test).+(ts|tsx|js)"],"transform": {"^.+\\.(ts|tsx)$": "ts-jest"},}
(If your package.json
file contains "type": "module"
, which causes Node to assume modules are in es6 format, you can convert the above to es6 format by replacing the top line to export default {
.)
Explanation:
We always recommend having all TypeScript files in a src
folder in your project. We assume this is true and specify this using the roots
option.
The testMatch
config is a glob pattern matcher for discovering .test / .spec files in ts / tsx / js format.
The transform
config just tells jest
to use ts-jest
for ts / tsx files.
Run npx jest
from your project root and jest will execute any tests you have.
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
.
npx jest --watch
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 '../foo';test('basic', () => {expect(sum()).toBe(0);});test('basic again', () => {expect(sum(1, 2)).toBe(3);});
Notes:
Jest provides the global test
function.
Jest comes prebuilt with assertions in the form of the global expect
.
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 */);
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 your jest.config.js
:
module.exports = {// OTHER PORTIONS AS MENTIONED BEFORE// Setup Enzyme"snapshotSerializers": ["enzyme-to-json/serializer"],"setupFilesAfterEnv": ["<rootDir>/src/setupEnzyme.ts"],}
Create src/setupEnzyme.ts
file.
import { configure } from 'enzyme';import 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><inputtype="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 demoexpect(checkbox.text()).toEqual('Off');checkbox.find('input').simulate('change');expect(checkbox.text()).toEqual('On');// Snapshot demoexpect(checkbox).toMatchSnapshot();});
Built-in assertion library.
Great TypeScript support.
Very reliable test watcher.
Snapshot testing.
Built-in coverage reports.
Built-in async/await support.