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 the data
asynchronously.
But in the test1
, when I try to verify:
expect(data).toBe(something);
The data is undefined
, because getSomeDataFromRemote
has not finished yet.
How to fix it?
If an operation is asynchronous just because it relies on setTimeout or other time-based behavior, a good way to test it is to use Jasmine's mock clock to make it run synchronously. This type of test can be easier to write and will run faster than an asynchronous test that actually waits for time to pass.
Jasmine supports testing async code. We can test async code with: describe("Using callbacks", function () { beforeEach(function (done) { setTimeout(function () { value = 0; done(); }, 1); }); it("supports sequential execution of async code", function (done) { value++; expect(value). toBeGreaterThan(0); done(); }); });
JasmineJS - beforeEach() Advertisements. Another notable feature of Jasmine is before and after each function. Using these two functionalities, we can execute some pieces of code before and after execution of each spec. This functionality is very useful for running the common code in the application.
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
Jasmine 2.0
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With