TypeStrong / ts-node

TypeScript execution and REPL for node.js
https://typestrong.org/ts-node
MIT License
12.9k stars 534 forks source link

'Unexpected token import' running mocha with TS 2.0 #182

Closed SethDavenport closed 8 years ago

SethDavenport commented 8 years ago

Hi, I was hoping you could help me troubleshoot something.

I've been using ts-node to run unit tests with mocha for a while:

mocha  --opts ./src/___tests___/mocha.opts

./src/**tests**/mocha.opts:

--compilers ts:ts-node/register
--compilers tsx:ts-node/register
**/*.spec.ts

This works great with typescript 1.8.10. However since upgrading to typescript 2.0.0 I'm getting this:

/Users/Seth/code/angular-redux/ng2-redux/examples/counter/node_modules/ng2-redux/src/___tests___/components/ng-redux.spec.ts:1
(function (exports, require, module, __filename, __dirname) { import 'reflect-metadata';
                                                              ^^^^^^
SyntaxError: Unexpected token import
    at Object.exports.runInThisContext (vm.js:76:16)
    at Module._compile (module.js:513:28)
    at Module._extensions..js (module.js:550:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/Seth/code/angular-redux/ng2-redux/node_modules/ts-node/src/index.ts:304:16)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Module.require (module.js:468:17)
    at require (internal/module.js:20:19)
    at /Users/Seth/code/angular-redux/ng2-redux/node_modules/mocha/lib/mocha.js:220:27
    at Array.forEach (native)
    at Mocha.loadFiles (/Users/Seth/code/angular-redux/ng2-redux/node_modules/mocha/lib/mocha.js:217:14)
    at Mocha.run (/Users/Seth/code/angular-redux/ng2-redux/node_modules/mocha/lib/mocha.js:469:10)
    at Object.<anonymous> (/Users/Seth/code/angular-redux/ng2-redux/node_modules/mocha/bin/_mocha:404:18)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Module.runMain (module.js:575:10)
    at run (bootstrap_node.js:352:7)
    at startup (bootstrap_node.js:144:9)
    at bootstrap_node.js:467:3
SethDavenport commented 8 years ago

I'm using node 6.3.0.

Here's my tsconfig.json:

{
  "compilerOptions": {
    "target": "ES5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "rootDir": "src",
    "outDir": "lib/",
    "noImplicitAny": false,
    "declaration": true
  },
  "compileOnSave": false,
  "buildOnSave": false,
  "exclude": [
    "node_modules",
    "dist",
    "lib",
    "examples"
  ]
}
SethDavenport commented 8 years ago

This is using ts-node 1.2.3. tsc works fine.

Any ideas what I'm doing wrong?

SethDavenport commented 8 years ago

Here's the repo/branch I'm on: https://github.com/angular-redux/ng2-redux/tree/update/typescript-2

blakeembrey commented 8 years ago

ts-node does not compile files in node_modules.

blakeembrey commented 8 years ago

You can review a similar feature request in https://github.com/TypeStrong/ts-node/issues/155, but it's not high priority personally since it's unlikely you should be publishing raw TypeScript and running it. I would, of course, accept PRs that enable this behaviour behind a flag, but it's a terrible default for reasons I've mentioned in a few other issues.

SethDavenport commented 8 years ago

@blakeembrey thanks for the quick response.

I'm not actually trying to compile a dependency - just my own code. However for some reason stuff is getting pulled in from folders I've explicitly ignored in my tsconfig.json.

SethDavenport commented 8 years ago

Yep that was it.

Need to change **/*.spec.ts to src/**/spec.ts in my mocha.opts. Sorry for wasting your time :)

Not sure why this used to work...

blakeembrey commented 8 years ago

Great, good to know! It probably worked before 1.0 of ts-node (not sure if you updated both at the same time?). The previous behaviour just compiled every .ts file, but it's more important that this module is a good citizen and interacts with how the NPM ecosystem should be used. So in 1.0, I blacklisted node_modules and made it fallback to the old module compiler (in this case it falls back on .js) which is the behaviour you'd normally expect (your node module should be a box you control and shouldn't be affected by someone who's changed their ts-node config as that would result in weird issues) and hence it errors.

