MLH-Fellowship / jest

Delightful JavaScript Testing.
https://jestjs.io
MIT License
8 stars 3 forks source link

Support for spawned processes/threads #20

Open kunal-kushwaha opened 4 years ago

kunal-kushwaha commented 4 years ago

Summary

Jest implements a sandbox for every test allowing you to run tests in isolation, and within that sandbox allows you to modify module resolution, globals and so on without worrying how it will impact other tests. But if people spawn subprocesses or worker threads, the sandbox is broken out of, and you lose support for Jest’s features like mocks and fake timers. In addition, we’re unable to collect code coverage for spawned processes. This project would explore ways for Jest to intercept subprocesses or worker threads so it can provide the same features it does in the main process. One avenue to explore is if V8 coverage allows Jest to collect coverage.

Deliverables

Expected behavior

Jest should correctly output coverage for forked processes.

Observed behavior

Jest outputs no coverage for forked processes.

Repo that reproduces the issue

https://github.com/mnmkng/nyc-jest-issue

References

https://github.com/facebook/jest/issues/5274

Test Plan

TBD

SimenB commented 4 years ago

As I think I mentioned it the call we had earlier - this is the area I've put the least research into, and I believe it to be the toughest/most involved project provided to you. I'll try to string some thoughts together, though!

The way Jest currently runs a test is to set up a single jest-runtime, which loads the test file with module resolution, loading etc.. For subprocess/thread to work, we'd essentially have to create a secondary jest-runtime just for the spawned child. Then somehow report back code coverage to the parent process afterwards. If we can make a second runtime work, I assume reporting back some JSON is relatively trivial.

I'm not sure how to best hook into the spawned process, tho. nyc uses node-preload - looking into that implementation might make sense, although it mentions in the README it doesn't support worker threads. If we can support just subprocesses and not threads for now, some support is way better than no support though. And it would still allow us to land the other parts (like reporting back, merging results etc.).

However, I think the approach we need to make is mock out child_process and worker_threads (similar to what we do with module) and replace the spawning with our own custom one, which starts up a new runtime in a thread and then loads the JS file. We need to avoid spawns for non-none programs etc.. I don't know how feasible/scalable that is though.

One open question is whether we should inject expect and the other globals - I'm thinking "no", but I haven't put much thought into it.

rbuckton commented 3 years ago

Would the goals for this project include allowing preprocessors like ts-jest the opportunity to perform preprocessing/transformation as well? I currently have to work around this limitation when using jest+ts-jest by injecting ts-node/register into a worker_thread.Worker that needs to import TypeScript code in the same project.