Setting up Mocha.js to run TypeScript

Dave Schinkel
3 min readSep 22, 2020

I use TypeScript for tests and production code for my site WeDoTDD.com, however I’m not a big fan of it because it becomes pretty cumbersome to maintain it and to continually make TypeScript “happy” in my opinion.

Here’s what you’ll need to do to set it all up

Rename all your existing specs

Well of course this is the first thing you should do, rename spec.js to spec.tsx for those tests who are testing React Components.

If your tests have nothing to do with JSX, and are just unit tests testing behavior outside React, then just rename spec.js to spec.ts.

.mocharc.json

Add this to the root of your project with (tweak the paths depending on your setup):

{
"extension": ["ts", "tsx"],
"spec": ["src/test/**/*.spec.tsx"],
"require": ["jsdom-global/register", "./src/test/compiler.ts"]
}

note: you’ll only need jsdom if you’re rendering your components using mount() or render() whereas it renders full trees of React components.

Enzyme Shallow rendering does not use jsdom. I only have a handful of tests that use mount().

./package.json

"scripts": {
"test": "mocha"
}

src/test/compiler.js

I’ve created an additional compiler.js file which tells ts-node to process my additional tsconfig.json that lives in my src/test folder:

require('ts-node').register({
project: './src/test/tsconfig.json',
});

src/test/tsconfig.json

{
"ts-node": {
"files": true
},
"compilerOptions": {
"jsx": "react",
"lib": ["es2020"],
"module": "commonjs",
"target": "es2020",
"sourceMap": false,
"inlineSources": false,
"esModuleInterop": true,
"resolveJsonModule": true
},
"files": [
"jsx.d.ts"
],
"include": ["src/test/**/*"]
}

Notice I’ve added a ts-node section so that I could tell ts-node to include the custom types defined in my jsx.d.ts file.

optional: src/test/jsx.d.ts

declare namespace JSX {
interface IntrinsicAttributes {
store?: any;
}
}

Here I added a local declaration file that extends and adds store to InstrinsicAttributes for React as I was getting TS runtime errors as React did not know what the store prop was.

Optional: Extending the HTMLAttributes interface

This is another one you’ll come across occasionally:

Property ‘xyz’ does not exist on type ‘HTMLAttributes’

Where ‘xyz’ is some custom prop you are trying to reference from your tests on a React Component.

In this scenario, I was performing an enzyme shallow, finding a child component, and then trying to access its props:

it("shows a question and answer", () => {
const question = {...questionStub},

devsKnow = shallow(<DevsHiredKnowTDD question={question} />),
quest = devsKnow.find(".ft-question").text(),
answer = devsKnow.find(".ft-answer").render().text().toString().replace(/,/g, ""),
details = devsKnow.find(".ft-details");

expect(quest).to.equal(question.question);
expect(answer).to.equal(question.answer[0].toString().replace(/,/g, ""));
expect(details.props().details[0]).to.equal(question.details[0]);
});

it was happening on the following:

details.props().details[0]

so I added a react.custom.d.ts to extend HTMLAttributes:

import { AriaAttributes, DOMAttributes } from 'react';

declare module 'react' {interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
details?: string;
}
}

and then just add the new declaration file to your test folder’s tsconfig again:

"files": [
"jsx.d.ts",
"react.custom.d.ts"
],

This fix is not just for Mocha

This fix applies not only to mocha but possibly other frameworks such as Jest, Ava, etc. because you’ll get the same error in Jest as well with TS in this scenario and possibly others.

So you should be able to apply this same kind of hack to get you past issues like this for now with those frameworks as well.

Hope this helps you. In the meantime check out WeDoTDD.com!

👾 Also, get in on the discussions on Test Driven Development by joining the WeDoTDD.com slack!

--

--

Dave Schinkel

Software Crafter, XP Coach. Past: Sr. Software Artisan at Pillar Tech, Lead Crafter at 8th Light. Test Driven Development Practitioner. I run WeDoTDD.com