Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

WIP - feat($route): wait for resolves #15587

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions src/ngMock/angular-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,26 @@ angular.mock.$Browser = function() {
self.$$lastUrl = self.$$url; // used by url polling fn
self.pollFns = [];

// TODO(vojta): remove this temporary api
self.$$completeOutstandingRequest = angular.noop;
self.$$incOutstandingRequestCount = angular.noop;

// Testability API

var outstandingRequestCount = 0;
var outstandingRequestCallbacks = [];
self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
self.$$completeOutstandingRequest = function() {
outstandingRequestCount--;
if (!outstandingRequestCount) {
while (outstandingRequestCallbacks.length) {
outstandingRequestCallbacks.pop()();
}
}
};
self.notifyWhenNoOutstandingRequests = function(callback) {
if (outstandingRequestCount) {
outstandingRequestCallbacks.push(callback);
} else {
callback();
}
};

// register url polling fn

Expand Down Expand Up @@ -166,10 +182,6 @@ angular.mock.$Browser.prototype = {

state: function() {
return this.$$state;
},

notifyWhenNoOutstandingRequests: function(fn) {
fn();
}
};

Expand Down
19 changes: 15 additions & 4 deletions src/ngRoute/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
var isArray;
var isObject;
var isDefined;
var noop;

/**
* @ngdoc module
Expand Down Expand Up @@ -54,6 +55,7 @@ function $RouteProvider() {
isArray = angular.isArray;
isObject = angular.isObject;
isDefined = angular.isDefined;
noop = angular.noop;

function inherit(parent, extra) {
return angular.extend(Object.create(parent), extra);
Expand Down Expand Up @@ -350,7 +352,8 @@ function $RouteProvider() {
'$injector',
'$templateRequest',
'$sce',
function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce) {
'$browser',
function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce, $browser) {

/**
* @ngdoc service
Expand Down Expand Up @@ -677,9 +680,10 @@ function $RouteProvider() {
} else if (nextRoute || lastRoute) {
forceReload = false;
$route.current = nextRoute;

var nextRoutePromise = $q.resolve(nextRoute);

$browser.$$incOutstandingRequestCount();

nextRoutePromise.
then(getRedirectionData).
then(handlePossibleRedirection).
Expand All @@ -693,17 +697,24 @@ function $RouteProvider() {
nextRoute.locals = locals;
angular.copy(nextRoute.params, $routeParams);
}

$rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
}
});
}).catch(function(error) {
}).
catch(function(error) {
if (nextRoute === $route.current) {
$rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error);
}
});
}).
finally(decrementRequestCount);
}
}

function decrementRequestCount() {
$browser.$$completeOutstandingRequest(noop);
}

function getRedirectionData(route) {
var data = {
route: route,
Expand Down
9 changes: 9 additions & 0 deletions test/e2e/fixtures/ng-route-promise/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html ng-app="lettersApp">
<body>
<ng-view></ng-view>

<script src="angular.js"></script>
<script src="angular-route.js"></script>
<script src="script.js"></script>
</body>
</html>
25 changes: 25 additions & 0 deletions test/e2e/fixtures/ng-route-promise/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

angular.
module('lettersApp', ['ngRoute']).
config(function($routeProvider) {
$routeProvider.
when('/foo', {
resolveRedirectTo: function($q) {
return $q(function(resolve) {
window.setTimeout(resolve, 1000, '/bar');
});
}
}).
when('/bar', {
template: '<ul><li ng-repeat="letter in $resolve.letters">{{ letter }}</li></ul>',
resolve: {
letters: function($q) {
return $q(function(resolve) {
window.setTimeout(resolve, 1000, ['a', 'b', 'c', 'd', 'e']);
});
}
}
}).
otherwise('/foo');
});
36 changes: 36 additions & 0 deletions test/e2e/tests/ng-route-promise.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

describe('ngRoute promises', function() {
beforeEach(function() {
loadFixture('ng-route-promise');
});

it('should wait for promises in resolve blocks', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

description needs to be updated

expect(element.all(by.tagName('li')).count()).toBe(5);
});

it('should time out if the promise takes long enough', function() {
// Don't try this at home kids, I'm a protractor dev
browser.manage().timeouts().setScriptTimeout(1500);

browser.waitForAngular().
then(onUnexpectedSuccess, onExpectedFailure).
then(restoreTimeoutLimit);

// Helpers
function onUnexpectedSuccess() {
fail('waitForAngular() should have timed out, but didn\'t');
}

function onExpectedFailure(error) {
expect(error.message).toContain(
'Timed out waiting for asynchronous Angular tasks to finish after');
}

function restoreTimeoutLimit() {
return browser.getProcessedConfig().then(function(config) {
browser.manage().timeouts().setScriptTimeout(config.allScriptsTimeout);
});
}
});
});
54 changes: 54 additions & 0 deletions test/ngRoute/routeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2082,4 +2082,58 @@ describe('$route', function() {
expect(function() { $route.updateParams(); }).toThrowMinErr('ngRoute', 'norout');
}));
});

describe('testability', function() {
it('should wait for route promises before calling callbacks', function() {
var deferred;

module(function($provide, $routeProvider) {
$routeProvider.when('/path', { template: '', resolve: {
a: function($q) {
deferred = $q.defer();
return deferred.promise;
}
} });
});

inject(function($location, $route, $rootScope, $httpBackend, $$testability) {
$location.path('/path');
$rootScope.$digest();

var callback = jasmine.createSpy('callback');
$$testability.whenStable(callback);
expect(callback).not.toHaveBeenCalled();

deferred.resolve();
$rootScope.$digest();
expect(callback).toHaveBeenCalled();
});
});

it('should call callback after route promises are rejected', function() {
var deferred;

module(function($provide, $routeProvider) {
$routeProvider.when('/path', { template: '', resolve: {
a: function($q) {
deferred = $q.defer();
return deferred.promise;
}
} });
});

inject(function($location, $route, $rootScope, $httpBackend, $$testability) {
$location.path('/path');
$rootScope.$digest();

var callback = jasmine.createSpy('callback');
$$testability.whenStable(callback);
expect(callback).not.toHaveBeenCalled();

deferred.reject();
$rootScope.$digest();
expect(callback).toHaveBeenCalled();
});
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs test for resolveRedirectTo

});