React, TypeScript, Webpack & Jest

Max Korabelskyi
7 min readJul 28, 2017

Here is an article about first three things in the title, but what about testing?

If you’r using jest and confusing of how to test your ts-react app within it, then you in right place to get started!

So let’s start from scratch and create a new project, I will be using yarn.

First of all we gonna initialize a new project typing:

cd path/to/your/working/directory/

Checkout to working directory

mkdir ts-react-jest

Creating project directory

yarn init

Initialization of the project

Then you will need to provide your project info, but for now you could just hit Enter to proceed

yarn init output

At this point we have basic project setup. Let’s add all necessary typescript dependencies.

First of all it is good to have typescript installed globally in your system so let’s do it:

yarn global add typescript

Installing ts globally

Also we should add typescript as a dev dependency to our project:

yarn add typescript --dev

Adding ts as a dev dependency to the project

If you don’t have webpack installed globally it is time to install it:

yarn global add webpack

Installing wp globally

And let’s add webpack as a dev dependency to our project

yarn add webpack --dev

Adding wb as a dev dependeny to our project

After it we should add all other necessary dev dependencies:

yarn add awesome-typescript-loader source-map-loader --dev

Adding all necessary dev dependencies

awesome-typescript-loader — just a webpack loader for typescript. About the differences between it and ts-loader (another popular loader for ts) you could read here.

source-map-loader — provides us cool debugging experience as if you were debugging regular ts code in your browser.

Since we are gonna develop react app we need it is as a dependency as well:

yarn add react react-dom

Adding react and react-dom to dependencies

Also we will add declaration files:

yarn add @types/react @types/react-dom

Adding declaration files

Next we should create tsconfig.json file in the root of our project and put there such content:

{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"lib": ["es5", "es6", "dom"],
"jsx": "react"
},
"include": [
"./src/**/*"
]
}

You can take more info about what is tsconfig and how to configure it here.

And at least let’s create webpack.config.js and put it to the root of our project as well:

module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: __dirname + "/dist"
},
devtool: "source-map",
resolve: {
extensions: [".ts", ".tsx", ".js", ".json"],
},
module: {
rules: [{
test: /\.tsx?$/,
loader: "awesome-typescript-loader",
}, {
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader",
}]
},
};

It is a pretty simple config and you could get more about it here.

And one more step before coding is adding tslint :

yarn add tslint tslint-react --dev

Adding tslint and tslint-react to dev dependencies

tslint-react it is react preset for tslint.

Next we should run tslint --init in the root of our project

Initialization of tslint

This will create tslint.json in the root put there such content:

{
"defaultSeverity": "error",
"extends": [
"tslint:latest",
"tslint-react",
],
"jsRules": {},
"rules": {},
"rulesDirectory": [],
"exclude": [
"node_modules",
]
}

tslint is typescript code-style checker more about it you could read here.

So we’r ready to write some code!

Let’s now create our target index.html file. In the root of our project put index.html with such content:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello ts-react app!</title>
</head>
<body>
<div id="app"></div>
<script src="./dist/bundle.js"></script>
</body>
</html>

Then create src directory in the root of our project

mkdir src

Creating src directory

Let’s add index.tsx file in the src and put there this code

import * as React from "react";
import * as ReactDOM from "react-dom";
import App from "./App";ReactDOM.render(
<App testMessage="Hello ts-react-jest app" />,
document.getElementById("app"),
);

Here what we do is rendering our root App component to the DOM

Put in src directory App.tsx file:

import * as React from "react";export interface InterfaceAppProps { testMessage: string };class App extends React.Component<InterfaceAppProps, undefined> {
render() {
return (
<div>
{this.props.testMessage}
</div>
);
}
}
export default App;

It is just a basic react component

At this point we can test how it all works just type webpack at the root:

webpack

Launching webpack

After build just open your index.html in any browser and you should see something like this:

index.html

Let’s create one more component, which will be a child of our App.tsx

Name it Child.tsx :

import * as React from 'react';interface InterfaceChildProps { items: Array<string> }class Child extends React.Component<InterfaceChildProps, undefined>{   
render() {
return (
<div>
{
this.props.items.map((item, i) =>
<p key={i} >{item}</p>
)
}
</div>
);
}
}
export default Child;

Then add Child as a descendant to App and provide to it some mock data:

import * as React from "react";import Child from './Child';export interface InterfaceAppProps { testMessage: string };const mockItems = ["First", "Second", "Third"];class App extends React.Component<InterfaceAppProps, undefined> {
render() {
return (
<div>
<Child items={mockItems} />
</div>
);
}
}
export default App;

Save, recompile with webpack and reload index.hml, result should be next:

index.html

Let’s add some tests!

First of all we should add jest globally and as a dev dependency

yarn global add jest

Adding jest globally

yarn add jest --dev

Adding jest

Secondly we will need enzyme for testing react components:

yarn add enzyme --dev

Adding enzyme

It’s declarations and react-test-renderer:

yarn add @types/enzyme --dev

Adding @types/enzyme

yarn add react-test-renderer --dev

Adding react-test-renderer

Also let’s add ts-jest and @types/jest

yarn add ts-jest @types/jest --dev

Adding ts-jest and @types/jest

As it’s said on official ts-jest github page:

ts-jest is a TypeScript preprocessor with source map support for Jest that lets you use Jest to test projects written in TypeScript.

And I think it is pretty clear =)

After that we should update our package.json file to give jest understanding that it works in typescript env and how it could be compiled in regular JS. Just put it at the end of your package.json:

"jest": {
"transform": {
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
]
}

From ts-jest doc:

This setup should allow you to write Jest tests in Typescript and be able to locate errors without any additional gymnastics.

Now we are able to write tests and launch it with jest command, as usual.

Let’s write test for our Child component:

At first lets create __test__ directory in the src and put there Child.tsx file. Jest will scan our project and understood that all files which are in __test__ directories is test files.

Child.tsx :

import * as React from "react";
import { HTMLAttributes, shallow, ShallowWrapper } from "enzyme";
import Child from "../Child";const testChildProps = {
items: ["1", "2", "3"],
};
let child: ShallowWrapper<undefined, undefined>;beforeEach(() =>
child=shallow(<Child {...testChildProps}/>));
// checking that all is fine and component has been rendered
it("should render without error", () =>
expect(child.length).toBe(1));
it("should render paragraph for each item that has been passed
through props", () => {
const pNodes: ShallowWrapper<HTMLAttributes, undefined> =
child.find("p");
expect(pNodes.length).toBe(testChildProps.items.length);
});

Now you can launch tests with jest command from the root of the project:

Result of running jest

Here you can find all the sources.

--

--