19

I'm getting acquainted with Jasmine (http://pivotal.github.com/jasmine/) and found something rather baffling:

it("should be able to send a Ghost Request", function() {
  var api = fm.api_wrapper;

  api.sendGhostRequest(function(response) {
    console.dir('server says: ', response);
  });

  expect(true).toEqual(false);
});

Fails as expected.

However, moving the expect call inside the callback:

it("should be able to send a Ghost Request", function() {
  var api = fm.api_wrapper;

  api.sendGhostRequest(function(response) {
    console.dir('server says: ', response);
    expect(true).toEqual(false);
  });
});

Somehow passes :O

After some debugging: api.sendGhostRequest() does an asynchronous ajax request, and jasmine rushes past before the request has completed.

Hence the question:

How do I get jasmine to wait for ajax execution before ascertaining the test result?

Val Redchenko
  • 580
  • 1
  • 8
  • 20
  • 1
    With Jasmine 2.0 you just call it("desc",function(done){... done(); ...}). Just saying, because this thread is high in google results :) – pkopac Apr 12 '16 at 13:33

3 Answers3

15

Edit for Jasmine 2

Asynchronous tests have become much simpler in Jasmine 2. Any test that needs to handle asynchronous code can be written with a callback which will indicate the completion of the test. See the Jasmine 2 docs under the header Asynchronous Support

it('should be able to send a ghost request', (done) => {
    api.sendGhostRequest((response) => {
        console.log(`Server says ${response}`);
        expect(true).toEqual(false);
        done();
    });
});

Jasmine 1

Have a look at waitsFor() and runs() on the Jasmine site under the header Asynchronous Support.

Use of runs and waitsfor should force Jasmine to wait for the ajax call to finish or for some timeout.

The code would look like:

it("should be able to send a Ghost Request", function() {
    runs(function() {
        api.sendGhostRequest(function(response) {
            console.dir('server says: ', response);
            flag = true;
        });
    }, 500);

    waitsFor(function() {
        return flag;
    }, "Flag should be set", 750);

    runs(function() {
        expect(true).toEqual(false);
    });
}

In which case the expect would fail.

halfs13
  • 308
  • 2
  • 10
  • Cheers! Feel embarrassed, like I've just been RTFM-ed :) Works like a charm :) – Val Redchenko Feb 28 '13 at 17:47
  • What is the '500' at the end of the first runs()? – zkent Jan 08 '14 at 17:26
  • The 500 on the first runs is a timeout for the asynchronous action. Alternatively you could add a setTimeout after the api.sendGhostRequest call to provide an alternate case to execute on timeout. For example: setTimeout(function() { flag = true; }, 500); – halfs13 Jan 14 '14 at 18:50
  • 3
    broken link. moved here: http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support – Nathan Wallace May 15 '14 at 20:40
  • Jasmine 2 seems to have removed "waitsFor", and it's not at all clear to me what should be used instead :-( . It might be worth updating your answer with "Jasmine 1" and "Jasmine 2" sections, if you know the new approach? – Rich Sep 25 '17 at 10:20
4

As @pkopac commented, runs() and waitsFor() have been deprecated in v2 favour of using a done() callback as documented: https://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support

it("should be able to send a Ghost Request", function(done) {
    var api = fm.api_wrapper;

    var success = function(response) {
        console.dir('server says: ', response);
        expect(response).toEqual('test response')
        done();
    };

    api.sendGhostRequest(success);
});
ptim
  • 14,902
  • 10
  • 83
  • 103
  • `done` should be in function parameter to use. `it("should be able to send a Ghost Request", function(done) {` – Chase Choi Aug 18 '17 at 07:28
  • How do you wait for a condition to become true in the spec? i.e. what do I do if I want to wait for my app to work, but I don't have a "success" callback? Do I need to write my own "waitFor" polling loop? – Rich Sep 25 '17 at 10:22
1

Look into runs() and waitfor()

Specifically you can call waitfor to check that the callback has run in some fashion (maybe using a boolean as a check?) and then run the expect afterwards.

runs allows you to wait until the waitfor has completed.

async jasmine documentation

Ben McCormick
  • 25,260
  • 12
  • 52
  • 71