Jest states in docs:
"Jest virtualizes JavaScript environments and runs tests in parallel across worker processes."
But what about multiple tests inside one file, do they run in parallel or this statement applies just to the test files? Can I assume that tests in one file run in order of appearance and in serial?
You can safely assume tests inside a single file will run in the order of appearance. You could prove this by putting a console.log in each it block.
It's probably worth mentioning that it's generally bad practice to rely on the order of execution / external state...and you never know, Jest (or the current underlying test runner, Jasmine) may decide to run them in a random order in a newer version.
Jest in 2020
To add a bit more information on this, async tests are run in series inside of a describe() statement. This is useful for IO/Database setup and cleanup functions. Just take a look at the following example:
some.spec.js
describe("my asynchronous tests", () => {
beforeEach(async () => {
console.log('> setup test')
// SOMETHING ASYNCHRONOUS
});
afterEach(async () => {
console.log('< teardown test')
// SOMETHING ASYNCHRONOUS
});
test("test 1", async () => {
console.log('-- starting test 1');
// SOMETHING ASYNCHRONOUS
console.log('-- finished test 1');
}, 100000);
test("test 2", async () => {
console.log('-- starting test 2');
// SOMETHING ASYNCHRONOUS
console.log('-- finished test 2');
}, 100000);
});
Outputs:
> setup test
-- starting test 1
-- finished test 1
< teardown test
> setup test
-- starting test 2
-- finished test 2
< teardown test
Multiple describe() statements will execute in parallel though, even if they're in the same file.
Note, you may get side effects of two tests running in parallel if one of them times out after 5 seconds - jest stops waiting for the timed out test, but it's code continues executing, in parallel with the following test jest picks up.
(pulled out quite an amount of hair before I realised that this was the reason of the side effects that led me here)
You can use test.concurrent('test run concurrently', () => { ... }) if you want to run them in parallel inside one file is too slow. It is a bit buggy and not well documented, but at least there's a way there.
One thing I notice is it does not wait for async stuff in the beforeAll() so you need some of your own trick(like setInterval to wait) to make it work as expected.
To make test files run sequentially use -i or --runInBand flag
jest --runInBand
ref: jest docs
Weirdly enough, running the tests sequentially finishes faster on my M1 Mac!, better test for you use case
Related
I need to make part of my method's code asynchronous, so it will execute in a non-blocking manner. For this purpose I've tried to create a "dummy" Promise and put the specified code in then block. I have something like this:
public static foo(arg1, arg2) {
const prom = new Promise((resolve, reject) => {
if (notValid(arg1, arg2)) {
reject();
}
resolve(true);
});
prom.then(() => {
...my code using arg1 and arg2...
});
}
However, then block always executes synchronously and blocks whole app, even though each and every JS documentation tells that then always runs asynchronously. I've also tried to replace the Promise with this:
Promise.resolve().then(() => {
...my code using arg1 and arg2...
});
but got same result.
The only way I've managed to make then block work asynchronously is by using setTimeout:
const pro = new Promise(resolve => {
setTimeout(resolve, 1);
});
pro.then(() => {
...my code using arg1 and arg2...
})
What can be the reason behind then block working synchronously? I don't want to proceed with using setTimeout, because it is kind of a "dirty" solution, and I think that there should be a way to make then run asynchronously.
Application is NodeJS with Express, written using Typescript.
I need to make part of my method's code asynchronous, so it will execute in a non-blocking manner. For this purpose I've tried to create a "dummy" Promise and put the specified code in then block.
Promises don't really make things asynchronous in and of themselves. What they do is wrap around something that's already asynchronous, and give a convenient way to tell when that thing is done. If you wrap a promise around something synchronous, your code is mostly still synchronous, just with a few details about when the .then callback executes.
even though each and every JS documentation tells that then always runs asynchronously.
By that, they mean that it waits for the current call stack to finish, and then runs the code in the .then callback. The technical term for what it's doing is a "microtask". This delay is done so that the order of operations of your code is the same whether the promise is already in a resolved state, or if some time needs to pass before it resolves.
But if your promise is already resolved (eg, because it's wrapped around synchronous code), the only thing your .then callback will be waiting for is the currently executing call stack. Once the current call stack synchronously finishes, your microtask runs synchronously to completion. The event loop will not be able to progress until you're done.
The only way I've managed to make then block work asynchronously is by using setTimeout
setTimeout will make things asynchronous*, yes. The code will be delayed until the timer goes off. If you want to wrap this in a promise you can, but the promise is not the part that makes it asynchronous, the setTimeout is.
I don't want to proceed with using setTimeout, because it is kind of a "dirty" solution
Ok, but it's the right tool for the job.
* when i say setTimeout makes it asynchronous, i just mean it delays the execution. This is good enough for many cases, but when your code eventually executes, it will tie up the thread until it's done. So if it takes a really long time you may need to write the code so it just does a portion of the work, and then sets another timeout to resume later
I'am trying to invoke the same function parallely, but with different arguements. I used Promise.all, but that doesn't seem to run the tasks parallely. I tried using bluebird, but still it seems that the executions are happening sequentially only. PFB the snippet of code and logs.
let records = await getRecords(query);
if (_.size(records) > 0) {
bluebird.map(records, function (record) {
return prepareFileContent(record.MESSAGE_PAYLOAD);
}, { concurrency: records.length }).then(function (data) {
finalData = data;
console.log("done");
});
}
export async function prepareFileContent(payload : string) : Promise<string>{
return new Promise<string>(function(resolve,reject){
try{
console.log("content generation starts");
//logic goes here
console.log("content generation ends");
resolve(details);
}
catch(err)
{
log.error("Error in parsing the payload:", err);
reject(err);
}
});`
Logs look something like this which shows that they are executed sequentially and not parallely. (from the time here, each one takes 4 seconds for execution)
2018-04-16T08:47:53.095Z content generation starts
2018-04-16T08:47:57.819Z content generation ends
2018-04-16T08:47:57.820Z content generation starts
2018-04-16T08:48:02.253Z content generation ends
2018-04-16T08:48:02.254Z content generation starts
2018-04-16T08:48:06.718Z content generation ends
2018-04-16T08:48:06.718Z content generation starts
2018-04-16T08:48:11.163Z content generation ends
2018-04-16T08:48:11.163Z content generation starts
2018-04-16T08:48:15.573Z content generation ends
2018-04-16T08:48:15.574Z content generation starts
Can someone help me out on how to achieve the same parallely and what am I missing here?
First off, node.js Javascript is single threaded. So, no two pieces of Javascript are ever truly run in parallel. When people speak of things running parallel, that only really applies to asynchronous operations that have a native code component such as networking operations, file operations, etc...
It appears that you're operating under an assumption that promises and functions like Bluebird's Promise.map() enable parallel operation. That is only true if the underlying operations you're monitoring with promises (your prepareFileContent() function in your example) are actually capable of running by themselves outside of the Javascript interpreter. But, the code from your function prepareFileContent() that you show us is just Javascript so it can't ever run in parallel with anything else. Remember, node.js runs your Javascript single threaded so it can't run two pieces of Javascript at the same time, ever.
So, your output is exactly as expected. bluebird.map() iterates through the array, calling your callback on each item in the array and collecting a promise from each function call. Then, it waits for all the promises to be done and collects all the resolved results into an array for you.
But, each of your callbacks is synchronous. They don't have any asynchronous part to them so all your code ends up running synchronously. Nothing runs in parallel.
This code works because system-sleep blocks execution of the main thread but does not block callbacks. However, I am concerned that system-sleep is not 100% portable because it relies on the deasync npm module which relies on C++.
Are there any alternatives to system-sleep?
var sleep = require('system-sleep')
var done = false
setTimeout(function() {
done = true
}, 1000)
while (!done) {
sleep(100) // without this line the while loop causes problems because it is a spin wait
console.log('sleeping')
}
console.log('If this is displayed then it works!')
PS Ideally, I want a solution that works on Node 4+ but anything is better than nothing.
PPS I know that sleeping is not best practice but I don't care. I'm tired of arguments against sleeping.
Collecting my comments into an answer per your request:
Well, deasync (which sleep() depends on) uses quite a hack. It is a native code node.js add-on that manually runs the event loop from C++ code in order to do what it is doing. Only someone who really knows the internals of node.js (now and in the future) could imagine what the issues are with doing that. What you are asking for is not possible in regular Javascript code without hacking the node.js native code because it's simply counter to the way Javascript was designed to run in node.js.
Understood and thanks. I am trying to write a more reliable deasync (which fails on some platforms) module that doesn't use a hack. Obviously this approach I've given is not the answer. I want it to support Node 4. I'm thinking of using yield / async combined with babel now but I'm not sure that's what I'm after either. I need something that will wait until the callback is callback is resolved and then return the value from the async callback.
All Babel does with async/await is write regular promise.then() code for you. async/await are syntax conveniences. They don't really do anything that you can't write yourself using promises, .then(), .catch() and in some cases Promise.all(). So, yes, if you want to write async/await style code for node 4, then you can use Babel to transpile your code to something that will run on node 4. You can look at the transpiled Babel code when using async/await and you will just find regular promise.then() code.
There is no deasync solution that isn't a hack of the engine because the engine was not designed to do what deasync does.
Javascript in node.js was designed to run one Javascript event at a time and that code runs until it returns control back to the system where the system will then pull the next event from the event queue and run its callback. Your Javascript is single threaded with no pre-emptive interruptions by design.
Without some sort of hack of the JS engine, you can't suspend or sleep one piece of Javascript and then run other events. It simply wasn't designed to do that.
var one = 0;
function delay(){
return new Promise((resolve, reject) => {
setTimeout(function(){
resolve('resolved')
}, 2000);
})
}
while (one == 0) {
one = 1;
async function f1(){
var x = await delay();
if(x == 'resolved'){
x = '';
one = 0;
console.log('resolved');
//all other handlers go here...
//all of the program that you want to be affected by sleep()
f1();
}
}
f1();
}
I've recently encountered a strange behaviour. I have a big project that contains a lot of the tests and some of them were written in a synchronous way, assuming that the promise library is the one without deferred.
However, after preparing the environment on my machine (Mac OS X, nodeJS 0.12.18 - i know :( ), the tests seem to run with a different promise implementation - this time using async version with deferred and hence following test fails:
// Some generic mocking code here
instance.doSomething(); // This returns a promise
// Immediately after the previous call, we check the results and clean mocks
sinon.assert.called(request.Request);
request.Request.restore();
It started to work after being rewritten like this:
return instance.doSomething().then(function() {
sinon.assert.called(request.Request);
request.Request.restore();
});
To sum up, instance.doSomething performs two requests.
If the promise is called synchronously, request mock gets restored after both calls. If the promise is called asynchronously, first call succeeds but the second one fails, as in the meantime the stub was restored (before second call).
My questions are:
Is is possible that on my machine and CI, Mocha uses different promise implementations?
Is there a way to force promise implementation for Mocha?
Maybe the changed Promise comes from another place in the code?
All of this seems really strange, especially as the code uses bluebird as the main Promise library...
If you what you are testing won't be guaranteed to be in the correct state for testing until the promise is resolved, then you should write your test as you show in your 2nd snippet. That is the correct way to test conditions that depend on resolved promises. The fact that your initial code worked is due to luck. Consider the following code:
const assert = require("assert");
const Promise = require("bluebird");
let moo = "initial";
function someFunc() {
return Promise.resolve()
.then(function () {
moo = "modified";
});
}
beforeEach(() => moo = "initial");
it("test one", () => {
someFunc();
assert.equal(moo, "modified");
});
it("test two", () => {
return someFunc().then(() => {
assert.equal(moo, "modified");
});
});
The promise in someFunc is resolved immediately, but it does not matter. test one fails because I'm not waiting for the promise. It does not matter if I use Bluebird or Node's stock Promise implementation.
There may be circumstances under which test one will pass, but that's just luck because promises do not guarantee that it will work. This luck may change, if:
You switch to a different promise implementation.
You run on a different platform. Promise implementations have to work with that the various platforms give them. And may thus behave somewhat differently from platform to platform, which is fine, so long as it does not violate the specs. However, the behavior your initial code depended on is not guaranteed by the specs so it may not be maintained on all platforms.
A new version of the promise implementation you use is released and no longer maintains the behavior you were relying on.
Is is possible that on my machine and CI, Mocha uses different promise implementations?
Looking at Mocha's code I do not see any location where Mocha instantiate promises. It detects whether it returns a promise and depends on the API that promises provide but it does not create its own promises.
Is there a way to force promise implementation for Mocha?
See above. It receives the promises you return so it uses whatever implementation you use in your test suite.
Maybe the changed Promise comes from another place in the code?
Unsure what you mean there.
We are using Node for developing and 95% of code is Async, working fine.
For some 5% (one small module), which is sync in nature [and depends on other third party software],
and we are looking for
1. "Code to block until call back is finished"
2. At a time only one instance of function1 + its callback should be executed.
PS 1: I do completely agree, Node is for async work, We should avoid that, but this is separate non-realtime process.
PS 2: If not with Node any other Serverside JS framework? Last option is to use other lang like python, but if anything in JS possible, we are ready to give it a shot!
SEQ should solve your problem.
For an overview about sync modules please look at http://nodejsrocks.blogspot.de/2012/05/how-to-avoid-nodejs-spaghetti-code-with.html
Seq()
.seq(function () {
mysql.query("select * from foo",[], function(err,rows,fields) {
this(null, rows);
});
})
.seq(function(mysqlResult) {
console.log("mysql callback returnes:"+mysqlResult);
})
There are lots and lots of options, look at node-async, kaffeine async support, IcedCoffeescript, etc.
I want to make a plug for IcedCoffeeScript since I'm its maintainer. You can get by with solutions like Seq, but in general you'll wind up encoding control flow with function calls. I find that approach difficult to write and maintain. IcedCoffeeScript makes simple sequential operations a breeze:
console.log "hello, just wait a sec"
await setTimeout defer(), 100
console.log "ok, what did you want"
But more important, it handles any combination of async code and standard control flow:
console.log "Let me check..."
if isRunningLate()
console.log "Can't stop now, sorry!"
else
await setTimeout defer(), 1000
console.log "happy to wait, now what did you want?"
resumeWhatIWasDoingBefore()
Also loops work well, here is serial dispatch:
for i in [0...10]
await launchRpc defer res[i]
done()
And here is parallel dispatch:
await
for i in [0...10]
launchRpc defer res[i]
done()
Not only does ICS make sequential chains of async code smoother, it also encourages you to do as much as possible in parallel. If you need to change your code or your concurrency requirements, the changes are minimal, not a complete rewrite (as it would be in standard JS/CS or with some concurrency libraries).