Angular unit testing $ interval for the "clock" directive

I have Angular directive "clock" and . I am trying to write unit test to see if the current hours interval is in the future (i.e.: 2 minutes on looking at element.text() ). I have a current time test, now I want to check if it will show the future through $interval.flush . It seems to me that $interval.flush does not advance the clock.

Is it possible to ask two answers:

  • How do I unit test if $interval works?
  • Why doesn't $interval.flush seem to promote Date() ?

I follow the recommendations of these posts:

A related post suggested using Jasmine mocks, which I think is no longer needed.

  • Testing the $ interval with Jasmine in PhantomJS

A similar problem:

HTML

  <mydatething format="EEEE, MMMM d" interval="1000" timezone="notused"></mydatething> 

DIRECTIVE

 myApp.directive('mydatething', ['$interval', 'dateFilter', function ($interval, dateFilter) { return { restrict: "AE", scope: { format: '@', interval: '@' }, template: '', // the template is the Date() output link: function (scope, element, attrs) { // scope expects format, interval and timezone var clockid; var clockinterval = scope.interval; var dateformat = scope.format; var clocktimezone = scope.timezone; // DOM update function function updateClock() { element.text(dateFilter(new Date(), dateformat)); } // Instantiate clock updateClock(); clockid = $interval(updateClock, clockinterval); // fixed // For cancelling scope.$on('$destroy', function () { $interval.cancel(clockid); }); // Separate listener for locale change, manually refresh clock format scope.$on('$localeChangeSuccess', function () { updateClock(); }) } }; }]); 

UNIT TEST

 describe("tsdate directive", function(){ var elem, scope, $interval, dateFilter; beforeEach(module('tsApp')); beforeEach(inject(function(_$rootScope_, _$interval_, _$compile_, _dateFilter_){ $compile = _$compile_; dateFilter = _dateFilter_; $interval = _$interval_; $rootScope = _$rootScope_; scope = $rootScope.$new(); elem = angular.element('<mydatething format="h:mm a" interval="15000"></mydatething>'); elem = $compile(elem)(scope); scope.$digest(); })); describe('on clock start', function() { it('to show the current date', function() { var currentdate = dateFilter(new Date(), elem.isolateScope().format); expect(elem.text()).toBe(currentdate); // this passes }); it('that it updates the clock', function() { var futurems = 120000; // 2 minutes var futuredate = dateFilter(new Date().getTime() + futurems, elem.isolateScope().format) $interval.flush(futurems); expect(elem.text()).toBe(futuredate); // this fails }); }); }); 

TERMINAL

 PhantomJS 1.9.8 (Mac OS X) mydatething directive on clock start that it updates the clock FAILED Expected '3:55' to be '3:57'. 

Console.log shows that futuredate var increases by 2 minutes, but elem.text() remains current.

+7
javascript angularjs unit-testing
source share
2 answers

NOTE BEFORE BEGINNING:

You have an error in your directory code. When you call $ interval, you pass the object to the function as the first parameter. No brackets.

 // Do this clockid = $interval(updateClock, clockinterval); // Not this clockid = $interval(updateClock(), clockinterval); 

See the difference on plunker

Secondly, calling $ interval.flush causes the interval to move forward milliseconds, but it does not affect the internal Javascript clock. Since you use Date to update the time on the watch, you always get the current time. Calling $ interval.flush can cause an interval to update the clock several times, but always sets it to the current time.

+4
source share

I think you might need to use $scope.$apply() after the $ interval to ensure that Angular is aware of this.

0
source share

All Articles