How to test a method in Jasmine if the code in `beforeEach` is asynchronous?
Solution 1
Just like the async stuff within an it
you can use the runs
and waitsFor
in your beforeEach:
define( 'Jasmine' , function () {
var data ;
beforeEach(function(){
runs( function () {
getSomeDataFromRemote(function(res){
data = res;
});
});
waitsFor(function () { return !!data; } , 'Timed out', 1000);
});
it("test1", function() {
runs( function () {
expect(data).toBe(something);
});
});
});
Although I'm going to assume that it's because this was test code I think you should probably have the getSomeDataFromRemote
call inside your it
as that's actually what you're testing ;)
You can see some larger examples in some tests I've written for an async API here: https://github.com/aaronpowell/db.js/blob/f8a1c331a20e14e286e3f21ff8cea8c2e3e57be6/tests/public/specs/open-db.js
Solution 2
Be careful because in the new Jasmine 2.0 this is going to change and it will be mocha style. You have to use done()
function in beforeEach()
and it()
. For example, imagine you want to test if a page exists and is not empty, in a LAMP server, using jQuery $.get
. First you need to add jQuery to the SpecRunner.html
file, and in your spec.js
file:
describe('The "index.php" should', function() {
var pageStatus;
var contents;
beforeEach(function (done) {
$.get('views/index.php', function (data, status) {
contents = data;
pageStatus = status;
done();
}).fail(function (object, status) {
pageStatus = status;
done();
});
});
it('exist', function(done) {
expect(status).toBe('success');
done();
});
it('have content', function(done) {
expect(contents).not.toBe('');
expect(contents).not.toBe(undefined);
done();
});
});
As you can see, you pass the function done()
as a parameter for beforeEach()
and it()
. When you run the test, it()
won't be launched until done()
has been called in beforeEach()
function, so you are not going to launch the expectations until you have the response from the server.
The page exists
If the page exists we capture the status and the data from the response of the server, and we call done()
. Then we check if the status is "success" and if the data is not empty or undefined.
The page does not exist
If the page does not exist we capture the status from the response of the server, and we call done()
. Then we check if the status is not "success" and if the data is empty or undefined (that must be because the file does not exist).
Solution 3
In this case I typically stub the asynchronous call to respond immediately.
I'm not sure if you've seen it or not, but here is some documentation about asynchronous testing with Jasmine.
Comments
-
Freewind about 2 years
I'm trying to write some tests with Jasmine, but now have a problem if there are some code is asynchronous in
beforeEach
.The sample code looks like:
describe("Jasmine", function() { var data ; beforeEach(function(){ console.log('Before each'); getSomeDataFromRemote(function(res){ data = res; }); }); it("test1", function() { expect(data).toBe(something); console.log('Test finished'); }); });
You can see, in the
beforeEach
, I want to get some data from remote, and assign it to thedata
asynchronously.But in the
test1
, when I try to verify:expect(data).toBe(something);
The data is
undefined
, becausegetSomeDataFromRemote
has not finished yet.How to fix it?
-
Freewind about 12 yearsI just checked your link, but still don't know how to do it in my case.
-
x1a4 about 12 yearsYou wrap your
getSomeDataFromRemote
call in aruns
function, as well as the expectations. You usewaits
to provide some timeout that's long enough before your expectation runs. It's fiddly for sure, and can cause random failures. This is why i just stub the call to return immediately. Sinon.js also provides some help in the ajax stubbing area if you prefer something further from the metal. -
Freewind about 12 yearsthank you,
runs
andwaitsFor
is exactly what I'm looking for. But since @Slace gave me an working and detail example, I have to accept his answer. Sorry~ -
snapfractalpop about 11 years@x1a4 when you say that id's "fiddly" and can cause "random failures", are you referring to the inherent race condition in using waits instead of waitsFor, or are you saying that runs, waits, and waitsFor functionality is buggy in jasmine?
-
x1a4 about 11 years@snapfractalpop the race condition
-
Joe Grund about 10 years
done()
also holds true for projects such as minijasminenode -
Kaicui about 9 yearsi found beforeAll does not support async style.the spec below will run before the beforeAll call the "done"
-
paulhhowells almost 9 yearsWhy is
done
passed into theit
functions and called? What could go wrong if they were omitted from theit
? -
Timbergus almost 9 yearsIt appears in Jasmine documentation. I'm doing some tests and it seems that if you use
done
, you stop the execution until you calldone()
. If you remove it from thebeforeEach
, the test fails because you launch theit
before resolving theGET
. It seems to have no effect in theit
. Here you have the example I have in GitHub. -
paulhhowells almost 9 yearsthanks @Timbergus, that is what I was wondering. Its clear to me how (& why)
done
is used withbeforeEach()
, it was the simultaneous use init()
that had me puzzled. -
Mehul Tandale about 8 yearswaitsFor and runs have been discontinued in Jasmine. Now on, You can use done(). Hope this helps - jasmine.github.io/2.0/…