fix($browser): detect changes to the browser url that happened in sync

Closes #6976.
This commit is contained in:
Tobias Bosch
2014-08-26 15:23:47 -07:00
parent 1812af58c2
commit 2ece4d0347
4 changed files with 43 additions and 4 deletions

View File

@@ -234,6 +234,13 @@ function Browser(window, document, $log, $sniffer) {
return callback;
};
/**
* Checks whether the url has changed outside of Angular.
* Needs to be exported to be able to check for changes that have been done in sync,
* as hashchange/popstate events fire in async.
*/
self.$$checkUrlChange = fireUrlChange;
//////////////////////////////////////////////////////////////
// Misc API
//////////////////////////////////////////////////////////////

View File

@@ -608,6 +608,8 @@ function $RootScopeProvider(){
logIdx, logMsg, asyncTask;
beginPhase('$digest');
// Check for changes to browser url that happened in sync before the call to $digest
$browser.$$checkUrlChange();
lastDirtyWatch = null;

View File

@@ -56,6 +56,8 @@ angular.mock.$Browser = function() {
return listener;
};
self.$$checkUrlChange = angular.noop;
self.cookieHash = {};
self.lastCookieHash = {};
self.deferredFns = [];

View File

@@ -36,7 +36,7 @@ function MockWindow() {
};
this.location = {
href: 'http://server',
href: 'http://server/',
replace: noop
};
@@ -414,7 +414,7 @@ describe('browser', function() {
expect(replaceState).not.toHaveBeenCalled();
expect(locationReplace).not.toHaveBeenCalled();
expect(fakeWindow.location.href).toEqual('http://server');
expect(fakeWindow.location.href).toEqual('http://server/');
});
it('should use history.replaceState when available', function() {
@@ -426,7 +426,7 @@ describe('browser', function() {
expect(pushState).not.toHaveBeenCalled();
expect(locationReplace).not.toHaveBeenCalled();
expect(fakeWindow.location.href).toEqual('http://server');
expect(fakeWindow.location.href).toEqual('http://server/');
});
it('should set location.href when pushState not available', function() {
@@ -448,7 +448,7 @@ describe('browser', function() {
expect(pushState).not.toHaveBeenCalled();
expect(replaceState).not.toHaveBeenCalled();
expect(fakeWindow.location.href).toEqual('http://server');
expect(fakeWindow.location.href).toEqual('http://server/');
});
it('should return $browser to allow chaining', function() {
@@ -615,4 +615,32 @@ describe('browser', function() {
expect(browser.baseHref()).toEqual('/base/path/');
});
});
describe('integration tests with $location', function() {
beforeEach(module(function($provide, $locationProvider) {
spyOn(fakeWindow.history, 'pushState').andCallFake(function(stateObj, title, newUrl) {
fakeWindow.location.href = newUrl;
});
$provide.value('$browser', browser);
browser.pollFns = [];
$locationProvider.html5Mode(true);
}));
it('should update $location when it was changed outside of Angular in sync '+
'before $digest was called', function() {
inject(function($rootScope, $location) {
fakeWindow.history.pushState(null, '', 'http://server/someTestHash');
// Verify that infinite digest reported in #6976 no longer occurs
expect(function() {
$rootScope.$digest();
}).not.toThrow();
expect($location.path()).toBe('/someTestHash');
});
});
});
});