12

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?

3
  • You will always need a compile step for ts files however you could have two separate scripts one for ts / tsx files that you compile and another for js files and chain them then just run mocha --extension js,jsx instead of including and piping tsx to the babel register. Commented Nov 4, 2019 at 17:18
  • Hmm ... I guess that is doable. Hints on how to set that up? I guess I'd need a build folder that copied all the js modules over and transpiled all the ts modules into something that would could be loaded by Mocha. Commented Nov 5, 2019 at 14:57
  • i assume you are using npm or yarn you can just add them to the scripts part of your package.json you could do it by directory or by file extension eg --extension js,jsx and then use the precompiler on the ts and tsx ones. Of course webpack provides a lot of easy config stuff for that, which might make your life easier if you where to start using that. Commented Nov 6, 2019 at 13:47

1 Answer 1

5

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
    ]
}
Sign up to request clarification or add additional context in comments.

4 Comments

That indeed seems very promising, but it is essentially the same as my Babel config (which also didn't do any actual type checks, only superficial transpilation). Does the transpile step actually end up outputting transpiled javascript files, or is that more of a temporal thing? I would like to avoid having a dist folder or needing to git clean -fd every time. P.S. mocha.opts is deprecated, and .mocharc.js does everything it does. So you can just delete the mocha.opts file and inline the require calls into the config as a require: ['ts-node/register/transpile-only'] field.
I'll award you the answer, once I have some time to test this and verify that I can get it to work the way I hope it works :-) P.S. I just realized you were that Cam from Twitter :D Thanks for getting back to me with some actual code!
Took my a looong time to get this working, as JSX would make it fail, but it turned out the TS config was set to not touch JSX, so I had to create a new tsconfig just for tests that extended my standard tsconfig and basically set jsx: "react".
Ah yeah my tsconfig file for working with react is a whole thing in itself. I will edit and include what I believe are the relevant compilerOptions. There is a lot of hoop-jumping to get tests, linting, and compiling working with a large react project that was not set up in TS to begin with. This is a whole story of its own.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.