timeout in Jasmine of JS learning

Recently, I was crashed by the asynchronous timeout in Jasmine. The specific problem is setTimeout, which sometimes causes the test case to time out, and sometimes does not wait for enough time. So I decided to study the usage of asynchronous timeout in Jasmine.

First, look at the example given by the jasmine documentation:

describe("long asynchronous specs", function() {
    var originalTimeout;
    beforeEach(function() {
        originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
    });

    it("testTimeout", function(done) {
        setTimeout(function() {
            done();
        }, 9000);
    });

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

This example is very simple. When running the use case testTimeout, it paused for about 9 seconds. The test result is:

SPEC HAS NO EXPECTATIONS testTimeout

This result is quite normal, because there is no test expectation in the test case, if you add the expect(1).toEqual(1); statement, the above information will not be prompted.

Next, write an example following the above code:

describe("TimeOutTest", function() {
    var value = 0;

    beforeEach(function() {
        jasmine.clock().install();
    });

    afterEach(function() {
        jasmine.clock().uninstall();
    });

    it("testTimeout", function(done) {
        console.log("start testTimeout ...");
        expect(value).toEqual(0);
        setTimeout(function() {
            console.log("timeout callback");
            value++;
            done();
        }, 2000);

        console.log("after timeout");
        expect(value).toEqual(1);
    });
});

But the result is unexpected, there are two errors:

  1. expect(value).toEqual(1); This sentence failed, and the value of value is 0 at this time. If you think about it carefully, the value is indeed 0, because although the setTimeout function sets a timeout callback, the function itself will not block here, but will continue to execute.
  2. Prompt error:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

This error is somewhat incomprehensible. It is similar to the code in the previous example. Why does this not call back to the timeout callback? If the callback is executed and done() is executed; the above timeout error will not occur.

Study the jasmine example again, and modify the above example as follows:

describe("TimeOutTest", function() {
    var value = 0;

    beforeEach(function() {
        jasmine.clock().install();
    });

    afterEach(function() {
        jasmine.clock().uninstall();
    });

    it("testTick", function(done) {
        console.log("start testTick ...");
        expect(value).toEqual(0);
        setTimeout(function() {
            console.log("timeout callback");
            value++;
            done();
        }, 2000);

        console.log("after timeout");
        jasmine.clock().tick(2001);
        expect(value).toEqual(1);
    });
});

The test case runs correctly this time. The secret lies in the introduction of the jasmine.clock().tick() function. This function will have two consequences:

  1. It will block the execution of javascript code, which is equivalent to the sleep function in C program.
  2. After the timeout, call back to the callback set in setTimeout. In the above example, value++ will be executed, so the test of expect(value).toEqual(1); is passed.

Looking back at the second example, where is the problem? The reason is that jasmine.clock().install(); This sentence, it will actually rewrite the system's setTimeout function, it will wait for a period of time to pass synchronously, at this time you need to use jasmine.clock().tick() Come to sleep for a while. Without this line, the test case waits until the jasmine.DEFAULT_TIMEOUT_INTERVAL times out. What happens if jasmine.clock().tick(2001); is changed to a value less than 2000 in the third example? The answer is that jasmine.DEFAULT_TIMEOUT_INTERVAL timeout occurs, that is, the waiting time is not long enough to trigger setTimeout timeout.

Summarize:

  1. jasmine.clock().install()/jasmine.clock().uninstall() should be used in conjunction with jasmine.clock().tick().

The complete code above can refer to my project on github jsdemo.

Tags: Javascript Front-end unit testing

Posted by shanksta13 on Mon, 12 Dec 2022 14:21:41 +0300