Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test a method in Jasmine if the code in `beforeEach` is asynchronous?

Tags:

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?

like image 448
Freewind Avatar asked May 10 '12 04:05

Freewind


People also ask

How do you test async methods in Jasmine?

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.

How do I write a test case for setTimeout in Jasmine?

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(); }); });

What is beforeEach in Jasmine?

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.


2 Answers

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

like image 82
Aaron Powell Avatar answered Sep 19 '22 14:09

Aaron Powell


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).

like image 23
Timbergus Avatar answered Sep 18 '22 14:09

Timbergus