Support concurrent runs in Node.js
See original GitHub issueWhat
I suggest for the setupServer
(node-request-interceptor
) API to support execution in a concurrent mode (i.e. multiple test suite at the same time).
Why
Concurrency is crucial in large projects, allowing for faster execution of tests.
Current behavior
Currently node-request-interceptor
patches native request issuing modules per process, which allows irrelevant mocking rules to leak to another test suites, as they all run in a single process.
How
Look into how nock
operates. It performs modules patching in a similar fashion, and I’d suspect it to support concurrent mode. We can learn how they did it and evaluate if we can adopt a similar solution.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:23
- Comments:29 (20 by maintainers)
Top Results From Across the Web
A simple guide to JavaScript concurrency in Node.js | TSH.io
In the article about JavaScript concurrency in Node.js, the author clarifies how Node deals with asynchronicity. What are the biggest traps?
Read more >Parallelism, concurrency, and async programming in Node.js
Concurrency means that a program is able to run more than one task at a time — this is not to be confused...
Read more >How to handle concurrency in Node.js ? - GeeksforGeeks
Node.js works asynchronously. In other words, it does not block incoming requests from clients when the operating system has one I/O ...
Read more >How does concurrency work in nodejs? - Stack Overflow
Node.js does use multiple threads to handle io user the covers, but this is hidden from the user.
Read more >Does Node.js support concurrent programming natively like Go?
No. Node.js concurrency is “we have only one thread running event loop”. The nearest thing to real concurrency are webworkers - isolated environments ......
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I’ve had some time to think about this, sharing my thoughts below.
First of all, the issue is relevant only to using runtime handlers with parallel test runs. If you’re using the same (global) set of handlers you won’t be affected: handlers are idempotent in nature. When using runtime handlers (
server.use()
), you modify the global list of handlers by pretending a runtime handler. Since all tests refer to the global handlers list, in parallel runs if you prepend one handler in one test, it may affect requests in the irrelevant test (module).I can propose to solve this by ensuring identity of requests and runtime handlers.
Request identity
Currently, each captured request has an
id
. That’s okay. On top of that, I suggest to add something likemoduleId
/modulePath
that represents the module which issued this request. This is only relevant in Node.js.Runtime handler identity
Similar to requests identity, I propose to add
moduleId
/modulePath
only to runtime handlers (those defined viaserver.use()
). As long as the request and the runtime handler share themoduleId
, it guarantees that they were issued/prepended in the same module and can affect each other.moduleId
is not set in the browser.moduleId
is derived from the module and is fixed.moduleId
affects what handlers are considered relevant in the lookup phase. We can first check themoduleId
equality (if set at all) before executinghandler.predicate()
.I find the modification of request/handler instances more acceptable as opposed to creating a handlers list relevant to the module because we can keep our internal handler lookup/resolution phase intact with the proposed change—the source of handlers always remains the same.
In theory, this should allow us to support parallel test runs. Curious about what others think.
I have found two things in my test suite that creates the flaky behaviour. Simply clearing the cache like this does not help (all the time):
When adding a artifical delay like this, it seems to consistently work:
I suspect this might be connected to the other thing I’ve found, but not been able to prove/create a consistent reproducing case.
I test a component that uses SWR to load data, but in this case it can render instantly before the fetch is complete and update it as the data comes in. I have no way to differentiate the loading status from an empty dataset, so the test passes immediately.
But the request (and the mock) is still in-flight and active, so the next test (which should have data) hits the previous mock.
Workaround was adding an invisible loader that I can wait for to disappear before passing the test.