jest icon indicating copy to clipboard operation
jest copied to clipboard

doMock doesn't fake modules required from NodeJS Worker Thread

Open Alexsey opened this issue 5 years ago • 9 comments

🐛 Bug Report

Module faked with jest.doMock would not be faked for code executed in NodeJS Worker Thread

To Reproduce

Steps to reproduce the behavior:

Main file index.js

const {Worker} = require('worker_threads')

// mocked module outside of Worker Thread. Mocked as expected
const foo = require('./foo')

module.exports = async () => {
  return new Promise(resolve => {
    const worker = new Worker('./worker.js')
    const outOfWorkerFoo = foo()
    worker.on('message', workerFoo =>
      resolve({outOfWorkerFoo, workerFoo})
    )
  })
}

Worker code worker.js

const {parentPort} = require('worker_threads')

// mocked module inside of Worker Thread. Failed to be mocked
const foo = require('./foo')

parentPort.postMessage(foo())

The faked module. It's faked version would be executed for non-worker code and its real version would be executed for worker code

module.exports = () => 'real foo'

The test file index.test.js

const foo = jest.fn()

jest.doMock('./foo', () => foo)

const main = require('./index')

test('test', async () => {
  foo.mockImplementation(() => 'mock foo')

  const mockResult = await main()

  expect(mockResult).toEqual({ // this check would failed
    outOfWorkerFoo: 'mock foo', // value would be as expected: 'mock foo'
    workerFoo: 'mock foo'   // value would NOT be as expected: 'real foo'
  })
})

Expected behavior

Faked scripts should be faked no matter whether they had been required inside of Worker Thread or not. And there should definitely never exist faked and real version of the same script at the same time

Link to repl or repo (highly encouraged)

https://github.com/Alexsey/jest-worker-threads-bug

envinfo

npx: installed 1 in 13.891s

  System:
    OS: Windows 10 10.0.18362
    CPU: (4) x64 Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz
  Binaries:
    Node: 13.7.0 - C:\Program Files\nodejs\node.EXE
    npm: 6.13.6 - C:\Program Files\nodejs\npm.CMD
  npmPackages:
    jest: ^24.9.0 => 24.9.0

Thank you

Alexsey avatar Jan 25 '20 21:01 Alexsey

Yeah, we don't support worker_threads (or child_process). Sorta related to #5274, but that issue is just about coverage, which would be solved at the same time.

I haven't spent much time digging into what we would need to change in order to support it...

SimenB avatar Jan 27 '20 11:01 SimenB

@SimenB I have the same problem with moduleNameMapper - it does not apply to worker_threads. This issue needs to be reclassified, is not a bug report and it doesn't need repro - it is a feature request. Isn't there some simple way to call jest from the worker thread to make it install its handlers? All that is needed is its require interceptor. This would be a very good temporary solution.

mmomtchev avatar Apr 19 '21 13:04 mmomtchev

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

github-actions[bot] avatar Feb 17 '23 16:02 github-actions[bot]

Still relevant

Alexsey avatar Feb 17 '23 17:02 Alexsey

I came up with this workaround - i'm able to get away with it because i'm doing more of an integration test where i'm using a test helper and loading it with worker_threads to reproduce a race condition, but hey, it might help someone:

in my test helper thread worker, at the top:

const mockedModules = new Map(
  ['dependency-1', 'dependency-2'].map((id) => [require.resolve(id), id]),
);
const originalJsHandler = require.extensions['.js'];
const hijackedExtensionHandler = (mod, filename) => {
  const mockedModule = mockedModules.get(filename);
  if (mockedModule) {
    const mockId = `../__mocks__/${mockedModule}`;
    filename = require.resolve(mockId);
  }
  return originalJsHandler(mod, filename);
};
require.extensions['.js'] = hijackedExtensionHandler;

forivall avatar Jun 14 '23 03:06 forivall

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

github-actions[bot] avatar Jun 13 '24 04:06 github-actions[bot]

I don't think it has been resolved

Alexsey avatar Jun 13 '24 05:06 Alexsey

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

github-actions[bot] avatar Jun 13 '25 06:06 github-actions[bot]

still relevant

forivall avatar Jun 13 '25 23:06 forivall