docs/testing/jest.md
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.
Install the following using npm:
npm i jest @types/jest ts-jest typescript -D
Explanation:
jest framework (jest)jest (@types/jest)ts-jest) which allows jest to transpile TypeScript on the fly and have source-map support built in.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:
src folder in your project. We assume this is true and specify this using the roots option.testMatch config is a glob pattern matcher for discovering .test / .spec files in ts / tsx / js format.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"
}
npm t.npm t -- --watch.npx jest --watchFor 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:
test function.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>
<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();
});