Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to unit-test setInterval in karma angularjs

app.directive('shuffleBlocks', function($timeout){
    return {
        link: function(sco,ele,att){
            if (itemCnt <= 1) return;

            /*Trigger function*/
            function triggerEvent(){
                ...
            }
            ele.bind('click', triggerEvent);

            setInterval(triggerEvent, 5000);
        }
    }
})

here I wrote the test

        var elem = '<div shuffle-blocks><div>';
        elem = mockCompile(elem)(rootScope.$new());
        setInterval(function(){
            expect(......).toBe(....)
        });

Obviously this is not the right method, does anyone know how to test $timeout and setInterval in karma?

like image 953
user2167582 Avatar asked Jan 13 '23 02:01

user2167582


1 Answers

UPDATE: The proper method of mocking setInterval in an angular 1.2+ application is to use angular's $interval service. Using the $interval service provides a number of benefits, but the one of most use in this situation is the $interval.flush() method. When writing tests, $interval exposes a .flush() method which allows you to mock the JS clock.

app.directive('shuffleBlocks', function($timeout, $interval){
    return {
        link: function(sco,ele,att){
            if (itemCnt <= 1) return;

            /*Trigger function*/
            function triggerEvent(){ ... }
            ele.bind('click', triggerEvent);

            $interval(triggerEvent, 5000);
        }
    }
});

and then in your unit test:

var elem = '<div shuffle-blocks><div>';
elem = mockCompile(elem)(rootScope.$new());
$interval.flush(5000); // flush accepts the # of ms to be flushed
expect(......).toBe(....);

Hope that's helpful to anyone who looks up this answer in the future. I'll leave my previous answer for those still using 1.1X.


Previous Answer: According the jasmine docs, you should be able to just use the jasmine.Clock.useMock() function to mock the typical javascript clock and manually work your way through the interval. Since angular is just wrapping the native setTimeout function, I'm quite positive it should allow this to work, though I haven't tested it to be sure.

The jasmine docs for version 1.3 are here. Here's the code example that demonstrates how it works.

beforeEach(function() {
    timerCallback = jasmine.createSpy('timerCallback');
    jasmine.Clock.useMock();
});

it("causes a timeout to be called synchronously", function() {
    setTimeout(function() {
        timerCallback();
    }, 100);

    expect(timerCallback).not.toHaveBeenCalled();

    jasmine.Clock.tick(101);

    expect(timerCallback).toHaveBeenCalled();
});

The only issue I see is that your triggerEvent() function is local to your link function, so I don't know how you'll be able to get to it to mock it. But hopefully that points you in the right direction. If not, sorry, I tried.

UPDATE: The syntax for mocking the clock has changed in Jasmine 2.0. If you are using 2.0, please see the updated docs here.

like image 149
tennisgent Avatar answered Jan 19 '23 03:01

tennisgent