Edit: The easy way to catch this is by looking at the stack trace and you can see it was attempted to be loaded with the .js extension compiler.

SethDavenport commented 8 years ago

Yeah, I did update ts-node at the same time. That makes complete sense.

OliverJAsh commented 8 years ago

in 1.0, I blacklisted node_modules and made it fallback to the old module compiler (in this case it falls back on .js) which is the behaviour you'd normally expect

This is also how tsc behaves. If you bundle a module depending on a TS module in node_modules, it won't be compiled. However, if you add that node_modules file to the files whitelist in tsconfig.json, I would expect ts-node to take that as precedence, which is exactly what tsc does.

blakeembrey commented 8 years ago

@OliverJAsh What you describe just isn't really possible. TypeScript follows the files or excludes, but ts-node does not as it wouldn't make a ton of sense to avoid compiling that server file that isn't technically in the tsconfig.json but was required. On top of which, you may also compile 100x more files than you do need during ts-node startup (think testing a single file using mocha, etc).

vekexasia commented 8 years ago

Hello All,

i'm not sure if this is related but i'm getting the same issue "Unexpected token import" from an import which is a local ts file.

tsc works fine. And removing the following tsconfig.json will make everything work as expected:

{
  "compilerOptions": {
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": ["es6", "dom"],

    "module": "es6",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es5"
  }

}
tomitrescak commented 8 years ago

I am having the very same problem. Yet it does not seem to be related to anything that is mentioned here. This is the command that I execute:

> mocha --require ./test_setup.js --report lcovonly src/server/**/tests/*.ts --compilers ts:ts-node/register

/Users/tomi/Github/apps/Clara-Apollo/src/server/configs/tests/accounts_config_tests.ts:1
(function (exports, require, module, __filename, __dirname) { import { config } from 'apollo-module-authentication';

this is my tsconfig.json

{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "es6",
    "module": "es6",
    "moduleResolution": "node"
  },
  "include": [
    "./src/**/*.ts",
    "./src/**/*.tsx"
  ],
  "exclude": [
    "node_modules",
    "src/**/tests/*.ts",
    "src/**/tests/*.tsx"
  ]
}

Does anything seem dodgy to you? I am stuck with this for several hours.

tomitrescak commented 8 years ago

Ah, ok. I need to actually change to es5 and commonjs if I want to use ts-node. Makes sense. This falls back to my problem that -P flag cannot be used with mocha.

jeffrey-l-turner commented 7 years ago

I'm able to compile using the es6 flag by setting module to "commonJS" in my tsconfig @tomitrescak. It appears as though the tsc is not properly compiling the imports otherwise. So I think it is actually a tsc bug.

lygstate commented 7 years ago

"commonjs" after all.

mattdell commented 7 years ago

Strangely for me, I fixed this with @SethDavenport's example though slightly differently.

I had the files to test glob in the test script like so

"test": "mocha --opts tests/mocha.opts tests/**/*.spec.ts"

Moving tests/**/*.spec.ts to mocha.opts magically fixed the issue. Strange!

--compilers ts:ts-node/register
tests/**/*.spec.ts
blakeembrey commented 7 years ago

If you quoted it in the test script, does that also fix your issue? I'm not sure what the problem would be there, but there's probably differences in the shell expansion used by Mocha vs your shell.

akoidan commented 7 years ago

@jeffrey-l-turner well, tsc "module": "commonjs" works but it doesn't allow using fs from node while I'm in tests, how else I'm supposed to load file-content?

import fs from 'fs';
import path from 'path'
blakeembrey commented 7 years ago

@Deathangel908 Both of those are incorrect. It should be import * as fs from 'fs' and import * as path from 'path'.

gluons commented 7 years ago

Thanks @jeffrey-l-turner . You save me. 👍

ts-node -O '{ "module": "commonjs" }' work for me. 🎉

