How can I avoid mixing static and dynamic imports when using Jest and ESM together?
Asked Answered
S

0

6

Recently I had to migrate my project to ESM, mainly because many dependencies I'm using are not compatible with CommonJS anymore.

By doing so I had a lot of troubles that I solved step by step. However, the way I'm testing with Jest now is worse than before.

This is how I used to spyOn a library before:

it('stringFormatMatchValidatorFactory return the correct result', async () => {
  const spiedValidate = jest.spyOn(ValidatorHelper, 'validateStringFormat');
  const testDataFunctionMatch = Validator.stringFormatMatchValidatorFactory({
    toMatch: true,
    pattern: StringFormatEnum.ALL,
  });
});

And this is how I have to do it now:

import { importMockedEsm } from '@nestjs-yalc/jest/esm.helper.js';
import { DeepMocked } from '@golevelup/ts-jest';

const ValidatorHelper = (await importMockedEsm(
  '../validator.helper.js',
  import.meta,
)) as DeepMocked<typeof import('../validator.helper.js')>;

const Validator = await import('../validator.decorator.js');

// [...]


it('stringFormatMatchValidatorFactory return the correct result', async () => {
  const spiedValidate = jest.spyOn(ValidatorHelper, 'validateStringFormat');
  const testDataFunctionMatch = Validator.stringFormatMatchValidatorFactory({
    toMatch: true,
    pattern: StringFormatEnum.ALL,
  });
});

Where importMockedEsm is a custom function that I had to set up in my project, and it doesn't fully support partial mocking.

As you can see, there's a mix of static imports and dynamic imports as well, which makes the job for the Visual Studio Code IDE even worse regarding autocompletion and type checking.

This happens because ESM modules are treated as "frozen" modules, which means spyOn can't mock its functions anymore, but mocking with the new Jest unstable_mockModule implies that we should use the dynamic imports for all the dependencies that need to use the mocked module.

References:

Keeping my project under CommonJS and downgrading other dependencies is not really a possibility (I've read about people suggesting it everywhere). Many packages are discarding support for CommonJS.

I've looked around for alternative solutions, but apparently the JavaScript world is doing this switch while Jest and many other tools are not prepared yet.

I would like to avoid it using this syntax:

const ValidatorHelper = (await importMockedEsm(
  '../validator.helper.js',
  import.meta,
)) as DeepMocked<typeof import('../validator.helper.js')>;

and not having both static and dynamic imports.

Is there a way to avoid needing that syntax above every time I need to mock/spy a module function? Is there a way to let Visual Studio Code use dynamic imports everywhere (in the __tests__ folder, for the .spec files)?

Skinner answered 21/2, 2023 at 11:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.