84

Is it possible to override which tsconfig.json ts-node uses when called from mocha?

My main tsconfig.json contains "module": "es2015", but I want to use "module": "commonjs" for ts-node only.

I tried this

mocha --compilers ts:ts-node/register,tsx:ts-node/register \
    --compilerOptions '{"module":"commonjs"}' \
    --require ts-node/register test/**/*.spec.ts*

but it did not work:

SyntaxError: Unexpected token import
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:387:25)
    at Module.m._compile (/usr/lib/node_modules/ts-node/src/index.ts:406:23)
    at Module._extensions..js (module.js:422:10)
    at Object.require.extensions.(anonymous function) [as .tsx] (/usr/lib/node_modules/ts-node/src/index.ts:409:12)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at /usr/lib/node_modules/mocha/lib/mocha.js:222:27
    at Array.forEach (native)
    at Mocha.loadFiles (/usr/lib/node_modules/mocha/lib/mocha.js:219:14)
    at Mocha.run (/usr/lib/node_modules/mocha/lib/mocha.js:487:10)
    at Object.<anonymous> (/usr/lib/node_modules/mocha/bin/_mocha:458:18)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Function.Module.runMain (module.js:447:10)
    at startup (node.js:146:18)
    at node.js:404:3
Ralph
  • 31,584
  • 38
  • 145
  • 282

9 Answers9

84

You need to set the configuration through the TS_NODE_COMPILER_OPTIONS environment variable

Example code on an unix machine:

TS_NODE_COMPILER_OPTIONS='{"module":"commonjs"}' \
mocha --require ts-node/register 'test/**/*.spec.{ts,tsx}'

Explanation extracted from the repository documentation


CLI and Programmatic Options

Environment variable denoted in parentheses.

  • -T, --transpile-only Use TypeScript's faster transpileModule (TS_NODE_TRANSPILE_ONLY, default: false)
  • -I, --ignore [pattern] Override the path patterns to skip compilation (TS_NODE_IGNORE, default: /node_modules/)
  • -P, --project [path] Path to TypeScript JSON project file (TS_NODE_PROJECT)
  • -C, --compiler [name] Specify a custom TypeScript compiler (TS_NODE_COMPILER, default: typescript)
  • -D, --ignore-diagnostics [code] Ignore TypeScript warnings by diagnostic code (TS_NODE_IGNORE_DIAGNOSTICS)
  • -O, --compiler-options [opts] JSON object to merge with compiler options (TS_NODE_COMPILER_OPTIONS)
  • --files Load files from tsconfig.json on startup (TS_NODE_FILES, default: false)
  • --pretty Use pretty diagnostic formatter (TS_NODE_PRETTY, default: false)
  • --skip-project Skip project config resolution and loading (TS_NODE_SKIP_PROJECT, default: false)
  • --skip-ignore Skip ignore checks (TS_NODE_SKIP_IGNORE, default: false)
  • --log-error Logs errors of types instead of exit the process (TS_NODE_LOG_ERROR, default: false)
  • --prefer-ts-exts Re-order file extensions so that TypeScript imports are preferred (TS_NODE_PREFER_TS_EXTS, default: false)
lleon
  • 2,615
  • 1
  • 20
  • 14
  • bummer that there doesn't seem to be a nice way of doing this in a way that works for both Windows and *nix. – Zach Lysobey Jan 16 '18 at 02:28
  • Take a look at @Louis answer for a cross-platform support – lleon Jan 17 '18 at 19:21
  • 6
    Windows: ```cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} mocha -r ts-node/register test/**/*.spec.ts --reporter=dot``` – Dantio Oct 17 '19 at 10:59
49

TypeScript allows you to override a configuration file. Rather than hard-code JSON in an environment variable as mentioned in the other solutions, specify the overridden configuration path in the environment. The TS_NODE_PROJECT environment variable can be used for this.

TS_NODE_PROJECT='./tsconfig.commonjs.json'

So if your main config is:

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
   }
}

You can create another configuration that overrides the module setting.

tsconfig.commonjs.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs"
  }
}

When you run mocha, specify the overridden configuration to use:

"test": "TS_NODE_PROJECT='./tsconfig.commonjs.json' mocha -r ts-node/register test/**/*.spec.ts*"

This makes it very easy to further customize your tsconfig just for mocha testing. You can even run ts-node (outside of mocha) directly specifying that path:

