piotrwitek / ts-mocha

Mocha thin wrapper that allows running TypeScript tests with TypeScript runtime (ts-node) to get rid of compilation complexity
MIT License
190 stars 25 forks source link

TypeError: Unknown file extension ".ts" - esmodules support #70

Open AuroraLantean opened 2 years ago

AuroraLantean commented 2 years ago

Original post in Anchor repo: [(https://github.com/project-serum/anchor/issues/1286)]

Anchor.toml [script] command: test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/*/.ts"

The problem is the m1.ts file cannot import functions from another ts file!!!??? in my utils.ts

export const log1 = console.log;

in my m1.ts file:

import { log1 } from './utils';
describe('scenario1', async () => {
  it('initialize', async () => {
    log1('\n---------== init');
  });
});

the imported log1 function or any other function will cause the Unknown file extension ".ts" error!!??

my local package dependencies: "mocha": "^9.1.3", "ts-mocha": "^9.0.0-alpha1", "ts-node": "^10.4.0", "typescript": "^4.5.4"

Please advise. Thank you unknown file extension ts2

piotrwitek commented 2 years ago

please test with new v9.0.0 9.0.0-alpha1 is experimental

AuroraLantean commented 2 years ago

Thank you for your post... but "ts-mocha": "9.0.0" results in the same error as above.

piotrwitek commented 2 years ago

@AuroraLantean need a little bit of help, if you could help me to create a simple repo with your setup (package.json and m1.ts + utils.ts files and npm test command) I would try to investigate that repo and fix that issue and also look for a way to add it to the regression testing for your use-case. 

I guess it's related to the ts-node version, not sure why you have installed it in your project but it's different from ts-mocha version possibly clashing.

AuroraLantean commented 2 years ago

Hi @piotrwitek , thank you for your quick reply. Please take the following code: https://github.com/AuroraLantean/SolanaAnchorDemo2 Thank you!

Burwin commented 2 years ago

For another example, I was able to reproduce it with the following repo after installing/using dateformat: https://github.com/Burwin/ts-mocha-file-extension

simonbuchan commented 2 years ago

Pretty sure this is due to type: module in package.json (possibly in a dep). See the ts-node issue for this.

Not sure how to mangle ts-mocha into doing the right thing here? Something like node --loader=ts-node/esm ts-mocha ... should be enough, but doesn't work for me, perhaps ts-mocha needs to support --loader itself?

cn-ia commented 2 years ago

Try ts-mocha -n loader=ts-node/esm -p tsconfig.json tests/**/*.test.ts via npm scripts, it works for me! (Optional) Check npx ts-mocha --help for more details of this option.

DoodahProductions commented 2 years ago

Hello, having the same issue here. Trying @cn-ia solution did not work for me

DoodahProductions commented 2 years ago

If that can help, I found out that this issue seems to be triggered when I do use the package get-port version >= ^6.0.0 If I do remove this package, tests are running correctly. If I add this package, then my test command produce the error TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"

Test command :

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

TsConfig:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "composite": true,
    "outDir": "dist",
    "rootDir": ".",
    "sourceMap": true,
    "strict": false,
    "declaration": true,
    "esModuleInterop": true,
    "resolveJsonModule": true
  },
  "include": [
    "./**/*.ts",
    "src/definitions/**/*.json",
    "src/modules/tasks"
  ],
  "exclude": [
    "node_modules",
    "dist",
    "test"
  ]
}
sagrawal31 commented 2 years ago

Pretty sure this is due to type: module in package.json (possibly in a dep). See the ts-node issue for this.

Not sure how to mangle ts-mocha into doing the right thing here? Something like node --loader=ts-node/esm ts-mocha ... should be enough, but doesn't work for me, perhaps ts-mocha needs to support --loader itself?

For me, this was the problem. Removing "type": "module" from package.json fixed the problem for me.

SmashingQuasar commented 2 years ago

Hey! I have the same issue. I do not have "type": "module" in my package.json so it might be something else. Honestly my package.json is extremely simple so it's doubtful that it originates from there. I'm using ts-mocha version 10.0.0 and ts-node version 10.7.0.

felipeplets commented 2 years ago

@SmashingQuasar I believe the issue is because ts-mocha depends on 1ts-node@7.0.11 which didn't support ESM it would need to depend on 10+ or to have it as a peer dependency although that would force all developers to install ts-node themselves even if they don't use ts-node for other reasons.

