문제

I want to be thorough, so please bear with me, there's going to be a lot here. We have a remote logging service function that will send us some client-side information when we want to. Something like this:

callHome: function(message){
    var deferred, promise;
    try{
        if (someService.getRemoteLoggingEnabled())
        {
            //collect all the info into remoteLog
            promise = $http.post("Logging", remoteLog);
            wipeLog();
        }
        else
        {
            deferred = $q.defer();
            promise = deferred.promise;
            deferred.resolve();
        }
    }
    catch(error)
    {
        try{
            if (!promise)
            {
                deferred = $q.defer();
                promise = deferred.promise;
            }
            deferred.reject(error.message);
        }
        catch(e2){}
    }
    return promise;
}

This all works just fine when running it in the actual app. The problem comes when trying to write unit tests for it. I have tests for when remote logging isn't enabled and for when there is an error. Those look like this:

it ("should resolve the promise with nothing when remote logging is turned off", inject(function($rootScope) {
    remoteLoggingEnabled = false; //this is declared above a beforeEach that mocks getRemoteLoggingEnabled
    var successSpy = jasmine.createSpy("success");
    var failSpy = jasmine.createSpy("fail");
    var promise = loggingService.callHome("Hello World");
    promise.then(successSpy, failSpy);
    $rootScope.$digest();

    expect(successSpy).toHaveBeenCalledWith(undefined);
    expect(failSpy).not.toHaveBeenCalled();
}));
it ("should reject the promise when there is an error with the error message", inject(function($rootScope) {
    remoteLoggingEnabled = true;
    var successSpy = jasmine.createSpy("success");
    var failSpy = jasmine.createSpy("fail");
    //angular.toJson is called while it's gathering client-side info
    spyOn(angular, "toJson").andCallFake(function() {throw new Error("This is an error");}); 
    var promise = loggingService.callHome("Hello World");
    promise.then(successSpy, failSpy);
    $rootScope.$digest();

    expect(successSpy).not.toHaveBeenCalled();
    expect(failSpy).toHaveBeenCalledWith("This is an error");
}));

These work great. I next wanted to add tests for when it actually made the makes the request. I put together a test like this:

it ("should resolve the promise with the http info when it makes a successful request", inject(function($rootScope, $httpBackend) {
    remoteLoggingEnabled = true;
    var successSpy = jasmine.createSpy("success");
    var failSpy = jasmine.createSpy("fail");
    $httpBackend.expect("POST", new RegExp("Logging"), function(jsonStr){
        //not concerned about the actual payload
        return true;
    }).respond(200);
    var promise = loggingService.callHome("Hello World");
    promise.then(successSpy, failSpy);
    $httpBackend.flush();
    $rootScope.$digest();

    expect(successSpy).toHaveBeenCalledWith(/*http info*/);
    expect(failSpy).not.toHaveBeenCalled();
}));

However, this test just hangs. I stepped through the code and it gets stuck in the $rootScope.$digest() call of $httpBackend.flush(), specifically in this while loop:

      while(asyncQueue.length) {
        try {
          asyncTask = asyncQueue.shift();
          asyncTask.scope.$eval(asyncTask.expression);
        } catch (e) {
          clearPhase();
          $exceptionHandler(e);
        }
        lastDirtyWatch = null;
      }

I've inspected the asyncTask.expression as it loops through, but I can't find any pattern to what it's doing.

I'm still getting a grasp on promises and how to use them, so I hope there's just something fundamentally wrong I'm doing here. Any help would be much appreciated.

도움이 되었습니까?

해결책

The problem was just in the setup of my test (not shown as part of the question). This callHome function gets called anytime there is an Error via a decorated $exceptionHandler. There was an error during the test on callHome, so it got called again, and then just looped from there. I fixed that error, and now it all works just fine.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top