4
votes

The changes to asynchronous testing in Jasmine 2.0 are great in many ways. However, I'm not sure I fully understand how to test asynchronous code when I have no way to bind a callback to the async methods.

How do I test against an unknown number of async events in Jasmine 2.0? Or parallel async events which do not provide a callback call.

In 1.3 I would do this:

describe("my spec", function () {
   it("should check the state of a variable after unknown number of async events", function () {

        // This will execute several async functions in parallel (more than 1).
        // Once they are all complete the 'window.done' variable will be set to "true".
        // This method does not provide a callback.
        fire_parallel_async_methods();

        waitsFor(function () {
            // I know that once this condition is met,
            // all the above async calls are done
            return window.done === true;
        });

        runs(function () {
            // Now I can run the rest of my unit tests
        });
   });
});

Is Tony's answer in Jasmine 2.0: refactoring out 1.3's runs() and waitsFor() the only solution?

Another use case is for event validation. For example:

describe("my spec", function () {
   it("should make sure event is fired", function () {

        // This element has an event binding on 'click' which changes its class.
        // In this test I want to check to make sure the event does the right thing.
        var $element = $('.some-element');

        // Simulate a click
        $element.simulate('click');
        // or $element.click();

        waitsFor(function () {
            // Once the event is done, the element should have a new 'after-event' class
            return $element.hasClass('after-event');
        });
   });
});

In this example, I have no way to access the event's binding, so I can't attach a callback to it. How would I validate this in Jasmine 2.0?

1
If you can't bind a callback to your async methods then you will probably just need to guess and set a timeout. Why don't you use an async library like Q in order to wrap all of your requests and know exactly when they finish?jraede
It's not an option in certain cases where the async events are all inside a third-party module (for example).Ev Haus
You could make a wrapper for that third-party process to make it play nicely with Q or a similar library. Otherwise there's nothing you can really do aside from using a timeout based on how long you think it would take.jraede

1 Answers

2
votes

I was able to find a workaround using timeouts, which mimics waitsFor() behaviour:

describe("my spec", function () {
   it("should make sure event is fired", function (done) {

        // This element has an event binding on 'click' which changes its class.
        // In this test I want to check to make sure the event does the right thing.
        var $element = $('.some-element');

        // Simulate a click
        $element.simulate('click');
        // or $element.click();

        // Set a timeout to wait for the async event to go through.
        // Pick a time here that will be enough. It's a little messy, but it works for cases
        // where you can't attach a callback. The hardest part is figuring out how long to set
        // the timeout for.
        setTimeout(function () {
            // Do your test here
            expect($element).toHaveClass('after-event');

            // Tell Jasmine the test is finished
            done();
        }, 500);
   });
});