Spec for async functions using Jasmine

2019-07-04 07:19发布

问题:

When I'm trying to test _.debounce function like in this qunit test using jasmine something strange happens.

Seems like it could be tested using jasmine.Clock.useMock()... But when I write:

it('_.debounce()', function () {
    var spy = jasmine.createSpy('debounce'),
        debouncedSpy = _.debounce(spy, 100);

    jasmine.Clock.useMock();

    // direct calls
    debouncedSpy();
    debouncedSpy();
    debouncedSpy();

    // timed out calls
    setTimeout(debouncedSpy, 60);
    setTimeout(debouncedSpy, 120);
    setTimeout(debouncedSpy, 180);
    setTimeout(debouncedSpy, 240);
    setTimeout(debouncedSpy, 300);

    jasmine.Clock.tick(300);
    expect(spy).toHaveBeenCalled();

    jasmine.Clock.tick(400);
    expect(spy).toHaveBeenCalled();

    jasmine.Clock.tick(1000);
    expect(spy.callCount).toBe(1);
});

It doesn't work (call count is equal 3). But without direct calls (or when I'm using setTimeout(..., 0)) everything works fine. What I'm doing wrong?

Also I've try to do it through runs and waits, and it works. But why it doesn't work in previous example?

it('should be called once', function () {
    var spy = jasmine.createSpy('debounce'),
        debouncedSpy = _.debounce(spy, 100);

    runs(function () {
        debouncedSpy();
        debouncedSpy();
        debouncedSpy();

        expect(spy).not.toHaveBeenCalled();

        setTimeout(debouncedSpy, 60);
        setTimeout(debouncedSpy, 120);
        setTimeout(debouncedSpy, 180);
        setTimeout(debouncedSpy, 240);
        setTimeout(debouncedSpy, 300);
    });

    waits(800);

    runs(function () {
        expect(spy.callCount).toBe(1);
    });
});

回答1:

Until https://github.com/pivotal/jasmine/issues/361 and https://github.com/pivotal/jasmine/pull/455. are released, you add this to your tests to have Jasmine skip the debounce delay.

_.debounce = function (func) { return function () { func.apply(this, arguments);}; };


回答2:

The jasmine mock clock only changes the behavior of setTimeout and it's ilk, it currently doesn't mock out Date see https://github.com/pivotal/jasmine/issues/361 and https://github.com/pivotal/jasmine/pull/455. Using runs and waitsFor (or in jasmine 2.0 done callbacks), actually lets the time pass so the browser actually changes the Date value so the date math that happens inside debounce adds up.