Jest provides _once-global_ setup and teardown, and _per-file_ setup and teardown, but conspicuously absent is _per-worker_ setup and teardown.
One worker's set of tests runs serially, and is ideally suited to reusing an exclusive resource like a database or redis connection.
Sue has a test suite that uses a database. She can create _multiple_ databases, but there is a time cost associated with spinning one up before it can be used.
From her test suite she'd like to get maximum concurrency with minimum database setup time.
Currently possible approaches:
1) One database, run all the tests serially.
beforeAll())globalSetup)-w (or get the wrong number inferred by your CPU core count), and it will either do too much work or not have enough databases.Ideally, instead:
4) Multiple databases, created once per-worker
-w you want (or let Jest infer it), and you'd get the exact right number of databases.Why does this feature belong in the Jest core platform?
I'm not sure where the boundary of _core platform_ is, but it stands to reason that beforeWorker and afterWorker should be provided by the same system that provides beforeAll, beforeEach, and globalSetup.
I googled around but couldn't come up with another way to achieve this. Is there another (perhaps undocumented) way to hook into worker setup/teardown?
https://jestjs.io/docs/en/configuration#setupfilesafterenv-array
But AFAIK there's no option to run something before the worker is closed. I'd find such a feature useful, especially for generating database namespaces to run tests in isolation etc., like with Redis you mentioned.
For more complex use cases, a custom environment is probably more well suited. We do this e.g. for setting up and tearing down a database connection.
@jeysal by "custom environment", you mean the thing specified via testEnvironment, right? Does that give you an opportunity for setup/teardown per-worker, or only per-file?
Well, not exactly per-worker. You can use JEST_WORKER_ID to distinguish between workers for using distinct databases, but I can see how that might not be enough in some use cases, performance-wise.
A big +1 for this 馃憤馃徎
I'm from the core team maintaining Detox (who have already introduced enhancements to Jest, in the past), and we would also really appreciate this kind of support. Our use case is effectively identical, up to the point that instead of databases, we have Android/iOS emulators as the resource in question. We already have the means to bring up emulators on a per-worker basis, but we lack the ability to clean up efficiently (i.e. immediately when a worker is no longer required). Things become even more prominent when these emulators are _rented_ from external SaaS providers such as Genymotion cloud: You literally pay for rent time, and hence must painfully optimize it.
Have any of you folks found a way to emulate this feature using the existing setup / teardown primitives?
@airhorns I've tried doing so by registering a process.on('beforeExit', () => {...}) callback in a worker's context (reference).
Unfortunately, empirically it seems that Jest keeps all workers alive right until the last one is done, so there's no added value compared to subscribing a global-teardown listener (which is the obvious alternative).
In addition, it seems Jest doesn't approve asynchronous work done past the time it expects everything to be torn down -- you get the famous warning saying Jest is still alive 1 second after it should have ended, and can't distinguish this cause for it from a real problem with your tests/code. That is what happens at best, actually, and at worst - your callback is force-killed prematurely along with the worker itself.
@d4vidi that makes sense, thanks for the tip! Are you running without jest's module resetting stuff so that you keep a handle on your per-worker shared resource throughout the run? I have been trying to get the same thing going but struggling to keep any kind of persistent state between suites because of the module reset, which seems desirable for other reasons.
Most helpful comment
A big +1 for this 馃憤馃徎
I'm from the core team maintaining Detox (who have already introduced enhancements to
Jest, in the past), and we would also really appreciate this kind of support. Our use case is effectively identical, up to the point that instead of databases, we have Android/iOS emulators as the resource in question. We already have the means to bring up emulators on a per-worker basis, but we lack the ability to clean up efficiently (i.e. immediately when a worker is no longer required). Things become even more prominent when these emulators are _rented_ from external SaaS providers such as Genymotion cloud: You literally pay for rent time, and hence must painfully optimize it.