Jest

Pro egghead lesson on Jest / TypeScript

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.

Step 1: Install

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)

Step 2: Configure Jest

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.

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 '../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.

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

Pro egghead lesson on Enzyme / Jest / TypeScript

Enzyme allows you to test react components with dom support. There are three steps to setting up enzyme:

  1. 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

  2. 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"],
    }
  3. 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();
    });

Reasons why we like jest

For details on these features see jest website

  • Built-in assertion library.

  • Great TypeScript support.

  • Very reliable test watcher.

  • Snapshot testing.

  • Built-in coverage reports.

  • Built-in async/await support.