When attempting to simulate a response to a JSONP GET request using a function that returns an ES6 promise wrapped in $q.when()
, everything seems to be working fine. However, during unit testing, the request isn't intercepted by $httpBackend and goes directly to the actual URL. As a result, when flush()
is triggered, an error message saying
Error: No pending request to flush !
is displayed. The JSONP request is performed through jQuery's $.getJSON()
within the ES6 promise, prompting the use of a regex instead of a fixed URL to capture all outgoing requests.
I've spent quite some time trying to troubleshoot this issue and can't seem to grasp why the call is bypassing $httpBackend. It feels like the HTTP request within the ES6 promise is being executed "outside of Angular", causing $httpBackend to not recognize or intercept it. This might not have been the case if the call was made within a $q promise from the beginning. Could someone shed light on why this behavior is happening and why a simple timeout workaround works seamlessly? I've experimented with various combinations of $scope.$apply
, $scope.$digest
, and $httpBackend.flush()
without success.
Perhaps reviewing some code snippets will offer clarification...
Controller
function homeController() {
...
var self = this;
self.getData = function getData() {
$q.when(user.getUserInformation()).then(function() {
self.username = user.username;
});
};
}
Unit Test
...
beforeEach(module('home'));
describe('Controller', function() {
var $httpBackend, scope, ctrl;
beforeEach(inject(function(_$httpBackend_, $rootScope, $componentController) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new(); // attempted to invoke $digest or $apply
// tried different approaches like whenGET, when('GET', ..), etc...
$httpBackend.whenJSONP(/.*/)
.respond([
{
"user_information": {
"username": "TestUser",
}
}
]);
ctrl = $componentController("home");
}));
it("should add the username to the controller", function() {
ctrl.getData(); // trigger HTTP request
$httpBackend.flush(); // Error: No pending request to flush !
expect(ctrl.username).toBe("TestUser");
});
});
...
Strangely enough, the following workaround does work:
it("should add the username to the controller", function() {
ctrl.getData(); // trigger HTTP request
setTimeout(() => {
// no need to call flush, $digest, or $apply...?
expect(ctrl.username).toBe("TestUser");
});
});