Angular unit testing $interval for a "clock" directive

I have an Angular directive "clock" and I'm trying to write a unit test to see if the clock actually $interval advances to a future time (ie: 2 minutes by looking at element.text() ). I have a passing test of the current time, now I want to test if it will show a future time via $interval.flush . It appears to me $interval.flush isn't really advancing the clock.

Can I ask for two answers:

  • How do I unit test if $interval fires?
  • Why $interval.flush doesn't seem to advance the Date() ?
  • I'm following guidelines from these posts:

  • how to unit-test setInterval in karma angularjs

  • http://www.bradoncode.com/blog/2015/06/15/unit-testing-interval-angularls/

  • A related post suggested using Jasmine mocks, which I don't think is necessary anymore.

  • Testing a $interval with Jasmine in PhantomJS
  • A similar problem:

  • https://groups.google.com/forum/#!topic/angular/5TFvCa5m8n0
  • 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 reveals, the futuredate var is 2 minutes incremented, but that the elem.text() remains the current time.


    NOTE BEFORE I START:

    You have an error in your directive code. When calling $interval, you pass the function object as the first parameter. No parenthesis.

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

    See the difference on plunker

    Secondly, calling $interval.flush causes interval to move forward by the number of milliseconds, but it has not effect on the internal Javascript clock. Since you are using Date to update the time on the clock, you are always getting the current time. Calling $interval.flush may cause interval to update the clock a bunch of times, but it's always setting it to the current time.


    我认为你可能需要在$ interval之后使用$scope.$apply()来确保Angular知道它。

    链接地址: http://www.djcxy.com/p/87462.html

    上一篇: 我可以在节点js文件中指定es6吗?

    下一篇: 对于“时钟”指令,角单元测试$ interval