Skip to content

Using testdouble esm loader with ts-node/esm loader on mocha leads to errors (Node 18.6.0) #496

Closed
@AlexZ-343

Description

@AlexZ-343

Description

I am trying to do esm mocking using testdouble with a mixed Typescript and Javascript project, mostly following this post

Node 18.6.0 now allows for chaining of loads, and I previously needed ts-node/esm in order to recognize my Typescript files and imports.

I realize that this new feature is less than a week old, but I would appreciate support with reconciling other loaders that I would need for my es6 project (or to find a way that only requires one loader). Due to project requirements, using commonjs on runtime is not an option.

Issue

When running the following mocha command:

NODE_OPTIONS='--experimental-specifier-resolution=node --loader=ts-node/esm --loader=testdouble' mocha test/.js test/.spec.ts

and any permutation thereof (removing experimental-specifier-resolution, changing the order of the --loader params)

I get the following exception

Exception in PromiseRejectCallback:
node:internal/modules/esm/loader:178
return output;
RangeError: Maximum call stack size exceeded
Exception in PromiseRejectCallback:
/Users/repos/moRepo/node_modules/ts-node/dist/esm.js:120
const { source: rawSource } = await defaultLoad(url, {
^
RangeError: Maximum call stack size exceeded
at validateArgs (node:internal/modules/esm/loader:578:26)

These 4 lines repeat indefinitely:

at addShortCircuitFlag (/Users/repos/myRepo/node_modules/ts-node/src/esm.ts:409:21)
at load (/Users/repos/myRepo/node_modules/ts-node/src/esm.ts:239:12)
at nextLoad (node:internal/modules/esm/loader:173:28)
at /Users/repos/myRepo/node_modules/ts-node/src/esm.ts:255:45

Environment

node v18.6.0
npm v.8.13.2
testdouble v.3.16.6

Example Repo

I don't have a repo handy, but I can try to create one and add it in the future.

Code-fenced Examples

service_one.ts


export function getAllInvalidObjects(connection: Connection) {
  
 const response: string[] = service_two.getData(someString);
 ... // some transformations of response
 return response;
}

service_two.ts

// this is the function I'd like to mock when testing service_one.ts
export function getData(someString) {
  axios.get('https://endpoint.com/path?string=' + someString).then((response: any) {
   resolve(response.json);
  }
}

test.ts :

import * as td from 'testdouble';

let mock_validation_rest: any;

beforeEach(async () => {
    mock_rest = await td.replaceEsm('../src/services/service_two.js');
});

afterEach(function () {
    sandbox.restore();
    td.reset();
});

it('successfully validates with mocking, async () => {
    td.when(mock_rest.prototype.getData(td.matchers.anything())).thenResolve(mockData);

    // as long as the mock above works then this test will pass
    return service_one.getAllInvalidObjects(connection).then((response: string[]) => {
      assert.equal(3, response.length);
    });
});

package.json:

    {
      "type": "module",
      "scripts": {
         "test": NODE_OPTIONS='--experimental-specifier-resolution=node --loader=ts-node/esm --loader=testdouble' mocha test/*.js test/*.spec.ts -r dotenv/config
      }
    }

tsconfig.json:

    {
      "compilerOptions": {
         "target": "es2016",
         "module": "es6,
         "moduleResolution": "node16"
         "allowJs": true,
         "esModuleInterop": true
      },
      "ts-node": {
         "esm": true
      }
      "include": [
         "./src/**/*",
         "test/**/*/.ts",
         "test/**/*.js"
      }
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions