diff --git a/src/ng/sniffer.js b/src/ng/sniffer.js index 8023bd8722ab..f65c45f57181 100644 --- a/src/ng/sniffer.js +++ b/src/ng/sniffer.js @@ -21,8 +21,13 @@ function $SnifferProvider() { this.$get = ['$window', '$document', function($window, $document) { var eventSupport = {}, // Chrome Packaged Apps are not allowed to access `history.pushState`. They can be detected by - // the presence of `chrome.app.runtime` (see https://developer.chrome.com/apps/api_index) - isChromePackagedApp = $window.chrome && $window.chrome.app && $window.chrome.app.runtime, + // the presence of `chrome.app.runtime` (see https://developer.chrome.com/apps/api_index). + // For sandboxed apps, check for an extension runtime ID, but no access to other Chrome + // runtime APIs. See https://developer.chrome.com/apps/manifest/sandbox + isChromePackagedApp = + $window.chrome && + ($window.chrome.app && $window.chrome.app.runtime || + !$window.chrome.app && $window.chrome.runtime && $window.chrome.runtime.id), hasHistoryPushState = !isChromePackagedApp && $window.history && $window.history.pushState, android = toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]), diff --git a/test/ng/snifferSpec.js b/test/ng/snifferSpec.js index dd52de11ff29..46db283b06aa 100644 --- a/test/ng/snifferSpec.js +++ b/test/ng/snifferSpec.js @@ -90,6 +90,26 @@ describe('$sniffer', function() { expect(pushStateAccessCount).toBe(0); }); + + it('should not try to access `history.pushState` in sandbox Chrome Packaged Apps', function() { + var pushStateAccessCount = 0; + + var mockHistory = Object.create(Object.prototype, { + pushState: {get: function() { pushStateAccessCount++; return noop; }} + }); + var mockWindow = { + chrome: { + runtime: { + id: 'x' + } + }, + history: mockHistory + }; + + sniffer(mockWindow); + + expect(pushStateAccessCount).toBe(0); + }); });