oshingc commented 6 years ago

where do you put this? ts-node -O '{ "module": "commonjs" }'

empz commented 6 years ago

@gluons Yes, that works, but why it doens't if "module": "commonjs" is specified in tsconfig.json ? tsc works using my tsconfig.json but ts-node doesn't...

gluons commented 6 years ago

@emzero In my case, I use "module": "es2015". So, it won't work because ts-node doesn't support "module": "es2015". (#212) But in the other case, I don't know. 😅

gluons commented 6 years ago

@oshingc It's just a command line option. You can use it as a command.

From ts-node docs:

--compilerOptions, -O Set compiler options using JSON (E.g. --compilerOptions '{"target":"es6"}') (also process.env.TS_NODE_COMPILER_OPTIONS)

dreampulse commented 6 years ago

ts-node -O '{ "module": "commonjs" }' works...

But why not ts-node -P? ts-node seems to ignore the tsconfig.json 👎

blakeembrey commented 6 years ago

@dreampulse If you want to complain, please provide enough information for someone to help you. ts-node does and always has read the tsconfig.json file, are you sure you don't have something else configured differently? This module does not have any intention of compiling modules in node_modules since that will end up with invalid output in many cases, especially with native ES6 modules coming to node.js.

fsaldivars commented 6 years ago

@blakeembrey
Hi Could you explain me why when I replace in my "tsconfig,json" => "module": "es6" by "module": "commonjs", everything works ok. I try to find the answer but I cand find it.

I appreciate your comments.

blakeembrey commented 6 years ago

@fsaldivars Node.js doesn't support ES6 modules.

gluons commented 6 years ago

@oshingc Update my answer: Sorry for my old irrelevant answer.
I put that line in package.json's scripts.

Sometime you may need to use ts-node -O {\\\"module\\\":\\\"commonjs\\\"} instead, if ts-node -O '{ "module": "commonjs" }' raise an error on Windows.

yankeeinlondon commented 6 years ago

Hi @blakeembrey, I'm able to get my TS tests to run just fine by pointing ts-node to a project file that states my module format to be "commonjs" (even though my build process actually converts to ES2015). My command line looks like:

TS_NODE_PROJECT="tsconfig.testing.json" mocha --require ts-node/register 'test/*/-spec.ts'

The problem I am running into is that I use the lodash-es library which appears to only export ES2015 code. My source code is transpiled from ES to CJS but libraries in `node_modules appear not to be. I sort of suspect that this is a "mocha" thing more than a "ts-node" thing but the boundary lines are a bit blurry to me. Was wondering if maybe you could weigh in on this.

Oh for reference the the tsconfig.testing.json looks like this:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2015",
    "lib": ["es2017"],
    "declaration": false,
    "noImplicitAny": false,
    "removeComments": true,
    "inlineSourceMap": true,
    "moduleResolution": "node"
  },
  "include": ["scripts/**/*.ts", "src/**/*.ts", "node_modules/lodash-es/**/*.js"]
}

The attempt to add "node_modules/lodash-es/*/.js" at the end is just pure desperation :)

bseib commented 4 years ago

A variation of the above information looks like this in package.json to invoke mocha:

  "scripts": {
    "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha"
  },

This will let mocha invoke ts-node however it may, and ts-node will pick up the compiler options from the environment variable.

folex commented 3 years ago

What worked for me is using esm and ts-node/register:

npx mocha --require ts-node/register --require esm src/**/*.spec.ts

Or in package.json scripts (both options work, choose whichever you like):

"scripts": {
    "test": "mocha -r esm -r ts-node/register src/**/*.spec.ts",
    "test-ts": "ts-mocha -r esm -p tsconfig.json src/**/*.spec.ts"
}

And don't forget to add esm to devDependencies:

npm install --save-dev esm

so in package.json it is gonna be

"devDependencies": {
    "esm": "^3.2.25"
}
EmptyInfinity commented 3 years ago

In my case I import .ts file from monorep, but I should import compiled .js file. Hope it would help someone