If you run npm ls ts-node in your project you should see something like:

@my-project@ /Users/myuser/projects/my-project
├─┬ ts-mocha@10.0.0
│ └── ts-node@7.0.1
└── ts-node@10.7.0

Showing that although your project uses a newer ts-node version ts-mocha still uses an older version.

piotrwitek commented 2 years ago

Hello Everyone, thanks for multiple useful contributions here in this issue, I'll try to look into this issue today and propose some solutions, also I will try to include a special test case scenario on a branch in the repo to help with debugging. Cheers!

piotrwitek commented 2 years ago

I have created a branch with a reproduction test case for experimentation here: https://github.com/piotrwitek/ts-mocha/tree/support-for-node-es-modules

After some research, the issue was indeed introduced by ts-node dependency not handling esmodules and I found some solutions we could try to implement:

More details on ts-node esm support:

I won't have time to work on it anytime soon, but will try to help and accept PRs for this. Cheers!

cspotcode commented 2 years ago

Let me know if you need guidance on the best way to use our ESM loader.

fiftin commented 2 years ago

Same issue.

yasinkocak commented 2 years ago

Same issue

hebelal commented 2 years ago

same issue

gliese1337 commented 1 year ago

Just ran into the same issue myself.

manooog commented 1 year ago

Hello everyone,I have the same problem and I think the problem was caused by tsconfig.json

// ❌ when module = esnext
{
    "compilerOptions": {
        "module": "esnext"
    }
}
// ✅ change module to commonjs,then everything is ok
{
    "compilerOptions": {
        "module": "CommonJS"
    }
}

Hope this trick can help.

janholusa commented 1 year ago

I got the same issue with package.json:

"scripts": 
    "test": "mocha --require ts-node/register test/**/*_spec.ts",
},
"devDependencies": {    
      "@types/chai": "^4.3.3",
      "@types/mocha": "^9.1.1",
      "chai": "^4.3.6",
      "mocha": "^10.0.0",
      "ts-mock-imports": "^1.3.8",
      "ts-node": "^10.9.1",
      "typescript": "^4.8.3"
}

attempt to run test npm run test throws this:

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /somepath/test/binding/cookieNumArray_spec.ts
    at new NodeError (node:internal/errors:372:5)
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:80:11)
    at defaultGetFormat (node:internal/modules/esm/get_format:122:38)
    at defaultLoad (node:internal/modules/esm/load:21:20)
    at ESMLoader.load (node:internal/modules/esm/loader:431:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:350:22)
    at new ModuleJob (node:internal/modules/esm/module_job:66:26)
    at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:369:17)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:328:34)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:409:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15)
    at async formattedImport (/somepath/node_modules/mocha/lib/nodejs/esm-utils.js:7:14)
    at async Object.exports.requireOrImport (/somepath/node_modules/mocha/lib/nodejs/esm-utils.js:38:28)
    at async Object.exports.loadFilesAsync (/somepath/node_modules/mocha/lib/nodejs/esm-utils.js:91:20)
    at async singleRun (/somepath/node_modules/mocha/lib/cli/run-helpers.js:125:3)
    at async Object.exports.handler (/somepath/node_modules/mocha/lib/cli/run.js:370:5)
piotrwitek commented 1 year ago

seems like a problem with Node itself, if someone can make a working example using mocha and ts-node I would be able to integrate it into the library

cspotcode commented 1 year ago

Needs the --loader flag, due to node limitations. Node does not allow programmatic API nor --require to hook ESM.

piotrwitek commented 1 year ago

@cspotcode thanks for jumping in and correcting my assumptions! Could you point me to some examples or solutions that are using mocha and ts-node with ESM successfully that I could try?

cspotcode commented 1 year ago

Google found this: https://github.com/TypeStrong/ts-node/discussions/1268

h-unterp commented 1 year ago

create .mocharc.json and

{ 
    "node-option": [
     "loader=ts-node/esm"
     ]
}
Windovvsill commented 1 year ago

In my case, on of my dependencies (nanoid) added "type": "module" to their package.json. I had to downgrade nanoid to fix mocha.

nmklotas commented 1 year ago

Nanoid got me too

Polve commented 1 year ago

same problem here, and I need to use type: module

quantuminformation commented 1 year ago

came across this today

