Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing typescript and javascript modules when running Mocha tests

tldr; I want to convert my JS project to TS one file at a time while being able to run Mocha tests without a build step.

I utilize a lot of Babel transforms (class props, jsx, ...) in my current javascript code, which Mocha handles at run-time by registering the babel loader (basically mocha --require @babel/register). This means running a single test is fast and requires no build step for the entire project.

I followed a guide on getting started with TypeScript using the (relatively) new babel plugin from Microsoft: @babel/preset-typescript. This worked fine for the basic case: converting app.js to app.ts.

What it didn't cover was how to do a step-wise transition. For me, fixing 3978 typescript errors (actual count after doing the <code>find</code> ...) is a bit overwhelming and would stall development for two weeks. Just getting my 200 LOC helpers lib to compile nicely with the definitions from react-redux took well over an hour.

While doing git mv app.{j,t}s worked fine, doing it to any other file was a disaster. Existing Mocha tests quickly crashed on being unable to find the right files, even when registering Babel and adding suitable extensions:

mocha --extension js,jsx,ts,tsx --require @babel/register

Typically if doing git mv Logger.{j,t}s I'd get Error: Cannot find module './lib/logging/Logger'.

Is there a way of getting Mocha's module loader to recognize typescript files and transparently run them through Babel?

like image 523
oligofren Avatar asked May 27 '19 13:05

oligofren


1 Answers

Here is how I got this working in our mixed javascript/typescript frankenstein codebase. mocha just transpiles the code before it executes our tests. This makes it happen all in a single step instead of two separate steps. This is my config below. You could replace mocha opts with just adding these as cli flags.

// .mocharc.js
module.exports = {
    diff: true,
    extension: ['ts', 'tsx', 'js'], // include extensions
    opts: './mocha.opts', // point to you mocha options file. the rest is whatever.
    package: './package.json',
    reporter: 'spec',
    slow: 75,
    timeout: 2000,
    ui: 'bdd'
};
// mocha.opts
--require ts-node/register/transpile-only // This will transpile your code first without type checking it. We have type checking as a separate step.
// ...rest of your options.
// package.json
{
  "scripts": {
    "test": "mocha"
  }
}

update: including relevant tsconfig options for a converted react project:

{
    "compilerOptions": {
        "noEmit": true, // This is set to true because we are only using tsc as a typechecker - not as a compiler.
        "module": "commonjs",
        "moduleResolution": "node",
        "lib": ["dom", "es2015", "es2017"],
        "jsx": "react", // uses typescript to transpile jsx to js
        "target": "es5", // specify ECMAScript target version
        "allowJs": true, // allows a partial TypeScript and JavaScript codebase
        "checkJs": true, // checks types in .js files (https://github.com/microsoft/TypeScript/wiki/Type-Checking-JavaScript-Files)
        "allowSyntheticDefaultImports": true,
        "resolveJsonModule": true,
        "esModuleInterop": true,
    },
    "include": [
        "./src/**/*.ts",
        "./src/**/*.tsx",
        "./src/pages/editor/variations/**/*" // type-checks all js files as well not just .ts extension
    ]
}
like image 145
Cam Sloan Avatar answered Oct 31 '22 06:10

Cam Sloan