My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMSΒ for Enterprise.
Upgrade ✨Learn more
Integrating Jest Testing in a TypeScript React app without using Create React App

Integrating Jest Testing in a TypeScript React app without using Create React App

Alexi Taylor  πŸš€'s photo
Alexi Taylor πŸš€
Β·Apr 4, 2019

Pre-requisites

Install React and TypeScript

$ npm i react react-dom typescript

Install type definations:

$ npm i --save-dev @types/react @types/react-dom

Install Jest

Jest is a testing framework created by Facebook and ts-jest is a TypeScript preprocessor that allows you to use Jest in TypeScript.

$ npm i --save-dev jest ts-jest @types/jest

Install enzyme

Enzyme is a JavaScript Testing utility for React built by Airbnb. It makes it easy and intuitive to test your React Components by mimicking jQuery's API for DOM manipulation and traversal.

$ npm i --save-dev enzyme enzyme-adapter-react-16 @types/enzyme @types/enzyme-adapter-react-16

Install react-test-renderer

The react-test-renderer library enables you to render React components as JavaScript objects without the need of a DOM.

$ npm i --save-dev react-test-renderer @types/react-test-renderer

React with TypeScript Integration

Create a tsconfig.json file

In order to write TSX or TS files, you need to update the compiler options so that it’s supported in .tsx and .ts files. The tsconfig.json file is the main configuration file for TypeScript. The tsconfig.json file identifies the presence of TypeScript files in the project. Adding this file will give you some control on the compilation of TypeScript into JavaScript.

Create tsconfig.json:

$ touch tsconfig.json

tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "jsx": "react",
    "baseUrl": "src",
    "declaration": false,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "esnext",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es6",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  }
}

Configure Jest Configs

By default, Jest is configured to listen to only JavaScript files. So we have to update the Jest Configs to test our TypeScript files.

Create jest.config.js:

$ touch jest.config.js

jest.config.js

module.exports = {
  preset: 'ts-jest',
  snapshotSerializers: ['enzyme-to-json/serializer'],
  testEnvironment: 'node',
  transform: {
    '^.+\\.tsx?$': 'ts-jest'
  },
  testRegex: '/__tests__/.*\\.test.(ts|tsx)$',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  setupFiles: ['<rootDir>/app/react/__tests__/setupTests.ts'],
  collectCoverage: true,
  collectCoverageFrom: ['app/react/**/*.{ts,tsx}', '!app/react/__tests__/api/api-test-helpers.ts']
};
  • transform: Compiles our TSX to JavScript using ts-jest preset
  • testRegex: Regex to detect what test files to run.
  • setupFiles: Path to our setupTests.ts file
  • collectCoverage: Indicates whether the coverage information should be collected while executing the test.
  • collectCoverageFrom: Indicates a set of files for which coverage information should be or NOT be collected. !app/react/__tests__/api/api-test-helpers.ts' indicates not to collect coverage information on api-test-helpers.ts file.

Create Test Setup File

The setup file configures and sets up our testing environment which will be executed immediately before running the test code itself. Here we register our Enzyme Adapter before each test.

Create setupTests.ts

$ touch setupTests.ts

setupTests.ts:

import enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

enzyme.configure({ adapter: new Adapter() });

Creating our Tests

Create a Components folder then add the following CheckBox TypeScript component (CheckBox.tsx):

import React, { Component } from 'react';

export interface CheckBoxProp {
  labelOn: string;
  labelOff: string;
}

class CheckBox extends Component<CheckBoxProp> {
  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>
    );
  }
}

export default CheckBox;

Create a test directory:

$ mkdir __tests__

Create our test for the CheckBox Component:

import * as React from 'react';
import Enzyme, { shallow, ShallowWrapper } from 'enzyme';
import { create, ReactTestRenderer } from 'react-test-renderer';

import CheckBox, { CheckBoxProp } from '../CheckBox/CheckBox';

let wrapper: ShallowWrapper<CheckBoxProp>;
let snapshot: ReactTestRenderer;

beforeEach(() => {
  const checkbox = <CheckBox labelOn="On" labelOff="Off" />;

  wrapper = shallow(checkbox);
  snapshot = create(checkbox);
});

describe('<CheckBox />', () => {
  test('it matches the snapshot', () => {
    expect(snapshot.toJSON()).toMatchSnapshot();
  });

  it('it should toggle checkbox label after click event', () => {
    expect(wrapper.text()).toEqual('Off');

    wrapper.find('input').simulate('change');

    expect(wrapper.text()).toEqual('On');
  });
});

Update package.json with jest script:

"scripts": {
    "test": "jest"
}

Run tests

$ npm run test

Happy Coding πŸš€