Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test asynchronous functionality in Jasmine 2.0.0 with done()

I am trying to implement a jasmine test on a simple promise implementation (asynchronous code) with the done() function and my test fails although the code being tested works perfectly fine. Can anyone please help me to figure out what is missing in my test?

 var Test = (function () {
    function Test(fn) {
        this.tool = null;
        fn(this.resolve.bind(this));
    }
    Test.prototype.then = function (cb) {
        this.callback = cb;
    };
    Test.prototype.resolve = function (value) {
        var me = this;
        setTimeout(function () {
            me.callback(value);
        }, 5000);
    };
    return Test;
})();

describe("setTimeout", function () {

    var test, newValue = false,
        originalTimeout;
    beforeEach(function (done) {
        originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;

        test = new Test(function (cb) {
            setTimeout(function () {
                cb();
            }, 5000);
        });
        test.then(function () {
            newValue = true;
            console.log(1, newValue);
            done();
        });
    });

    it("Should be true", function (done) {
        expect(1).toBe(1);

        expect(newValue).toBeTruthy();
    });

    afterEach(function () {
        jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
    });
});

the same test in jsfiddle: http://jsfiddle.net/ravitb/zsachqpg/

like image 919
Ravit Avatar asked Feb 09 '15 11:02

Ravit


People also ask

How do you test async in Jasmine?

You can check on the spied on function in . then of the async call. This is where you can use toHaveBeenCalled or toHaveBeenCalledWith to see if it was called. You should also check if the result of the promise is the expected output you want to see via the toEqual matcher.

What is done () in Jasmine?

If the function passed to Jasmine takes an argument (traditionally called done ), Jasmine will pass a function to be invoked when asynchronous work has been completed.

Does Jasmine support asynchronous operation?

Jasmine has a built-in way to handle async code and that's by the passed in done function in the test specs.

Does Jasmine support asynchronous operations Mcq?

Q: Does Jasmine support asynchronous operations? Ans: It's possible that the functions you supply to beforeAll, afterAll, beforeEach, and afterEach are asynchronous.


1 Answers

This code is testing a simple promise like object, so will call the Test object a promise for convenience.

There are two different async events after the promise creation: 1. The call to the .then() method 2. The resolving of the promise by calling the cb() function in the beforeEach() function.

In the real world these two can be called in any order and at any time.

For the test, the .then() call must be moved to the it() section's callback and all spec methods (e.g expect()) need to be called in it's callback or they'll run before it's resolved. The beforeEach() is part of the test setup while the it() function is the spec, the test itself.

The done() method needs to be called twice,

  1. When the beforeEach() async action is finished (i.e after the cb() is called), that will start running the spec. So it should look something like this:

      beforeEach(function (done) {
        test = new Test(function (cb) {
            setTimeout(function () {
                console.log("in beforeEach() | setTimeout()");
                cb(resolvedValue);
                done()
            }, 500);
        });
      });
    
  2. When the spec's (it() section's) async action is finished inside the .then() method after all calls to jasmine test methods, this will tell Jasmine the spec finished running (and so the time-out won't be reached). So:

    it("Should be " + resolvedValue, function (done) {
        test.then(function (value) {
            console.log("in then()");
            expect(value).toBe(resolvedValue);
            done();
        });      
    });
    

Also, as you can see instead of testing that a variable's value has changed I'm testing that the value passed to the .then() method is the same as the one passed to the promise resolve cb() function as that is the right behaviour you are expecting.

Here's an updated version of your fiddle.

You can check in the browser's console to see that all callbacks are being called

Note: Changing Jasmine's DEFAULT_TIMEOUT_INTERVAL just makes it more convoluted for no reason, so I removed it and some extraneous code.

like image 72
Lior Avatar answered Jan 02 '23 07:01

Lior