ts-node -P tsconfig.commonjs.json -r myFile.ts 
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
  • 7
    For Windows a small adjustment were needed: `SET TS_NODE_PROJECT=./tsconfig.commonjs.json&& mocha -r ts-node/register test/**/*.spec.ts` – Per Jan 07 '20 at 15:54
  • 1
    You can use cross-env (https://www.npmjs.com/package/cross-env) to make the command platform independent. – d_scalzi Apr 13 '20 at 22:53
  • 1
    In @PerThomasson's comment, the space between `.json` and `&&` is **not** a typo, it is needed. Might save you some time :D – colinD Jun 11 '20 at 11:56
  • Nice example. It worked. Now I have another problem, My code is for browser then I have some `document.getElementById`, when I run the test I get the error `ReferenceError: document is not defined` Any idea? Thanks. – Rolly Aug 06 '20 at 23:22
  • If document is not defined, you are not running in a browser, or you built for the wrong target, or you need to include a browser environment in your node runtime. – Steven Spungin Aug 07 '20 at 19:04
22

--compilerOptions wont' work.

What you need to do is customize how you register ts-node. My case was a little bit different from yours, I wanted it to use test/tsconfig.json, which contained settings needed by my test code. If I just used --require ts-node/register, it was using a default configuration that did not contain the settings needed to run my tests.

What I did was:

  1. Create a file test/tshook.js. It contains:

    require("ts-node").register({
      project: "test/tsconfig.json",
    });
    
  2. I edited my test/mocha.opts to have:

    --require test/tshook.js
    test/**/*.ts
    

This should will pass the desired setting to ts-node:

require("ts-node").register({
  compilerOptions: {
    module: "commonjs",
  },
});
Louis
  • 146,715
  • 28
  • 274
  • 320
  • This breaks breakpoints in Webstorm debug. Probably something wrong in maps file. Note that breakpoints break under in `./src/` files while under `./test` they work fine. Anything can be done about it? I mean if I don't do this `--require test/tshook.js` - breakpoints work as expected. – deathangel908 Jul 31 '17 at 14:00
  • Here's how it looks: I tried to `stepInto` but it skipped a lot of functions, and stopped somewhere in random place. Without `tshooks` this works as expected . https://static.pychat.org/photo/WLdZb0pO_Mon_Jul_31_170826_2017.gif – deathangel908 Jul 31 '17 at 14:11
  • 1
    In case anyone else is wondering how mocha finds "test/mocha.opts", that path is the default path for this file. In my case I had a different folder name for tests, which was causing problems. – Niilo Keinänen Jul 08 '19 at 11:14
7

In package.json - scripts section:

"test": "TS_NODE_PROJECT=src mocha"

picks up my tsconfig.json in the src directory of my project, overriding the default tsconfig.json.

OP can achieve same by using test instead of src

Samir Seth
  • 539
  • 6
  • 9
  • 3
    I have to specify path to the tsconfig.json file i.e. /test/tsconfig.json to make it work – barath Jun 25 '19 at 04:37
6

This worked for me on windows

set TS_NODE_COMPILER_OPTIONS={\"module\":\"commonjs\"} && mocha -r ts-node/register test/unit/*.test.ts 

This was the error that prompted me to use that solution

(function (exports, require, module, __filename, __dirname) { import 'mocha';

Wakeel
  • 4,272
  • 2
  • 13
  • 14
5

You can also use ts-mocha (https://www.npmjs.com/package/ts-mocha)

Example

package.json

"test": "ts-mocha -p test/tsconfig.cjs.json test/**/*.test.ts"

test/tsconfig.cjs.json

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "module": "commonjs"
  }
}
Grafluxe
  • 483
  • 4
  • 11
3

While there doesn't seem to be a unified linux/windows command line phrasing that works, you can set the compiler-options from the command line. In my case, much like the OP, I have a tsconfig.json with a module: esnext. I was able to override on the command line:

Ran on Windows, w/ts-node installed globally, but in different shell types:

bash/mingw64:
ts-node --compiler-options={"module":"commonJS"} xxx.ts

cmd:
ts-node --compiler-options={\"module\":\"commonJS\"} xxx.ts

Randy Larson
  • 6,817
  • 2
  • 18
  • 13
1

On mac

"test": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' mocha --require ts-node/register test/**/*.ts",
barath
  • 762
  • 1
  • 8
  • 26
0

This doesn't address the core original question, but goes to the heart of getting mocha with typescript working, so I'll post it here in case it helps others.

We found that some ridiculous backslash escaping was needed to make this work on Windows. It works fine on Mac too, even though Mac doesn't need the same escaping.

Then, additional ts-node require directives were critical.

File package.json:

{
  "scripts": {
    ...
    "test": "cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} mocha"
  },

  ...

  "mocha": {
    "require": [
      "ts-node/register",
      "tsconfig-paths/register"
    ],
    "watch-files": [
      "./src/**/*.ts",
      "./tests/**/*.spec.ts"
    ],
    "spec": "./tests/**/*.spec.ts"
  }
Andrew E
  • 7,697
  • 3
  • 42
  • 38