chaijs / chai-as-promised

Extends Chai with assertions about promises.
MIT License
1.42k stars 109 forks source link

New error with 8.0.0? Error [ERR_REQUIRE_ESM]: require() of ES Module - How to resolve? #301

Open lyricnz opened 4 months ago

lyricnz commented 4 months ago
 Exception during run: Error [ERR_REQUIRE_ESM]: require() of ES Module $$SOMEDIR/node_modules/chai-as-promised/lib/chai-as-promised.js from $$SOMEDIR/test/drivers/driverInterface.spec.js not supported.
Instead change the require of chai-as-promised.js in $$SOMEDIR/test/drivers/driverInterface.spec.js to a dynamic import() which is available in all CommonJS modules.
    at require.extensions.<computed> [as .js] ($$SOMEDIR/node_modules/ts-node/dist/index.js:851:20)

But the quoted driverInterface.spec.js is built from a TS which is:

import * as chai from 'chai';
import chaiAsPromised from 'chai-as-promised';

chai.use(chaiAsPromised);

class RandomInstrumentedResource extends ToolingInterface {
....

Which bit of the code is wrong? (sorry, I'm maintaining a project, but didn't set up any of this TS/JS stuff)

lyricnz commented 4 months ago

This feels like a tsconfig problem? My tsconfig.json file is

{
  "compilerOptions": {
    "target": "es2022",
    "module": "commonjs",
    "lib": [
      "es2022"
    ],
    "declaration": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": false,
    "inlineSourceMap": true,
    "inlineSources": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "typeRoots": [
      "./node_modules/@types"
    ]
  },
  "exclude": [
    "node_modules",
    "dist"
  ]
}

and the generated .js file includes

Object.defineProperty(exports, "__esModule", { value: true });
const chai = __importStar(require("chai"));
const chai_as_promised_1 = __importDefault(require("chai-as-promised"));
const instrumentedResource_1 = require("../../drivers/instrumentedResource");
const driverInterface_1 = require("../../drivers/driverInterface");
chai.use(chai_as_promised_1.default);
43081j commented 4 months ago

you're in a commonjs project (module: "commonjs")

8.0.0 is esm-only (like chai 5.x is too)

so you can either:

lyricnz commented 4 months ago

Thanks. It looks like doing that and I'll have to change 500+ imports to include explicit .js extension?

43081j commented 4 months ago

Node will probably still handle the imports without extensions but I guess typescript may complain if they're not exported paths 😬

It should be scriptable at least but I understand your pain (code review won't be a fun one)

You may be able to loosen typescript's constraints by using module: "bundler"

paulius-valiunas commented 4 months ago

The problem is you can't use 8.0.0 with Typescript yet, because the @types/chai-as-promised package hasn't been updated yet. I'm using this workaround for now:

import * as chaiAsPromised from "chai-as-promised";
use((chaiAsPromised as any).default);

Once the @types package is updated to 8.0, that can be changed to:

import chaiAsPromised from "chai-as-promised";
use(chaiAsPromised);
43081j commented 4 months ago

we should definitely push a new major to the @types package

if anyone has time to contribute that upstream to DT, i'd be happy to review