问题
My UserManager service automatically fires a $http POST every hour to refresh the user access token.
I'm trying to mock that call to verify that the token is being refreshed, but when I try to flush the $httpbackend I get an error saying 'No pending requests to flush' even though I know that the refresh function has been called (added a console.log just to verify).
Either the fact that the function is being called through a setTimeOut is effecting the $httpbackend or I'm missing something else.
Code attached bellow:
describe("UserManager Service Testing", function() {
beforeEach(angular.mock.module('WebApp'));
beforeEach(inject(function($httpBackend) {
window.apiUrls = jQuery.parseJSON('{"cover_art": "http://myrockpack.com/ws/cover_art/?locale=en-us", "channel_search_terms": "http://myrockpack.com/ws/complete/channels/?locale=en-us", "register": "http://myrockpack.com/ws/register/", "categories": "http://myrockpack.com/ws/categories/?locale=en-us", "reset_password": "http://myrockpack.com/ws/reset-password/", "share_url": "http://myrockpack.com/ws/share/link/", "video_search": "http://myrockpack.com/ws/search/videos/?locale=en-us", "channel_search": "http://myrockpack.com/ws/search/channels/?locale=en-us", "video_search_terms": "http://myrockpack.com/ws/complete/videos/?locale=en-us", "popular_channels": "http://myrockpack.com/ws/channels/?locale=en-us", "popular_videos": "http://myrockpack.com/ws/videos/?locale=en-us", "login": "http://myrockpack.com/ws/login/", "login_register_external": "http://myrockpack.com/ws/login/external/", "refresh_token": "http://myrockpack.com/ws/token/"}');
var mockLogin = {"token_type":"Bearer","user_id":"oCRwcy5MRIiWmsJjvbFbHA","access_token":"752a4f939662846a787a1474ad17ffddcd816dc7AAFB1G7HvgH-0qAkcHMuTESIlprCY72xWxyiuhySCpFJxKVYqOx9W7Gt","resource_url":"http://myrockpack.com/ws/oCRwcy5MRIiWmsJjvbFbHA/","expires_in":2,"refresh_token":"fa2f47f3590240e4bdfdbde03bf8042d"}
var refreshToken = {"token_type":"Bearer","user_id":"CeGfSz6dQW2ga2P2tKb3Bg","access_token":"ef235de46dba53ba69ed049f57496ec902da5d28AAFB1HdeTE-2vwnhn0s-nUFtoGtj9rSm9waiuhySCpFJxKVYqOx9W7Gt","resource_url":"http://myrockpack.com/ws/CeGfSz6dQW2ga2P2tKb3Bg/","expires_in":3600,"refresh_token":"873e06747d964a0d80f79181c98aceac"};
$httpBackend.when('POST', window.apiUrls.refresh_token).respond(refreshToken);
$httpBackend.when('POST', window.apiUrls.login).respond(mockLogin);
}));
it('UserManager should refresh the token after 2 seconds', inject(function(UserManager, $httpBackend) {
UserManager.oauth.Login('gtest','qweqwe');
$httpBackend.flush();
waits(4000);
$httpBackend.flush();
expect(UserManager.oauth.credentials.access_token).toEqual('ef235de46dba53ba69ed049f57496ec902da5d28AAFB1HdeTE-2vwnhn0s-nUFtoGtj9rSm9waiuhySCpFJxKVYqOx9W7Gt');
}));
});
回答1:
There is a discussion about this here. "Since promises are async you need to do $rootScope.$digest() in your tests to get them going"
add this before your $httpBackend.flush():
if(!$rootScope.$$phase) {
$rootScope.$apply();
}
so your code becomes:
it('UserManager should refresh the token after 2 seconds', inject(function(UserManager, $httpBackend) {
UserManager.oauth.Login('gtest','qweqwe');
if(!$rootScope.$$phase) {
$rootScope.$apply();
}
$httpBackend.flush();
expect(UserManager.oauth.credentials.access_token).toEqual('ef235de46dba53ba69ed049f57496ec902da5d28AAFB1HdeTE-2vwnhn0s-nUFtoGtj9rSm9waiuhySCpFJxKVYqOx9W7Gt');
}));
回答2:
I guess you have to wrap the code below the waits inside a runs(...) block. Otherwise your code is executed immediately before the waiting has been finished
waits(4000);
runs(function() {
$httpBackend.flush();
expect(UserManager.oauth.credentials.access_token).toEqual('ef235de46dba53ba69ed049f57496ec902 da5d28AAFB1HdeTE-2vwnhn0s-nUFtoGtj9rSm9waiuhySCpFJxKVYqOx9W7Gt');
});
It's described in the jasmine docs as well: https://github.com/pivotal/jasmine/wiki/Asynchronous-specs
回答3:
Your first $httpBackend.flush() flushes all the pending requests that you defined in your beforeEach().
When you call $httpBackend.flush() a second time, there are no pending requests, so you get the message.
You need to add another event(s) after the first flush.
Untested, but that's my theory.
回答4:
So with my jasmine tests all the time sometimes I have had to use regex to make the url a little less specific, most of this has been with angular wanting to strip trailing slashes or other stupid little things. Such as the request url wouldn't find the expect request but the regex below would.
https://qa.com/sessions/5cdec5bde6a242dca2cf5dd0ff7be2c9
/(qa.com\/sessions\/5cdec5bde6a242dca2cf5dd0ff7be2c9)/g
来源:https://stackoverflow.com/questions/17573817/angularjs-testing-jasmine-http-returning-no-pending-request-to-flush