What has been done () for and how to use it (protractor, jasmine)

it('should for something', function check(done) { browser.sleep(2000); $('.csTx').isPresent().then(function(result) { if(result) { done(); } else { xPage.clickBack(); check(done); } }) }, 30000); 

Can anyone explain how done () works and why it is needed. I was looking for her, but I can not find any information that would be easy enough to understand. I automate with a protractor and jasmine. consider the code above.

+6
source share
3 answers

You need to use done if your test creates a parallel TaskQueue in your test control flow (more on promises and control flow ).

For instance:

 describe('Control Flow', function() { function logFromPromise(text) { var deferred = protractor.promise.defer(); deferred.then(function() { console.log(text); }); deferred.fulfill(); return deferred; } it('multiple control flows', function() { setTimeout(function() { logFromPromise('1'); }); logFromPromise('0'); }); } 

The setTime call creates a parallel task queue in the control:

 ControlFlow | TaskQueue | | Task<Run fit("multiple control flows") in control flow> | | | TaskQueue | | | | Task <logFromPromise('0');> | TaskQueue | | Task <setTimeout> 

The protractor believes that the test is "completed" after 0 printed. In this example, 1 is likely to be printed after the test completes. To make the protractor wait for Task <setTimeout> , you need to call a ready-made function:

  it('multiple control flows', function(done) { setTimeout(function() { logFromPromise('1').then(function() { done(); }); }); logFromPromise('0'); }); 

If you can, let the protractor handle it when the test is "completed." Having parallel TaskQueues can lead to unexpected race conditions in your test.

+5
source

Here is a describe example that you can run and see what happens. I must mention that I am not using Protractor, so additional considerations may arise regarding its specific capabilities.

 describe('Done functionality', function(){ var echoInOneSecond = function(value){ console.log('creating promise for ', value); return new Promise(function(resolve, reject){ console.log('resolving with ', value); resolve(value); }); }; it('#1 this will untruly PASS', function(){ var p = echoInOneSecond('value #1'); p.then(function(value){ console.log('#1 expecting...and value is ', value); expect(value).toBe('value #1'); }); }); it('#2 this will NOT FAIL', function(){ var p = echoInOneSecond('value #2'); p.then(function(value){ console.log('#2 expecting... and value is ', value); expect(value).not.toBe('value #2'); }); }); it('3 = will truly FAIl', function(done){ var p = echoInOneSecond('value #3'); p.then(function(value){ console.log('#3 expecting... and value is ', value); expect(value).not.toBe('value #3'); done(); }); }); it('4 = this will truly PASS', function(done){ var p = echoInOneSecond('value #4'); p.then(function(value){ console.log('#4 expecting... and value is ', value); expect(value).toBe('value #4'); done(); }); }); }); 

when you start the test, you will notice the sequence: first promises # 1, # 2, # 3 will be created and resolved first. Please note that waiting for # 1 and # 2 will not start yet, since promises are resolved asynchronously.

Then, since test # 3 uses done , after creating promise # 3, the functions for then all previous promises are evaluated: you will see "# 1 waiting ..." and "# 2" waiting ... ", but jasmine does not care about that, because tests No. 1 and No. 2 have already been completed, and all that concerns their implementation: only after expectations No. 3 are made, and it really will fail, because jasmine really cares about everything that happens before it done done() .

And then you can observe the # 4 test of the normal flow - creating a promise, resolution, expectation, everything considered by jasmine, so the expectation will really pass.

+2
source

I did not use a protractor. As for Jasmine, I understand that done makes Jasmine wait, but not in the traditional sense of wait time. This is not like a timer that always works. I think that done acts as a checkpoint in Jasmine . When Jasmine sees that the specification uses done , he knows that he cannot go to the next step (say, start the next specification or mark this specification complete, that is, pronounce the verdict on the current specification) if the code for the leg containing done did not start.

For example, jasmine passes this specification even if it fails because it does not expect a call to setTimeout.

 fit('lets check done',()=>{ let i=0; setTimeout(function(){ console.log("in timeout"); expect(i).toBeTruthy();//the spec should fail as i is 0 but Jasmine passes it! },1000); //jasmine reaches this point and see there is no expectation so it passes the spec. It doesn't wait for the async setTimeout code to run }); 

But if I intend for Jasmine to expect asynchronous code in setTimeout , then I use done in asynchronous code

 fit('lets check done',(done)=>{ let i=0; setTimeout(function(){ console.log("in timeout"); expect(i).toBeTruthy();//with done, the spec now correctly fails with reason Expected 0 to be truthy. done();//this should make jasmine wait for this code leg to be called before declaring the verdict of this spec },1000); }); 

Note that done should be called where I want to validate the statements.

 fit('lets check done',(done)=>{ let i=0; setTimeout(function(){ console.log("in timeout"); expect(i).toBeTruthy();//done not used at the right place, so spec will incorrectly ypass again!. //done should have been called here as I am asserting in this code leg. },1000); done();//using done here is not right as this code leg will be hit inn normal execution of it. }); 

To summarize, imagine that everything is done as "Jasmine" - "I finished now" or "I will finish when this code appears"

0
source

Source: https://habr.com/ru/post/1264312/


All Articles