"ts-mocha": "^10.0.0"

➜  fireproof git:(main) ✗ pnpm test

> @fireproof/core@0.5.6 test /Users/nikos/WebstormProjects/fireproof-nikos-clone/packages/fireproof
> npm run test:mocha

> @fireproof/core@0.5.6 test:mocha
> ts-mocha test/*.test.ts

TypeError: Unknown file extension ".ts" for /Users/nikos/WebstormProjects/fireproof-nikos-clone/packages/fireproof/test/clock.test.ts
    at new NodeError (node:internal/errors:399:5)
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:79:11)
    at defaultGetFormat (node:internal/modules/esm/get_format:121:38)
    at defaultLoad (node:internal/modules/esm/load:81:20)
    at nextLoad (node:internal/modules/esm/loader:163:28)
    at ESMLoader.load (node:internal/modules/esm/loader:605:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:457:22)
    at new ModuleJob (node:internal/modules/esm/module_job:64:26)
    at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:480:17)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:434:34)```

![Uploading image.png…]()
matthew-dean commented 1 year ago

I've tried a variety of solutions in this thread. These did not work:

  1. Changing tsconfig.json's module type to commonjs was not a fix. (This was already the case.)
  2. Changing "type": "module" in package.json was not a fix. (Wasn't the case.)
  3. Adding loader=ts-node/esm did not fix things.
  4. Changing mocha / ts-mocha / ts-node versions did not fix things.

So, I'm kind of at a loss.

quantuminformation commented 1 year ago

i switched to vitest, almost there

webJose commented 1 year ago

Like others, I suffer from this same pain. I have tried all solutions to no avail. If anyone has any updated information, please share.

Thanks.

Polve commented 1 year ago

hoping this can help somebody: I was able to make it work creating a .mocharc.json file with this content:

{
    "node-option": [
        "loader=ts-node/esm"
    ]
}
tim-rohrer commented 11 months ago

create .mocharc.json and

{ 
    "node-option": [
   "loader=ts-node/esm"
     ]
}

I tried adding this but then get:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/<path-to-project>/node_modules/ts-node/esm' imported from /<path-to-project>/
    at new NodeError (node:internal/errors:405:5)
    at finalizeResolution (node:internal/modules/esm/resolve:324:11)
    at moduleResolve (node:internal/modules/esm/resolve:943:10)
    at defaultResolve (node:internal/modules/esm/resolve:1129:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:835:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ESMLoader.import (node:internal/modules/esm/loader:524:22)
    at initializeLoader (node:internal/process/esm_loader:75:58)
    at loadESM (node:internal/process/esm_loader:90:11) {
  code: 'ERR_MODULE_NOT_FOUND'
}

node 18.17.0

cn-ia commented 11 months ago

create .mocharc.json and

{ 
    "node-option": [
     "loader=ts-node/esm"
     ]
}

I tried adding this but then get:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/<path-to-project>/node_modules/ts-node/esm' imported from /<path-to-project>/
    at new NodeError (node:internal/errors:405:5)
    at finalizeResolution (node:internal/modules/esm/resolve:324:11)
    at moduleResolve (node:internal/modules/esm/resolve:943:10)
    at defaultResolve (node:internal/modules/esm/resolve:1129:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:835:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ESMLoader.import (node:internal/modules/esm/loader:524:22)
    at initializeLoader (node:internal/process/esm_loader:75:58)
    at loadESM (node:internal/process/esm_loader:90:11) {
  code: 'ERR_MODULE_NOT_FOUND'
}

node 18.17.0

Do you have dependency ts-node in your project dependencies tree (package.json) ? Install it and try again.

tim-rohrer commented 11 months ago

Ha! I hadn't checked, assuming it was installed as a dep of ts-mocha.

Actually, I got the steps here to work without ts-mocha.

Thank you though.

matthew-dean commented 10 months ago

@webJose So, since I commented on this, I've switched test runners to Vitest in every scenario. As far as I can tell, Jest / Mocha just don't work, or don't work consistently, and Vitest works with very little configuration.

Akronae commented 4 months ago

@matthew-dean this is an order of magnitude much better. It just works, no config needed, and the API is really nice, default typescript support, no crap @types to import. If you're lucky enough to have the ability to switch please consider Vitest!

jacksondoherty commented 1 month ago

Switching to vitest was easy and fixed the issue for me.