Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use testdouble loader with mocha and typescript #487

Closed
3 tasks
paymog opened this issue Jun 5, 2022 · 2 comments
Closed
3 tasks

Can't use testdouble loader with mocha and typescript #487

paymog opened this issue Jun 5, 2022 · 2 comments

Comments

@paymog
Copy link

paymog commented Jun 5, 2022

Description

I'm trying to use td.replaceEsm which requires the testdouble loader but I also need to use the ts-node/esm loader and can't figure out how to use both simulatenously.

Issue

I have a nodejs application that I'm slowly migrating to typescript. I'm using mocha as my testing framework. I've found I need to pass -n loader=ts-node/esm to mocha so that it doesn't complain about my typescript test files. Without that loader I get the following error:

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/paymahn/code/tripvector/tripvector-mono/backend/src/api/trips/graphql/queries.test.ts

If I execute mocha like so, the above error goes away and all my tests run successfully: npx mocha -n loader=ts-node/esm src/**/*.test.ts

However, now that I need to use td.replaceEsm with the testdouble loader, I get similar errors above (note the two loaders I pass in the mocha command:

 ❯❯❯ NODE_ENV=testing npx mocha -n loader=ts-node/esm -n loader=testdouble --exit --timeout 60000 src/**/*.test.ts
(node:29103) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
(node:29103) DeprecationWarning: Obsolete loader hook(s) supplied and will be ignored: getFormat, getSource

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/paymahn/code/tripvector/tripvector-mono/backend/src/api/recommendations/convertTime.test.ts

I've also tried swapping the order of loaders but that causes the td.replaceEsm in one of my tests to fail (assuming I've set that up correctly):

 ❯❯❯ NODE_ENV=testing npx mocha  -n loader=testdouble -n loader=ts-node/esm --exit --timeout 60000 src/**/*.test.ts
(node:29280) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)

  // lots of output

  1) trips
       trip query
         throws error if user is not owner:
     Error: Sorry, you are not allowed to view this trip
      at Object.trip (file:///Users/paymahn/code/tripvector/tripvector-mono/backend/src/api/trips/graphql/queries.js:77:13)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at async Context.<anonymous> (file:///Users/paymahn/code/tripvector/tripvector-mono/backend/src/api/trips/graphql/queries.test.ts:33:7)

Is there a mechanism to use both the testdouble and ts-node loader?

Environment

  • node -v output: v17.6.0
  • npm -v (or yarn --version) output: 7.6.0
  • npm ls testdouble (or yarn list testdouble) version: nodejs-server@ /Users/paymahn/code/tripvector/tripvector-mono/backend
    └── testdouble@3.16.5
@paymog
Copy link
Author

paymog commented Jun 5, 2022

Ah, just found https://github.com/cspotcode/multiloader which seems to be working. I'm now invoking mocha like so:

12:26PM /Users/paymahn/code/tripvector/tripvector-mono/backend  ✘ 9 master ✭ ✱ ◼
 ❮❮❮ NODE_OPTIONS="--loader @cspotcode/multiloader/compose?ts-node/esm,testdouble" NODE_ENV=testing npx mocha   --exit --timeout 60000 src/**/*.test.ts
(node:31520) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
(node:31521) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)

// test output

It seems that the multiloader is working because there are two warnings regarding the experimental loader. However, I'm still seeing that td.replaceEsm isn't working. Here's the code I'm trying to work with:

// queries.js
import { findTripById, Trips } from '../index.js';
import { getTrip } from '../getTrip.js';
import { Guides } from '../../guides/index.js';
import {
  canUserAdministerTrip,
  checkIfUserCanEditTrip,
  checkIfUserCanSeeTrip,
} from '../../../lib/validation.js';

export const tripQueries = {
  trip: async (parent, args, context) => {
    const { _id, guide } = args;
    if (
      !(await checkIfUserCanSeeTrip({
        user: context.user,
        tripId: _id,
        editToken: context?.query?.editToken,
      }))
    ) {
      throw new Error('Sorry, you are not allowed to view this trip');
    }

    const trip = await getTrip(_id);

    return {
      ...trip,
      guide: await Guides.findOne({ _id: trip?.guideId }),
    };
  },
};

I'm trying to make a testdouble for the checkIfUserCanSeeTrip function. Here's my test file:

// queries.test.tx   <------ note that this is a typescript file!
import * as td from 'testdouble';

describe('trips', () => {
  let validationModule: any;
  let tripQueries: any;

  beforeEach(async () => {
    validationModule = await td.replaceEsm('../../../lib/validation.js');
    tripQueries = (await import('./queries.js')).tripQueries;
  });

  describe('trip query', () => {
    it('throws error if user is not owner', async () => {
      td.when(validationModule.checkIfUserCanSeeTrip(undefined, 1, undefined)).thenReturn(true);

      await tripQueries.trip({}, { _id: 1, guide: {} }, {});
      td.verify(validationModule.checkIfUserCanSeeTrip(undefined, 1, undefined));
    });
  });
});

Note that I call replaceEsm on the validation.js file with the exact same path as how validation.js is imported in the file I'm testing. Also note that I'm doing .thenReturn(true) which should end up with the file under test not throwing an error. However, when I invoke this test I get the following output:

  1) trips
       trip query
         throws error if user is not owner:
     Error: Sorry, you are not allowed to view this trip
      at Object.trip (file:///Users/paymahn/code/tripvector/tripvector-mono/backend/src/api/trips/graphql/queries.js:77:13)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at async Context.<anonymous> (file:///Users/paymahn/code/tripvector/tripvector-mono/backend/src/api/trips/graphql/queries.test.ts:33:7)

Am I doing something wrong here? Why isn't checkIfUserCanSeeTrip being correctly faked?

@paymog
Copy link
Author

paymog commented Jun 5, 2022

Turns out swapping the order of loaders solves the problem! This command causes all my tests to run as expected: NODE_OPTIONS="--loader @cspotcode/multiloader/compose?testdouble,ts-node/esm" NODE_ENV=testing npx mocha --exit --timeout 60000 src/**/*.test.ts

@paymog paymog closed this as completed Jun 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant