diff --git a/ads/google/a4a/test/test-utils.js b/ads/google/a4a/test/test-utils.js index ac148fa71446..2045bb376b84 100644 --- a/ads/google/a4a/test/test-utils.js +++ b/ads/google/a4a/test/test-utils.js @@ -66,7 +66,7 @@ function setupForAdTesting(fixture) { // functions. function noopMethods( impl, - doc, + ampdoc, sandbox, pageLayoutBox = { top: 11, @@ -81,7 +81,7 @@ function noopMethods( impl.element.build = noop; impl.element.getPlaceholder = noop; impl.element.createPlaceholder = noop; - sandbox.stub(impl, 'getAmpDoc').returns(doc); + sandbox.stub(impl, 'getAmpDoc').returns(ampdoc); sandbox.stub(impl, 'getPageLayoutBox').returns(pageLayoutBox); } @@ -331,7 +331,7 @@ describe('Google A4A utils', () => { 'height': '50', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); return fixture.addElement(elem).then(() => { return googleAdUrl(impl, '', 0, [], []).then(url1 => { expect(url1).to.match(/ady=11/); @@ -352,7 +352,7 @@ describe('Google A4A utils', () => { 'height': '50', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); const getRect = () => { return {'width': 100, 'height': 200}; }; @@ -385,7 +385,7 @@ describe('Google A4A utils', () => { 'data-experiment-id': '123,456', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); return fixture.addElement(elem).then(() => { return googleAdUrl(impl, '', 0, {}, ['789', '098']).then(url1 => { expect(url1).to.match(/eid=123%2C456%2C789%2C098/); @@ -405,7 +405,7 @@ describe('Google A4A utils', () => { 'height': '50', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); impl.win.AMP_CONFIG = {type: 'production'}; impl.win.location.hash = 'foo,deid=123456,654321,bar'; return fixture.addElement(elem).then(() => { @@ -427,7 +427,7 @@ describe('Google A4A utils', () => { 'height': '50', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); impl.win.gaGlobal = {cid: 'foo', hid: 'bar'}; return fixture.addElement(elem).then(() => { return googleAdUrl(impl, '', 0, [], []).then(url => { @@ -449,7 +449,7 @@ describe('Google A4A utils', () => { 'height': '50', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); const createElementStub = sandbox.stub( impl.win.document, 'createElement' @@ -478,7 +478,7 @@ describe('Google A4A utils', () => { 'height': '50', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); const createElementStub = sandbox.stub( impl.win.document, 'createElement' @@ -505,7 +505,7 @@ describe('Google A4A utils', () => { 'height': '50', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); impl.win.SVGElement = undefined; const createElementStub = sandbox.stub( impl.win.document, @@ -535,7 +535,7 @@ describe('Google A4A utils', () => { 'height': '50', }); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); sandbox .stub(Services.viewerForDoc(impl.getAmpDoc()), 'getReferrerUrl') .returns(new Promise(() => {})); @@ -564,7 +564,7 @@ describe('Google A4A utils', () => { doc.win = fixture.win; const elem = createElementWithAttributes(doc, 'amp-a4a', {}); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox); + noopMethods(impl, fixture.ampdoc, sandbox); return fixture.addElement(elem).then(() => { return googleAdUrl(impl, '', Date.now(), [], []).then(url => { expect(url).to.match(/[&?]bdt=[1-9][0-9]*[&$]/); @@ -580,7 +580,7 @@ describe('Google A4A utils', () => { doc.win = fixture.win; const elem = createElementWithAttributes(doc, 'amp-a4a', {}); const impl = new MockA4AImpl(elem); - noopMethods(impl, doc, sandbox, { + noopMethods(impl, fixture.ampdoc, sandbox, { top: 0, left: 0, right: 0, @@ -902,6 +902,7 @@ describe('Google A4A utils', () => { describe('variables for amp-analytics', () => { let a4a; let sandbox; + let ampdoc; beforeEach(() => { sandbox = sinon.sandbox; @@ -913,7 +914,8 @@ describe('Google A4A utils', () => { 'type': 'adsense', 'data-amp-slot-index': '4', }); - element.getAmpDoc = () => fixture.doc; + ampdoc = fixture.ampdoc; + element.getAmpDoc = () => ampdoc; a4a = new MockA4AImpl(element); }); }); @@ -957,9 +959,7 @@ describe('Google A4A utils', () => { }); it('should include viewer lastVisibleTime', () => { - const getLastVisibleTime = () => 300; - const viewerStub = sandbox.stub(Services, 'viewerForDoc'); - viewerStub.returns({getLastVisibleTime}); + sandbox.stub(ampdoc, 'getLastVisibleTime').returns(300); const vars = getCsiAmpAnalyticsVariables('trigger', a4a, null); expect(vars['viewerLastVisibleTime']).to.be.a('number'); diff --git a/ads/google/a4a/traffic-experiments.js b/ads/google/a4a/traffic-experiments.js index a1c8947269d6..3bd5155317c6 100644 --- a/ads/google/a4a/traffic-experiments.js +++ b/ads/google/a4a/traffic-experiments.js @@ -55,7 +55,7 @@ export const SINGLE_PASS_EXPERIMENT_IDS = { */ export function extractUrlExperimentId(win, element) { const expParam = - Services.viewerForDoc(element).getParam('exp') || + Services.ampdoc(element).getParam('exp') || parseQueryString(win.location.search)['exp']; if (!expParam) { return null; diff --git a/ads/google/a4a/utils.js b/ads/google/a4a/utils.js index 7258ff80c2ca..2905f21cc9fb 100644 --- a/ads/google/a4a/utils.js +++ b/ads/google/a4a/utils.js @@ -299,7 +299,7 @@ export function googlePageParameters(a4a, startTime) { const viewport = Services.viewportForDoc(ampDoc); const viewportRect = viewport.getRect(); const viewportSize = viewport.getSize(); - const visibilityState = Services.viewerForDoc(ampDoc).getVisibilityState(); + const visibilityState = ampDoc.getVisibilityState(); return { 'is_amp': a4a.isXhrAllowed() ? AmpAdImplementation.AMP_AD_XHR_TO_IFRAME_OR_AMP @@ -626,12 +626,11 @@ export function getCsiAmpAnalyticsConfig() { export function getCsiAmpAnalyticsVariables(analyticsTrigger, a4a, qqid) { const {win} = a4a; const ampdoc = a4a.getAmpDoc(); - const viewer = Services.viewerForDoc(ampdoc); const navStart = getNavigationTiming(win, 'navigationStart'); const vars = /** @type {!JsonObject} */ ({ 'correlator': getCorrelator(win, ampdoc), 'slotId': a4a.element.getAttribute('data-amp-slot-index'), - 'viewerLastVisibleTime': viewer.getLastVisibleTime() - navStart, + 'viewerLastVisibleTime': ampdoc.getLastVisibleTime() - navStart, }); if (qqid) { vars['qqid'] = qqid; diff --git a/builtins/amp-pixel.js b/builtins/amp-pixel.js index 60c147bb7e2f..629d3924fc8b 100644 --- a/builtins/amp-pixel.js +++ b/builtins/amp-pixel.js @@ -65,8 +65,9 @@ export class AmpPixel extends BaseElement { return; } // Trigger, but only when visible. - const viewer = Services.viewerForDoc(this.getAmpDoc()); - viewer.whenFirstVisible().then(this.trigger_.bind(this)); + this.getAmpDoc() + .whenFirstVisible() + .then(this.trigger_.bind(this)); } /** diff --git a/extensions/amp-a4a/0.1/amp-a4a.js b/extensions/amp-a4a/0.1/amp-a4a.js index 3316a27bff6c..57eca3b4e021 100644 --- a/extensions/amp-a4a/0.1/amp-a4a.js +++ b/extensions/amp-a4a/0.1/amp-a4a.js @@ -387,7 +387,7 @@ export class AmpA4A extends AMP.BaseElement { this.uiHandler = new AMP.AmpAdUIHandler(this); const verifier = signatureVerifierFor(this.win); - this.keysetPromise_ = Services.viewerForDoc(this.getAmpDoc()) + this.keysetPromise_ = this.getAmpDoc() .whenFirstVisible() .then(() => { this.getSigningServiceNames().forEach(signingServiceName => { @@ -632,7 +632,7 @@ export class AmpA4A extends AMP.BaseElement { // - Rendering fails => return false // - Chain cancelled => don't return; drop error // - Uncaught error otherwise => don't return; percolate error up - this.adPromise_ = Services.viewerForDoc(this.getAmpDoc()) + this.adPromise_ = this.getAmpDoc() .whenFirstVisible() .then(() => { checkStillCurrent(); @@ -997,7 +997,7 @@ export class AmpA4A extends AMP.BaseElement { this.isRelayoutNeededFlag = true; this.getResource().layoutCanceled(); // Only Require relayout after page visible - Services.viewerForDoc(this.getAmpDoc()) + this.getAmpDoc() .whenNextVisible() .then(() => { Services.ownersForDoc(this.getAmpDoc())./*OK*/ requireLayout( diff --git a/extensions/amp-a4a/0.1/amp-ad-network-base.js b/extensions/amp-a4a/0.1/amp-ad-network-base.js index 98b2c6561159..cbb2aa13d65e 100644 --- a/extensions/amp-a4a/0.1/amp-ad-network-base.js +++ b/extensions/amp-a4a/0.1/amp-ad-network-base.js @@ -15,7 +15,6 @@ */ import {FailureType, RecoveryModeType} from './amp-ad-type-defs'; -import {Services} from '../../../src/services'; import {dev, devAssert} from '../../../src/log'; import {isLayoutSizeDefined} from '../../../src/layout'; import {map} from '../../../src/utils/object'; @@ -150,7 +149,7 @@ export class AmpAdNetworkBase extends AMP.BaseElement { * @private */ sendRequest_() { - this.adResponsePromise_ = Services.viewerForDoc(this.getAmpDoc()) + this.adResponsePromise_ = this.getAmpDoc() .whenFirstVisible() .then(() => { const url = this.getRequestUrl(); diff --git a/extensions/amp-a4a/0.1/test/test-amp-a4a.js b/extensions/amp-a4a/0.1/test/test-amp-a4a.js index 1f8515a60b57..171ba0c722ed 100644 --- a/extensions/amp-a4a/0.1/test/test-amp-a4a.js +++ b/extensions/amp-a4a/0.1/test/test-amp-a4a.js @@ -2544,7 +2544,7 @@ describe('amp-a4a', () => { const a4aElement = createA4aElement(fixture.doc); const a4a = new MockA4AImpl(a4aElement); a4a.adPromise_ = Promise.resolve(); - a4a.getAmpDoc = () => a4a.win.document; + a4a.getAmpDoc = () => fixture.ampdoc; a4a.getResource = () => { return { layoutCanceled: () => {}, @@ -2583,7 +2583,7 @@ describe('amp-a4a', () => { const a4aElement = createA4aElement(fixture.doc); const a4a = new MockA4AImpl(a4aElement); a4a.adPromise_ = Promise.resolve(); - a4a.getAmpDoc = () => a4a.win.document; + a4a.getAmpDoc = () => fixture.ampdoc; a4a.getResource = () => { return { layoutCanceled: () => {}, @@ -2622,7 +2622,7 @@ describe('amp-a4a', () => { const a4aElement = createA4aElement(fixture.doc); const a4a = new MockA4AImpl(a4aElement); a4a.adPromise_ = null; - a4a.getAmpDoc = () => a4a.win.document; + a4a.getAmpDoc = () => fixture.ampdoc; a4a.getResource = () => { return { layoutCanceled: () => {}, diff --git a/extensions/amp-access/0.1/amp-access-server-jwt.js b/extensions/amp-access/0.1/amp-access-server-jwt.js index 790665eeef6b..f940511c45bf 100644 --- a/extensions/amp-access/0.1/amp-access-server-jwt.js +++ b/extensions/amp-access/0.1/amp-access-server-jwt.js @@ -89,9 +89,6 @@ export class AccessServerJwtAdapter { /** @private @const */ this.clientAdapter_ = new AccessClientAdapter(ampdoc, configJson, context); - /** @private @const {!../../../src/service/viewer-interface.ViewerInterface} */ - this.viewer_ = Services.viewerForDoc(ampdoc); - /** @const @private {!../../../src/service/xhr-impl.Xhr} */ this.xhr_ = Services.xhrFor(ampdoc.win); @@ -116,7 +113,7 @@ export class AccessServerJwtAdapter { this.isProxyOrigin_ = isProxyOrigin(ampdoc.win.location) || isInExperiment; const serviceUrlOverride = isInExperiment - ? this.viewer_.getParam('serverAccessService') + ? ampdoc.getParam('serverAccessService') : null; /** @private @const {string} */ diff --git a/extensions/amp-access/0.1/amp-access-server.js b/extensions/amp-access/0.1/amp-access-server.js index 1907cb4b3dee..805ce20bb8d0 100644 --- a/extensions/amp-access/0.1/amp-access-server.js +++ b/extensions/amp-access/0.1/amp-access-server.js @@ -72,9 +72,6 @@ export class AccessServerAdapter { /** @private @const */ this.clientAdapter_ = new AccessClientAdapter(ampdoc, configJson, context); - /** @private @const {!../../../src/service/viewer-interface.ViewerInterface} */ - this.viewer_ = Services.viewerForDoc(ampdoc); - /** @const @protected {!../../../src/service/xhr-impl.Xhr} */ this.xhr_ = Services.xhrFor(ampdoc.win); @@ -99,7 +96,7 @@ export class AccessServerAdapter { this.isProxyOrigin_ = isProxyOrigin(ampdoc.win.location) || isInExperiment; const serviceUrlOverride = isInExperiment - ? this.viewer_.getParam('serverAccessService') + ? ampdoc.getParam('serverAccessService') : null; /** @private @const {string} */ diff --git a/extensions/amp-access/0.1/amp-access.js b/extensions/amp-access/0.1/amp-access.js index b6b07174d744..84c55dd53dff 100644 --- a/extensions/amp-access/0.1/amp-access.js +++ b/extensions/amp-access/0.1/amp-access.js @@ -383,7 +383,7 @@ export class AccessService { runAuthorization_(opt_disableFallback) { this.toggleTopClass_('amp-access-loading', true); - const authorizations = this.viewer_.whenFirstVisible().then(() => { + const authorizations = this.ampdoc.whenFirstVisible().then(() => { return Promise.all( this.sources_.map(source => this.runOneAuthorization_(source)) ); @@ -559,11 +559,11 @@ export class AccessService { } this.reportViewPromise_ = null; this.ampdoc.whenReady().then(() => { - if (this.viewer_.isVisible()) { + if (this.ampdoc.isVisible()) { this.reportWhenViewed_(timeToView); } - this.viewer_.onVisibilityChanged(() => { - if (this.viewer_.isVisible()) { + this.ampdoc.onVisibilityChanged(() => { + if (this.ampdoc.isVisible()) { this.reportWhenViewed_(timeToView); } }); @@ -624,8 +624,8 @@ export class AccessService { return new Promise((resolve, reject) => { // 1. Document becomes invisible again: cancel. unlistenSet.push( - this.viewer_.onVisibilityChanged(() => { - if (!this.viewer_.isVisible()) { + this.ampdoc.onVisibilityChanged(() => { + if (!this.ampdoc.isVisible()) { reject(cancellation()); } }) diff --git a/extensions/amp-access/0.1/login-dialog.js b/extensions/amp-access/0.1/login-dialog.js index 9818715db475..74fd6588e43a 100644 --- a/extensions/amp-access/0.1/login-dialog.js +++ b/extensions/amp-access/0.1/login-dialog.js @@ -36,7 +36,7 @@ const RETURN_URL_REGEX = new RegExp('RETURN_URL'); */ export function createLoginDialog(ampdoc, urlOrPromise) { const viewer = Services.viewerForDoc(ampdoc); - const overrideDialog = parseInt(viewer.getParam('dialog'), 10); + const overrideDialog = parseInt(ampdoc.getParam('dialog'), 10); if (overrideDialog) { return new ViewerLoginDialog(viewer, urlOrPromise); } diff --git a/extensions/amp-access/0.1/test/test-amp-access.js b/extensions/amp-access/0.1/test/test-amp-access.js index 07368414f6f5..fa87565988f3 100644 --- a/extensions/amp-access/0.1/test/test-amp-access.js +++ b/extensions/amp-access/0.1/test/test-amp-access.js @@ -301,11 +301,12 @@ describes.fakeWin( elementError.setAttribute('amp-access-hide', ''); document.body.appendChild(elementError); + sandbox.stub(ampdoc, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'whenFirstVisible').returns(Promise.resolve()); + sandbox.stub(ampdoc, 'onVisibilityChanged').returns(function() {}); + service = new AccessService(ampdoc); service.viewer_ = { - isVisible: () => true, - whenFirstVisible: () => Promise.resolve(), - onVisibilityChanged: () => {}, broadcast: () => {}, onBroadcast: () => {}, }; @@ -711,6 +712,7 @@ describes.fakeWin( let configElement; let adapterMock; let cidMock; + let isVisibleStub; let visibilityChanged; let scrolled; let service; @@ -736,6 +738,13 @@ describes.fakeWin( document.body.appendChild(configElement); document.documentElement.classList.remove('amp-access-error'); + isVisibleStub = sandbox.stub(ampdoc, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'whenFirstVisible').returns(Promise.resolve()); + visibilityChanged = new Observable(); + sandbox + .stub(ampdoc, 'onVisibilityChanged') + .callsFake(callback => visibilityChanged.add(callback)); + service = new AccessService(ampdoc); const adapter = { @@ -757,11 +766,7 @@ describes.fakeWin( onReady: callback => callback(), }; - visibilityChanged = new Observable(); service.viewer_ = { - isVisible: () => true, - whenFirstVisible: () => Promise.resolve(), - onVisibilityChanged: callback => visibilityChanged.add(callback), broadcast: () => {}, }; @@ -895,7 +900,7 @@ describes.fakeWin( const p = service.reportWhenViewed_(/* timeToView */ 2000); return Promise.resolve() .then(() => { - service.viewer_.isVisible = () => false; + isVisibleStub.returns(false); visibilityChanged.fire(); return p; }) @@ -953,7 +958,7 @@ describes.fakeWin( .then(() => { p1 = service.reportViewPromise_; expect(p1).to.exist; - service.viewer_.isVisible = () => false; + isVisibleStub.returns(false); visibilityChanged.fire(); return p1; }) @@ -965,7 +970,7 @@ describes.fakeWin( }) .then(() => { // 2. Second attempt is rescheduled and will complete. - service.viewer_.isVisible = () => true; + isVisibleStub.returns(true); visibilityChanged.fire(); const p2 = service.reportViewPromise_; expect(p2).to.exist; @@ -1109,6 +1114,9 @@ describes.fakeWin( document.body.appendChild(configElement); document.documentElement.classList.remove('amp-access-error'); + sandbox.stub(ampdoc, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'onVisibilityChanged').returns(function() {}); + service = new AccessService(ampdoc); const cid = { @@ -1125,8 +1133,6 @@ describes.fakeWin( service.viewer_ = { broadcast: () => {}, - isVisible: () => true, - onVisibilityChanged: () => {}, }; }); @@ -1192,6 +1198,9 @@ describes.fakeWin( document.body.appendChild(configElement); document.documentElement.classList.remove('amp-access-error'); + sandbox.stub(ampdoc, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'onVisibilityChanged').returns(function() {}); + service = new AccessService(ampdoc); const cid = { @@ -1210,8 +1219,6 @@ describes.fakeWin( service.viewer_ = { broadcast: () => {}, - isVisible: () => true, - onVisibilityChanged: () => {}, }; }); diff --git a/extensions/amp-access/0.1/test/test-login-dialog.js b/extensions/amp-access/0.1/test/test-login-dialog.js index d70b81e30cd8..aadd269f3a7f 100644 --- a/extensions/amp-access/0.1/test/test-login-dialog.js +++ b/extensions/amp-access/0.1/test/test-login-dialog.js @@ -33,12 +33,6 @@ describes.sandboxed('ViewerLoginDialog', {}, () => { sandbox = sinon.sandbox; viewer = { - getParam: param => { - if (param == 'dialog') { - return '1'; - } - return null; - }, sendMessageAwaitResponse: () => {}, }; @@ -67,6 +61,12 @@ describes.sandboxed('ViewerLoginDialog', {}, () => { windowApi.document.defaultView = windowApi; installDocService(windowApi, /* isSingleDoc */ true); ampdoc = Services.ampdocServiceFor(windowApi).getSingleDoc(); + sandbox.stub(ampdoc, 'getParam').callsFake(param => { + if (param == 'dialog') { + return '1'; + } + return null; + }); }); afterEach(() => { @@ -170,7 +170,6 @@ describes.sandboxed('WebLoginDialog', {}, () => { clock = sandbox.useFakeTimers(); viewer = { - getParam: () => null, getResolvedViewerUrl: () => 'http://localhost:8000/test-login-dialog', }; const windowObj = { @@ -206,6 +205,7 @@ describes.sandboxed('WebLoginDialog', {}, () => { windowMock = sandbox.mock(windowApi); installDocService(windowApi, /* isSingleDoc */ true); ampdoc = Services.ampdocServiceFor(windowApi).getSingleDoc(); + sandbox.stub(ampdoc, 'getParam').returns(null); dialogUrl = null; dialog = { diff --git a/extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js b/extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js index 7f368822088a..4ab6839fb3ee 100644 --- a/extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js +++ b/extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js @@ -251,7 +251,7 @@ export class AmpAdNetworkAdsenseImpl extends AmpA4A { /** @override */ buildCallback() { super.buildCallback(); - this.identityTokenPromise_ = Services.viewerForDoc(this.getAmpDoc()) + this.identityTokenPromise_ = this.getAmpDoc() .whenFirstVisible() .then(() => getIdentityToken(this.win, this.getAmpDoc(), super.getConsentPolicy()) diff --git a/extensions/amp-ad-network-doubleclick-impl/0.1/amp-ad-network-doubleclick-impl.js b/extensions/amp-ad-network-doubleclick-impl/0.1/amp-ad-network-doubleclick-impl.js index 3c98443e811b..b99ba80689e0 100644 --- a/extensions/amp-ad-network-doubleclick-impl/0.1/amp-ad-network-doubleclick-impl.js +++ b/extensions/amp-ad-network-doubleclick-impl/0.1/amp-ad-network-doubleclick-impl.js @@ -477,7 +477,7 @@ export class AmpAdNetworkDoubleclickImpl extends AmpA4A { DOUBLECLICK_SRA_EXP_BRANCHES.SRA, DOUBLECLICK_SRA_EXP_BRANCHES.SRA_NO_RECOVER, ].some(eid => this.experimentIds.indexOf(eid) >= 0); - this.identityTokenPromise_ = Services.viewerForDoc(this.getAmpDoc()) + this.identityTokenPromise_ = this.getAmpDoc() .whenFirstVisible() .then(() => getIdentityToken(this.win, this.getAmpDoc(), super.getConsentPolicy()) diff --git a/extensions/amp-ad-network-doubleclick-impl/0.1/test/test-amp-ad-network-doubleclick-impl.js b/extensions/amp-ad-network-doubleclick-impl/0.1/test/test-amp-ad-network-doubleclick-impl.js index a5429033ff1f..916496744d36 100644 --- a/extensions/amp-ad-network-doubleclick-impl/0.1/test/test-amp-ad-network-doubleclick-impl.js +++ b/extensions/amp-ad-network-doubleclick-impl/0.1/test/test-amp-ad-network-doubleclick-impl.js @@ -1739,10 +1739,9 @@ describes.realWin( 'extractUrlExperimentId_' ); sandbox.stub(AmpA4A.prototype, 'buildCallback').callsFake(() => {}); - sandbox.stub(impl, 'getAmpDoc').returns({}); - sandbox - .stub(Services, 'viewerForDoc') - .returns({whenFirstVisible: () => new Deferred().promise}); + sandbox.stub(impl, 'getAmpDoc').returns({ + whenFirstVisible: () => new Deferred().promise, + }); }); afterEach(() => { toggleExperiment(env.win, 'envDfpInvOrigDeprecated', false); diff --git a/extensions/amp-ad/0.1/amp-ad-xorigin-iframe-handler.js b/extensions/amp-ad/0.1/amp-ad-xorigin-iframe-handler.js index baa056e8e7b5..8ef238c36c90 100644 --- a/extensions/amp-ad/0.1/amp-ad-xorigin-iframe-handler.js +++ b/extensions/amp-ad/0.1/amp-ad-xorigin-iframe-handler.js @@ -78,9 +78,6 @@ export class AmpAdXOriginIframeHandler { /** @private {!Array} functions to unregister listeners */ this.unlisteners_ = []; - /** @private @const {!../../../src/service/viewer-interface.ViewerInterface} */ - this.viewer_ = Services.viewerForDoc(this.baseInstance_.getAmpDoc()); - /** @private @const {!../../../src/service/viewport/viewport-interface.ViewportInterface} */ this.viewport_ = Services.viewportForDoc(this.baseInstance_.getAmpDoc()); @@ -183,7 +180,7 @@ export class AmpAdXOriginIframeHandler { ); this.unlisteners_.push( - this.viewer_.onVisibilityChanged(() => { + this.baseInstance_.getAmpDoc().onVisibilityChanged(() => { this.sendEmbedInfo_(this.baseInstance_.isInViewport()); }) ); @@ -493,7 +490,7 @@ export class AmpAdXOriginIframeHandler { 'embed-state', dict({ 'inViewport': inViewport, - 'pageHidden': !this.viewer_.isVisible(), + 'pageHidden': !this.baseInstance_.getAmpDoc().isVisible(), }) ); } diff --git a/extensions/amp-ad/0.1/test/test-amp-ad-xorigin-iframe-handler.js b/extensions/amp-ad/0.1/test/test-amp-ad-xorigin-iframe-handler.js index 962451b1f523..ea3d55850998 100644 --- a/extensions/amp-ad/0.1/test/test-amp-ad-xorigin-iframe-handler.js +++ b/extensions/amp-ad/0.1/test/test-amp-ad-xorigin-iframe-handler.js @@ -28,6 +28,7 @@ import {toggleExperiment} from '../../../../src/experiments'; describe('amp-ad-xorigin-iframe-handler', () => { let sandbox; + let ampdoc; let adImpl; let signals; let renderStartedSpy; @@ -38,7 +39,7 @@ describe('amp-ad-xorigin-iframe-handler', () => { beforeEach(() => { sandbox = sinon.sandbox; const ampdocService = Services.ampdocServiceFor(window); - const ampdoc = ampdocService.getSingleDoc(); + ampdoc = ampdocService.getSingleDoc(); const adElement = document.createElement('container-element'); adElement.getAmpDoc = () => ampdoc; adElement.isBuilt = () => { @@ -297,9 +298,7 @@ describe('amp-ad-xorigin-iframe-handler', () => { }); it('should be able to use embed-state API', () => { - sandbox - ./*OK*/ stub(iframeHandler.viewer_, 'isVisible') - .callsFake(() => true); + sandbox./*OK*/ stub(ampdoc, 'isVisible').returns(true); iframe.postMessageToParent({ type: 'send-embed-state', sentinel: 'amp3ptest' + testIndex, diff --git a/extensions/amp-addthis/0.1/addthis-utils/monitors/dwell-monitor.js b/extensions/amp-addthis/0.1/addthis-utils/monitors/dwell-monitor.js index a7b0e117447e..3210ca3ce875 100644 --- a/extensions/amp-addthis/0.1/addthis-utils/monitors/dwell-monitor.js +++ b/extensions/amp-addthis/0.1/addthis-utils/monitors/dwell-monitor.js @@ -14,15 +14,13 @@ * limitations under the License. */ -import {Services} from '../../../../../src/services'; - export class DwellMonitor { /** * Creates an instance of DwellMonitor. */ constructor() { this.dwellTime_ = 0; - this.viewer_ = null; + this.ampdoc_ = null; } /** @@ -31,16 +29,16 @@ export class DwellMonitor { * @param {!../../../../../src/service/ampdoc-impl.AmpDoc} ampDoc */ startForDoc(ampDoc) { - this.viewer_ = Services.viewerForDoc(ampDoc); - this.viewer_.onVisibilityChanged(this.listener.bind(this)); + this.ampdoc_ = ampDoc; + this.ampdoc_.onVisibilityChanged(this.listener.bind(this)); } /** * Calculates dwell time. */ listener() { - if (!this.viewer_.isVisible()) { - const lastVisibleTime = this.viewer_.getLastVisibleTime() || 0; + if (!this.ampdoc_.isVisible()) { + const lastVisibleTime = this.ampdoc_.getLastVisibleTime() || 0; this.dwellTime_ += Date.now() - lastVisibleTime; } } diff --git a/extensions/amp-addthis/0.1/amp-addthis.js b/extensions/amp-addthis/0.1/amp-addthis.js index 13bc6dbf9a17..cc6a9c994f80 100644 --- a/extensions/amp-addthis/0.1/amp-addthis.js +++ b/extensions/amp-addthis/0.1/amp-addthis.js @@ -201,7 +201,7 @@ class AmpAddThis extends AMP.BaseElement { const viewer = Services.viewerForDoc(ampDoc); const loc = parseUrlDeprecated(this.canonicalUrl_); - viewer + ampDoc .whenFirstVisible() .then(() => viewer.getReferrerUrl()) .then(referrer => { diff --git a/extensions/amp-analytics/0.1/activity-impl.js b/extensions/amp-analytics/0.1/activity-impl.js index b125296903a5..ddc0dc2480dc 100644 --- a/extensions/amp-analytics/0.1/activity-impl.js +++ b/extensions/amp-analytics/0.1/activity-impl.js @@ -115,7 +115,7 @@ class ActivityHistory { /** * Array of event types which will be listened for on the document to indicate - * activity. Other activities are also observed on the Viewer and Viewport + * activity. Other activities are also observed on the AmpDoc and Viewport * objects. See {@link setUpActivityListeners_} for listener implementation. * @private @const {Array} */ @@ -138,8 +138,8 @@ export class Activity { /** * Activity tracks basic user activity on the page. * - Listeners are not registered on the activity event types until the - * Viewer's `whenFirstVisible` is resolved. - * - When the `whenFirstVisible` of Viewer is resolved, a first activity + * AmpDoc's `whenFirstVisible` is resolved. + * - When the `whenFirstVisible` of AmpDoc is resolved, a first activity * is recorded. * - The first activity in any second causes all other activities to be * ignored. This is similar to debounce functionality since some events @@ -189,13 +189,10 @@ export class Activity { /** @private @const {!ActivityHistory} */ this.activityHistory_ = new ActivityHistory(); - /** @private @const {!../../../src/service/viewer-interface.ViewerInterface} */ - this.viewer_ = Services.viewerForDoc(this.ampdoc); - /** @private @const {!../../../src/service/viewport/viewport-interface.ViewportInterface} */ this.viewport_ = Services.viewportForDoc(this.ampdoc); - this.viewer_.whenFirstVisible().then(this.start_.bind(this)); + this.ampdoc.whenFirstVisible().then(this.start_.bind(this)); } /** @private */ @@ -242,7 +239,7 @@ export class Activity { } this.unlistenFuncs_.push( - this.viewer_.onVisibilityChanged(this.boundHandleVisibilityChange_) + this.ampdoc.onVisibilityChanged(this.boundHandleVisibilityChange_) ); // Viewport.onScroll does not return an unlisten function. @@ -293,7 +290,7 @@ export class Activity { /** @private */ handleVisibilityChange_() { - if (this.viewer_.isVisible()) { + if (this.ampdoc.isVisible()) { this.handleActivity_(); } else { this.handleInactive_(); diff --git a/extensions/amp-analytics/0.1/amp-analytics.js b/extensions/amp-analytics/0.1/amp-analytics.js index 2615928f8f1d..1f051a6ce86a 100644 --- a/extensions/amp-analytics/0.1/amp-analytics.js +++ b/extensions/amp-analytics/0.1/amp-analytics.js @@ -182,7 +182,7 @@ export class AmpAnalytics extends AMP.BaseElement { /** @override */ unlayoutCallback() { - if (Services.viewerForDoc(this.getAmpDoc()).isVisible()) { + if (this.getAmpDoc().isVisible()) { // amp-analytics tag was just set to display:none. Page is still loaded. return false; } @@ -207,7 +207,7 @@ export class AmpAnalytics extends AMP.BaseElement { } toggle(this.element, false); - this.iniPromise_ = Services.viewerForDoc(this.getAmpDoc()) + this.iniPromise_ = this.getAmpDoc() .whenFirstVisible() // Rudimentary "idle" signal. .then(() => Services.timerFor(this.win).promise(1)) diff --git a/extensions/amp-analytics/0.1/events.js b/extensions/amp-analytics/0.1/events.js index 57925971b75d..f89f7a17baf6 100644 --- a/extensions/amp-analytics/0.1/events.js +++ b/extensions/amp-analytics/0.1/events.js @@ -1531,15 +1531,15 @@ export class VisibilityTracker extends EventTracker { * @private */ createReportReadyPromiseForDocumentHidden_() { - const viewer = this.root.getViewer(); + const {ampdoc} = this.root; - if (!viewer.isVisible()) { + if (!ampdoc.isVisible()) { return Promise.resolve(); } return new Promise(resolve => { - viewer.onVisibilityChanged(() => { - if (!viewer.isVisible()) { + ampdoc.onVisibilityChanged(() => { + if (!ampdoc.isVisible()) { resolve(); } }); diff --git a/extensions/amp-analytics/0.1/test/test-amp-analytics.js b/extensions/amp-analytics/0.1/test/test-amp-analytics.js index 72801b6aaecc..ecf51c7b3abc 100644 --- a/extensions/amp-analytics/0.1/test/test-amp-analytics.js +++ b/extensions/amp-analytics/0.1/test/test-amp-analytics.js @@ -222,7 +222,7 @@ describes.realWin( el.setAttribute('trigger', 'immediate'); el.textContent = config; const whenFirstVisibleStub = sandbox - .stub(viewer, 'whenFirstVisible') + .stub(ampdoc, 'whenFirstVisible') .callsFake(() => new Promise(function() {})); doc.body.appendChild(el); const analytics = new AmpAnalytics(el); @@ -1468,7 +1468,7 @@ describes.realWin( return Promise.reject(); }); - sandbox.stub(viewer, 'isVisible').returns(false); + sandbox.stub(ampdoc, 'isVisible').returns(false); analytics.layoutCallback(); analytics.resumeCallback(); analytics.unlayoutCallback(); diff --git a/extensions/amp-analytics/0.1/test/test-events.js b/extensions/amp-analytics/0.1/test/test-events.js index bb3998b8aa0f..01c0a31b5ceb 100644 --- a/extensions/amp-analytics/0.1/test/test-events.js +++ b/extensions/amp-analytics/0.1/test/test-events.js @@ -1973,13 +1973,7 @@ describes.realWin('Events', {amp: 1}, env => { describe('should create correct reportReadyPromise', () => { it('with viewer hidden', () => { - const stub = sandbox.stub(tracker.root, 'getViewer').callsFake(() => { - return { - isVisible: () => { - return false; - }, - }; - }); + const stub = sandbox.stub(ampdoc, 'isVisible').returns(false); const promise = tracker.createReportReadyPromiseForDocumentHidden_(); return promise.then(() => { expect(stub).to.be.calledOnce; diff --git a/extensions/amp-analytics/0.1/test/test-visibility-manager-for-mapp.js b/extensions/amp-analytics/0.1/test/test-visibility-manager-for-mapp.js index cf7bd0b480f4..62309dccb260 100644 --- a/extensions/amp-analytics/0.1/test/test-visibility-manager-for-mapp.js +++ b/extensions/amp-analytics/0.1/test/test-visibility-manager-for-mapp.js @@ -62,7 +62,7 @@ describes.fakeWin('VisibilityManagerForMapp', {amp: true}, env => { clock.tick(1); viewer = win.__AMP_SERVICES.viewer.obj; - sandbox.stub(viewer, 'getFirstVisibleTime').callsFake(() => 1); + sandbox.stub(ampdoc, 'getFirstVisibleTime').returns(1); visibilityInterface = new MockVisibilityInterface(); root = new VisibilityManagerForMApp(ampdoc, visibilityInterface); @@ -79,7 +79,7 @@ describes.fakeWin('VisibilityManagerForMapp', {amp: true}, env => { root = new VisibilityManagerForMApp(ampdoc, visibilityInterface); expect(root.parent).to.be.null; expect(root.ampdoc).to.equal(ampdoc); - expect(root.getStartTime()).to.equal(viewer.getFirstVisibleTime()); + expect(root.getStartTime()).to.equal(ampdoc.getFirstVisibleTime()); expect(root.isBackgrounded()).to.be.true; expect(root.isBackgroundedAtStart()).to.be.true; @@ -156,7 +156,7 @@ describes.fakeWin('VisibilityManagerForMapp', {amp: true}, env => { it('listen on root integrated', () => { // There's a clock.tick(1) in beforeEach, so firstSeenTime is - // /*tick*/1 + /*tick*/1 - /*viewer.getFirstVisibleTime*/ 1) + // /*tick*/1 + /*tick*/1 - /*ampdoc.getFirstVisibleTime*/ 1) clock.tick(1); const disposed = sandbox.spy(); const spec = dict({ diff --git a/extensions/amp-analytics/0.1/test/test-visibility-manager.js b/extensions/amp-analytics/0.1/test/test-visibility-manager.js index e4fd10d5a3ea..f49e17c8bc21 100644 --- a/extensions/amp-analytics/0.1/test/test-visibility-manager.js +++ b/extensions/amp-analytics/0.1/test/test-visibility-manager.js @@ -79,7 +79,7 @@ describes.fakeWin('VisibilityManagerForDoc', {amp: true}, env => { clock.tick(1); viewer = win.__AMP_SERVICES.viewer.obj; - sandbox.stub(viewer, 'getFirstVisibleTime').callsFake(() => 1); + sandbox.stub(ampdoc, 'getFirstVisibleTime').returns(1); viewport = win.__AMP_SERVICES.viewport.obj; startVisibilityHandlerCount = getVisibilityHandlerCount(); @@ -104,7 +104,7 @@ describes.fakeWin('VisibilityManagerForDoc', {amp: true}, env => { expect(root.parent).to.be.null; expect(root.ampdoc).to.equal(ampdoc); - expect(root.getStartTime()).to.equal(viewer.getFirstVisibleTime()); + expect(root.getStartTime()).to.equal(ampdoc.getFirstVisibleTime()); expect(root.isBackgrounded()).to.be.true; expect(root.isBackgroundedAtStart()).to.be.true; expect(root.children_).to.be.null; // Don't take extra memory. @@ -120,7 +120,7 @@ describes.fakeWin('VisibilityManagerForDoc', {amp: true}, env => { it('should initialize correctly foregrounded', () => { expect(root.parent).to.be.null; expect(root.ampdoc).to.equal(ampdoc); - expect(root.getStartTime()).to.equal(viewer.getFirstVisibleTime()); + expect(root.getStartTime()).to.equal(ampdoc.getFirstVisibleTime()); expect(root.isBackgrounded()).to.be.false; expect(root.isBackgroundedAtStart()).to.be.false; @@ -182,7 +182,7 @@ describes.fakeWin('VisibilityManagerForDoc', {amp: true}, env => { // Go visible. viewer.setVisibilityState_(VisibilityState.VISIBLE); expect(root.getRootVisibility()).to.equal(1); - expect(root.getStartTime()).to.equal(viewer.getFirstVisibleTime()); + expect(root.getStartTime()).to.equal(ampdoc.getFirstVisibleTime()); }); it('should switch visibility for in-a-box', () => { @@ -792,7 +792,7 @@ describes.realWin( viewport = parentWin.__AMP_SERVICES.viewport.obj; viewer = parentWin.__AMP_SERVICES.viewer.obj; - sandbox.stub(viewer, 'getFirstVisibleTime').callsFake(() => 1); + sandbox.stub(ampdoc, 'getFirstVisibleTime').returns(1); parentRoot = new VisibilityManagerForDoc(ampdoc); parentWin.IntersectionObserver = IntersectionObserverStub; @@ -1055,7 +1055,7 @@ describes.realWin('VisibilityManager integrated', {amp: true}, env => { const docState = Services.globalDocumentStateFor(win); sandbox.stub(docState, 'isHidden').callsFake(() => false); - sandbox.stub(viewer, 'getFirstVisibleTime').callsFake(() => startTime); + sandbox.stub(ampdoc, 'getFirstVisibleTime').callsFake(() => startTime); ampElement = doc.createElement('amp-img'); ampElement.id = 'abc'; diff --git a/extensions/amp-analytics/0.1/visibility-manager-for-mapp.js b/extensions/amp-analytics/0.1/visibility-manager-for-mapp.js index b741ab589c07..4fd6efbb2353 100644 --- a/extensions/amp-analytics/0.1/visibility-manager-for-mapp.js +++ b/extensions/amp-analytics/0.1/visibility-manager-for-mapp.js @@ -14,7 +14,6 @@ * limitations under the License. */ -import {Services} from '../../../src/services'; import {VisibilityManager} from './visibility-manager'; import {dev, devAssert} from '../../../src/log'; import {dict} from '../../../src/utils/object'; @@ -35,14 +34,11 @@ export class VisibilityManagerForMApp extends VisibilityManager { * In VisibilityManagerForMApp case, */ - /** @const @private */ - this.viewer_ = Services.viewerForDoc(ampdoc); - /** @const @private {!../../../src/inabox/host-services.VisibilityInterface} */ this.visibilityInterface_ = visibilityInterface; /** @const @private {boolean} */ - this.backgroundedAtStart_ = !this.viewer_.isVisible(); + this.backgroundedAtStart_ = !ampdoc.isVisible(); /** @private {?../../../src/layout-rect.LayoutRectDef} */ this.intersectionRect_ = null; @@ -64,16 +60,16 @@ export class VisibilityManagerForMApp extends VisibilityManager { /** @override */ getStartTime() { - // viewer.getFirstVisibleTime depend on the visibilitychange API and + // AmpDoc.getFirstVisibleTime depend on the visibilitychange API and // document['hidden'] - // Expect the viewer is always visible in webview - return dev().assertNumber(this.viewer_.getFirstVisibleTime()); + // Expect the ampdoc is always visible in webview + return dev().assertNumber(this.ampdoc.getFirstVisibleTime()); } /** @override */ isBackgrounded() { // Listens to visibilitychange event, in theory this never fires - return !this.viewer_.isVisible(); + return !this.ampdoc.isVisible(); } /** @override */ @@ -126,7 +122,7 @@ export class VisibilityManagerForMApp extends VisibilityManager { return; } //TODO: Need discussion - // rootVisibility is set by hostAPI, instead of Viewer.isVisible + // rootVisibility is set by hostAPI, instead of ampdoc.isVisible let ratio = visibilityData.visibleRatio; // Convert to valid ratio range in [0, 1] ratio = Math.min(Math.max(0, ratio), 1); diff --git a/extensions/amp-analytics/0.1/visibility-manager.js b/extensions/amp-analytics/0.1/visibility-manager.js index e80e1d0c4709..2a8a8f0cbbd6 100644 --- a/extensions/amp-analytics/0.1/visibility-manager.js +++ b/extensions/amp-analytics/0.1/visibility-manager.js @@ -573,14 +573,11 @@ export class VisibilityManagerForDoc extends VisibilityManager { constructor(ampdoc) { super(/* parent */ null, ampdoc); - /** @const @private */ - this.viewer_ = Services.viewerForDoc(ampdoc); - /** @const @private */ this.viewport_ = Services.viewportForDoc(ampdoc); /** @private {boolean} */ - this.backgrounded_ = !this.viewer_.isVisible(); + this.backgrounded_ = !ampdoc.isVisible(); /** @const @private {boolean} */ this.backgroundedAtStart_ = this.isBackgrounded(); @@ -608,11 +605,11 @@ export class VisibilityManagerForDoc extends VisibilityManager { this.observe(rootElement, this.setRootVisibility.bind(this)) ); } else { - // Main document: visibility is based on the viewer. - this.setRootVisibility(this.viewer_.isVisible() ? 1 : 0); + // Main document: visibility is based on the ampdoc. + this.setRootVisibility(this.ampdoc.isVisible() ? 1 : 0); this.unsubscribe( - this.viewer_.onVisibilityChanged(() => { - const isVisible = this.viewer_.isVisible(); + this.ampdoc.onVisibilityChanged(() => { + const isVisible = this.ampdoc.isVisible(); if (!isVisible) { this.backgrounded_ = true; } @@ -633,7 +630,7 @@ export class VisibilityManagerForDoc extends VisibilityManager { /** @override */ getStartTime() { - return dev().assertNumber(this.viewer_.getFirstVisibleTime()); + return dev().assertNumber(this.ampdoc.getFirstVisibleTime()); } /** @override */ diff --git a/extensions/amp-animation/0.1/amp-animation.js b/extensions/amp-animation/0.1/amp-animation.js index 99c018a3f806..7c1b9a06d984 100644 --- a/extensions/amp-animation/0.1/amp-animation.js +++ b/extensions/amp-animation/0.1/amp-animation.js @@ -141,10 +141,9 @@ export class AmpAnimation extends AMP.BaseElement { }); listen(this.embed_.win, 'resize', () => this.onResize_()); } else { - const viewer = Services.viewerForDoc(ampdoc); - this.setVisible_(viewer.isVisible()); - viewer.onVisibilityChanged(() => { - this.setVisible_(viewer.isVisible()); + this.setVisible_(ampdoc.isVisible()); + ampdoc.onVisibilityChanged(() => { + this.setVisible_(ampdoc.isVisible()); }); this.getViewport().onResize(e => { if (e.relayoutAll) { diff --git a/extensions/amp-auto-ads/0.1/amp-auto-ads.js b/extensions/amp-auto-ads/0.1/amp-auto-ads.js index c7a5ba927480..55a59d176a30 100644 --- a/extensions/amp-auto-ads/0.1/amp-auto-ads.js +++ b/extensions/amp-auto-ads/0.1/amp-auto-ads.js @@ -61,8 +61,7 @@ export class AmpAutoAds extends AMP.BaseElement { AD_TAG ); - const viewer = Services.viewerForDoc(this.getAmpDoc()); - const whenVisible = viewer.whenFirstVisible(); + const whenVisible = this.getAmpDoc().whenFirstVisible(); const responsiveSizingBranch = this.getUseResponsiveForResponsiveExperimentBranch( adNetwork.isResponsiveEnabled() ); diff --git a/extensions/amp-auto-ads/0.1/test/test-amp-auto-ads.js b/extensions/amp-auto-ads/0.1/test/test-amp-auto-ads.js index 7772bd5ee031..181abf95c64c 100644 --- a/extensions/amp-auto-ads/0.1/test/test-amp-auto-ads.js +++ b/extensions/amp-auto-ads/0.1/test/test-amp-auto-ads.js @@ -186,8 +186,7 @@ describes.repeated( }; sandbox.spy(xhr, 'fetchJson'); - const viewer = Services.viewerForDoc(env.ampdoc); - whenVisible = sandbox.stub(viewer, 'whenFirstVisible'); + whenVisible = sandbox.stub(env.ampdoc, 'whenFirstVisible'); whenVisible.returns(Promise.resolve()); }); diff --git a/extensions/amp-bind/0.1/amp-state.js b/extensions/amp-bind/0.1/amp-state.js index 9e89f4f15a67..696b42d4190a 100644 --- a/extensions/amp-bind/0.1/amp-state.js +++ b/extensions/amp-bind/0.1/amp-state.js @@ -96,10 +96,9 @@ export class AmpState extends AMP.BaseElement { /** @override */ mutatedAttributesCallback(mutations) { - const viewer = Services.viewerForDoc(this.element); - if (!viewer.hasBeenVisible()) { + if (!this.getAmpDoc().hasBeenVisible()) { const TAG = this.getName_(); - dev().error(TAG, 'Viewer must be visible before mutation.'); + dev().error(TAG, 'ampdoc must be visible before mutation.'); return; } // "src" attribute may be missing if mutated with a non-primitive. @@ -220,8 +219,7 @@ export class AmpState extends AMP.BaseElement { */ fetchAndUpdate_(isInit, opt_refresh) { // Don't fetch in prerender mode. - const viewer = Services.viewerForDoc(this.element); - return viewer + return this.getAmpDoc() .whenFirstVisible() .then(() => this.prepareAndSendFetch_(isInit, opt_refresh)) .then(json => this.updateState_(json, isInit)); diff --git a/extensions/amp-bind/0.1/bind-impl.js b/extensions/amp-bind/0.1/bind-impl.js index e705df920df3..4a9ebe2d458c 100644 --- a/extensions/amp-bind/0.1/bind-impl.js +++ b/extensions/amp-bind/0.1/bind-impl.js @@ -200,7 +200,7 @@ export class Bind { * Resolved when the service finishes scanning the document for bindings. * @const @private {Promise} */ - this.initializePromise_ = this.viewer_ + this.initializePromise_ = ampdoc .whenFirstVisible() .then(() => { if (opt_win) { diff --git a/extensions/amp-bind/0.1/test/test-amp-state.js b/extensions/amp-bind/0.1/test/test-amp-state.js index ee2277884ced..29ef5fe784b5 100644 --- a/extensions/amp-bind/0.1/test/test-amp-state.js +++ b/extensions/amp-bind/0.1/test/test-amp-state.js @@ -31,13 +31,13 @@ describes.realWin( env => { let win; let sandbox; + let ampdoc; let element; let ampState; let bind; // Viewer-related vars. - let viewer; let whenFirstVisiblePromise; let whenFirstVisiblePromiseResolve; let whenFirstVisiblePromiseReject; @@ -50,15 +50,14 @@ describes.realWin( } beforeEach(() => { - ({win, sandbox} = env); + ({win, sandbox, ampdoc} = env); - viewer = Services.viewerForDoc(win.document); whenFirstVisiblePromise = new Promise((resolve, reject) => { whenFirstVisiblePromiseResolve = resolve; whenFirstVisiblePromiseReject = reject; }); - sandbox.stub(viewer, 'whenFirstVisible').returns(whenFirstVisiblePromise); - sandbox.stub(viewer, 'hasBeenVisible').returns(false); + sandbox.stub(ampdoc, 'whenFirstVisible').returns(whenFirstVisiblePromise); + sandbox.stub(ampdoc, 'hasBeenVisible').returns(false); element = getAmpState(); ampState = element.implementation_; @@ -77,7 +76,7 @@ describes.realWin( sandbox.stub(Services, 'bindForDocOrNull').resolves(bind); }); - it('should not fetch until viewer is visible', async () => { + it('should not fetch until doc is visible', async () => { element.setAttribute('src', 'https://foo.com/bar?baz=1'); element.build(); @@ -160,7 +159,7 @@ describes.realWin( const action = {method: 'refresh', satisfiesTrust: () => true}; await ampState.executeAction(action); - // Fetch via "refresh" should also wait for viewer visible. + // Fetch via "refresh" should also wait for doc visible. expect(ampState.fetch_).to.not.have.been.called; expect(bind.setState).to.not.have.been.called; @@ -197,7 +196,7 @@ describes.realWin( element.setAttribute('src', 'https://foo.com/bar?baz=1'); await element.build(); - // No fetch should happen until viewer is visible. + // No fetch should happen until doc is visible. expect(ampState.fetch_).to.not.have.been.called; expect(bind.setState).calledWithMatch( {myAmpState: {local: 'data'}}, @@ -218,18 +217,18 @@ describes.realWin( ); }); - it('should not fetch if `src` is mutated and viewer is not visible', () => { + it('should not fetch if `src` is mutated and doc is not visible', () => { element.setAttribute('src', 'https://foo.com/bar?baz=1'); element.build(); - // No fetch should happen until viewer is visible. + // No fetch should happen until doc is visible. expect(ampState.fetch_).to.not.have.been.called; allowConsoleError(() => { element.mutatedAttributesCallback({src: 'https://foo.com/bar?baz=1'}); }); - // Viewer still not visible. + // Doc still not visible. expect(ampState.fetch_).to.not.have.been.called; }); @@ -237,10 +236,10 @@ describes.realWin( element.setAttribute('src', 'https://foo.com/bar?baz=1'); element.build(); - // No fetch should happen until viewer is visible. + // No fetch should happen until doc is visible. expect(ampState.fetch_).to.not.have.been.called; - viewer.hasBeenVisible.returns(true); + ampdoc.hasBeenVisible.returns(true); element.mutatedAttributesCallback({src: 'https://foo.com/bar?baz=1'}); diff --git a/extensions/amp-consent/0.1/amp-consent.js b/extensions/amp-consent/0.1/amp-consent.js index 23d680d42b24..a0627eabaeb2 100644 --- a/extensions/amp-consent/0.1/amp-consent.js +++ b/extensions/amp-consent/0.1/amp-consent.js @@ -536,8 +536,7 @@ export class AmpConsent extends AMP.BaseElement { const ampdoc = this.getAmpDoc(); const sourceBase = getSourceUrl(ampdoc.getUrl()); const resolvedHref = resolveRelativeUrl(href, sourceBase); - const viewer = Services.viewerForDoc(ampdoc); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { return Services.xhrFor(this.win) .fetchJson(resolvedHref, init) .then(res => res.json()); diff --git a/extensions/amp-consent/0.1/consent-state-manager.js b/extensions/amp-consent/0.1/consent-state-manager.js index f5f795e36bf0..da5507549014 100644 --- a/extensions/amp-consent/0.1/consent-state-manager.js +++ b/extensions/amp-consent/0.1/consent-state-manager.js @@ -456,14 +456,12 @@ export class ConsentInstance { body: request, ampCors: false, }; - Services.viewerForDoc(this.ampdoc_) - .whenFirstVisible() - .then(() => { - Services.xhrFor(this.ampdoc_.win).fetchJson( - /** @type {string} */ (this.onUpdateHref_), - init - ); - }); + this.ampdoc_.whenFirstVisible().then(() => { + Services.xhrFor(this.ampdoc_.win).fetchJson( + /** @type {string} */ (this.onUpdateHref_), + init + ); + }); }); } } diff --git a/extensions/amp-date-countdown/0.1/amp-date-countdown.js b/extensions/amp-date-countdown/0.1/amp-date-countdown.js index b43e2fb52549..6ac165bf4a48 100644 --- a/extensions/amp-date-countdown/0.1/amp-date-countdown.js +++ b/extensions/amp-date-countdown/0.1/amp-date-countdown.js @@ -154,7 +154,7 @@ export class AmpDateCountdown extends AMP.BaseElement { /** @private {!Object|null} */ this.localeWordList_ = this.getLocaleWord_(this.locale_); - Services.viewerForDoc(this.getAmpDoc()) + this.getAmpDoc() .whenFirstVisible() .then(() => { const EPOCH = this.getEpoch_() + this.offsetSeconds_ * 1000; diff --git a/extensions/amp-date-countdown/0.1/test/test-amp-date-countdown.js b/extensions/amp-date-countdown/0.1/test/test-amp-date-countdown.js index 5b534285a0b7..1a1dbfc4c1a4 100644 --- a/extensions/amp-date-countdown/0.1/test/test-amp-date-countdown.js +++ b/extensions/amp-date-countdown/0.1/test/test-amp-date-countdown.js @@ -26,13 +26,6 @@ describes.realWin( }, env => { let win; - // let sandbox; - - // Viewer-related vars. - // let viewer; - // let whenFirstVisiblePromise; - //let whenFirstVisiblePromiseResolve; - let element; let impl; const ISOEndDate = '2020-06-01T00:00:00+08:00'; @@ -41,23 +34,11 @@ describes.realWin( beforeEach(() => { ({win /*, sandbox*/} = env); - // viewer = Services.viewerForDoc(win.document); - - // whenFirstVisiblePromise = new Promise(resolve => { - // whenFirstVisiblePromiseResolve = resolve; - // }); - // sandbox.stub(viewer, 'whenFirstVisible') - // .callsFake(() => whenFirstVisiblePromise); element = win.document.createElement('amp-date-countdown'); element.setAttribute('end-date', ISOEndDate); win.document.body.appendChild(element); - //element.build(); impl = element.implementation_; - - // sandbox.stub(impl, 'buildCallback'); - // sandbox.spy(impl, 'getYDHMSFromMs_'); - // sandbox.spy(impl, 'getLocaleWord_'); }); it( @@ -235,71 +216,5 @@ describes.realWin( '1 Days 0 Hours 0 Minutes 0 Seconds' ); }); - - // it('should calculate timeleft and have biggest-unit up to hours', () => { - // element.setAttribute('biggest-unit', 'HOURS'); - // element.build(); - // let timeObj; - // let itemElement; - // Services.viewerForDoc(win.document).whenFirstVisible().then(() => { - // debugger; - // //cant even come in here - // timeObj = Object.assign( - // impl.getYDHMSFromMs_(endDate - twoDaysBeforeEndDate), - // impl.getLocaleWord_('en')); - // itemElement = win.document.createElement('div'); - // itemElement.textContent = timeObj.d + ' ' + timeObj.days + ' ' + - // timeObj.h + ' ' + timeObj.hours + ' ' + - // timeObj.m + ' ' + timeObj.minutes + ' ' + - // timeObj.s + ' ' + timeObj.seconds ; - // }).then(() => { - // expect(itemElement.textContent) - // .to.equal('0 Days 48 Hours 0 Minutes 0 Seconds'); - // }); - // }); - - // it('should calculate timeleft and have biggest-unit up to minutes', () => { - // element.setAttribute('biggest-unit', 'MINUTES'); - // element.build(); - - // whenFirstVisiblePromiseResolve(); - - // let timeObj; - // return whenFirstVisiblePromise.then(() => { - // timeObj = Object.assign( - // impl.getYDHMSFromMs_(endDate - twoDaysBeforeEndDate), - // impl.getLocaleWord_('en')); - // }).then(() => { - // const itemElement = win.document.createElement('div'); - // itemElement.textContent = timeObj.d + ' ' + timeObj.days + ' ' + - // timeObj.h + ' ' + timeObj.hours + ' ' + - // timeObj.m + ' ' + timeObj.minutes + ' ' + - // timeObj.s + ' ' + timeObj.seconds ; - // expect(itemElement.textContent) - // .to.equal('0 Days 0 Hours 2880 Minutes 0 Seconds'); - // }); - // }); - - // it('should calculate timeleft and have biggest-unit up to seconds', () => { - // element.setAttribute('biggest-unit', 'SECONDS'); - // element.build(); - - // whenFirstVisiblePromiseResolve(); - - // let timeObj; - // return whenFirstVisiblePromise.then(() => { - // timeObj = Object.assign( - // impl.getYDHMSFromMs_(endDate - twoDaysBeforeEndDate), - // impl.getLocaleWord_('en')); - // }).then(() => { - // const itemElement = win.document.createElement('div'); - // itemElement.textContent = timeObj.d + ' ' + timeObj.days + ' ' + - // timeObj.h + ' ' + timeObj.hours + ' ' + - // timeObj.m + ' ' + timeObj.minutes + ' ' + - // timeObj.s + ' ' + timeObj.seconds ; - // expect(itemElement.textContent) - // .to.equal('0 Days 0 Hours 0 Minutes 172800 Seconds'); - // }); - // }); } ); diff --git a/extensions/amp-experiment/0.1/test/test-variant.js b/extensions/amp-experiment/0.1/test/test-variant.js index 0fdf5c58f800..4c909a1c742a 100644 --- a/extensions/amp-experiment/0.1/test/test-variant.js +++ b/extensions/amp-experiment/0.1/test/test-variant.js @@ -74,15 +74,13 @@ describes.sandboxed('allocateVariant', {}, env => { }) ); - getParamStub = sandbox.stub(); sandbox .stub(Services, 'viewerForDoc') .withArgs(ampdoc) - .returns({ - getParam: getParamStub, - }); + .returns({}); sandbox.stub(ampdoc, 'getHeadNode').returns(fakeHead); + getParamStub = sandbox.stub(ampdoc, 'getParam').returns(null); }); it('should throw for invalid config', () => { diff --git a/extensions/amp-experiment/0.1/variant.js b/extensions/amp-experiment/0.1/variant.js index b2d96f1d8078..900b81cc24dc 100644 --- a/extensions/amp-experiment/0.1/variant.js +++ b/extensions/amp-experiment/0.1/variant.js @@ -80,8 +80,7 @@ export function allocateVariant(ampdoc, experimentName, config) { validateConfig(config); // Variant can be overridden from URL fragment. - const viewer = Services.viewerForDoc(ampdoc); - const override = viewer.getParam(ATTR_PREFIX + experimentName); + const override = ampdoc.getParam(ATTR_PREFIX + experimentName); if (override && hasOwn(config['variants'], override)) { return Promise.resolve(override); } diff --git a/extensions/amp-experiment/1.0/amp-experiment.js b/extensions/amp-experiment/1.0/amp-experiment.js index 828019561f42..7a5065634b10 100644 --- a/extensions/amp-experiment/1.0/amp-experiment.js +++ b/extensions/amp-experiment/1.0/amp-experiment.js @@ -69,7 +69,7 @@ export class AmpExperiment extends AMP.BaseElement { // All experiments can be disabled by a hash param const viewer = Services.viewerForDoc(ampdoc); - const override = viewer.getParam( + const override = ampdoc.getParam( ATTR_PREFIX + 'disable-all-experiments' ); if (override != null) { diff --git a/extensions/amp-experiment/1.0/test/test-amp-experiment.js b/extensions/amp-experiment/1.0/test/test-amp-experiment.js index ffeb67d22007..fd10d5ed4acd 100644 --- a/extensions/amp-experiment/1.0/test/test-amp-experiment.js +++ b/extensions/amp-experiment/1.0/test/test-amp-experiment.js @@ -203,9 +203,7 @@ describes.realWin( .stub(applyExperiment, 'applyExperimentToVariant') .returns(Promise.resolve()); - sandbox.stub(Services, 'viewerForDoc').returns({ - getParam: () => true, - }); + sandbox.stub(ampdoc, 'getParam').returns('true'); experiment.buildCallback(); return Services.variantsForDocOrNull(ampdoc.getHeadNode()) diff --git a/extensions/amp-experiment/1.0/test/test-variant.js b/extensions/amp-experiment/1.0/test/test-variant.js index 771fe2818a65..55cc6ca71aed 100644 --- a/extensions/amp-experiment/1.0/test/test-variant.js +++ b/extensions/amp-experiment/1.0/test/test-variant.js @@ -75,12 +75,10 @@ describes.sandboxed('allocateVariant', {}, env => { }) ); - fakeViewer = { - getParam: () => 'true', - }; - getParamStub = sandbox.stub(fakeViewer, 'getParam').returns('true'); + fakeViewer = {}; sandbox.stub(ampdoc, 'getHeadNode').returns(fakeHead); + getParamStub = sandbox.stub(ampdoc, 'getParam').returns('true'); }); it('should throw for invalid config', () => { diff --git a/extensions/amp-experiment/1.0/variant.js b/extensions/amp-experiment/1.0/variant.js index dc0a4e669cd3..a86997797dbe 100644 --- a/extensions/amp-experiment/1.0/variant.js +++ b/extensions/amp-experiment/1.0/variant.js @@ -86,7 +86,7 @@ export function allocateVariant( validateExperiment(experimentName, experimentObject); // Variant can be overridden from URL fragment. - const override = viewer.getParam(ATTR_PREFIX + experimentName); + const override = ampdoc.getParam(ATTR_PREFIX + experimentName); if (override && hasOwn(experimentObject['variants'], override)) { return Promise.resolve(override); } diff --git a/extensions/amp-form/0.1/amp-form.js b/extensions/amp-form/0.1/amp-form.js index eb4f18d9833e..e9ccc153d611 100644 --- a/extensions/amp-form/0.1/amp-form.js +++ b/extensions/amp-form/0.1/amp-form.js @@ -134,6 +134,9 @@ export class AmpForm { /** @const @private {!HTMLFormElement} */ this.form_ = element; + /** @const @private {!../../../src/service/ampdoc-impl.AmpDoc} */ + this.ampdoc_ = Services.ampdoc(this.form_); + /** @const @private {!../../../src/service/template-impl.Templates} */ this.templates_ = Services.templatesFor(this.win_); @@ -359,7 +362,7 @@ export class AmpForm { /** @private */ installEventHandlers_() { - this.viewer_.whenNextVisible().then(() => { + this.ampdoc_.whenNextVisible().then(() => { const autofocus = this.form_.querySelector('[autofocus]'); if (autofocus) { tryFocus(autofocus); diff --git a/extensions/amp-form/0.1/test/test-amp-form.js b/extensions/amp-form/0.1/test/test-amp-form.js index 71f72c63a236..42c437aab25e 100644 --- a/extensions/amp-form/0.1/test/test-amp-form.js +++ b/extensions/amp-form/0.1/test/test-amp-form.js @@ -543,16 +543,15 @@ describes.repeated( button1.setAttribute('autofocus', ''); new AmpForm(form); - const viewer = Services.viewerForDoc(env.ampdoc); let resolve_ = null; - sandbox.stub(viewer, 'whenNextVisible').returns( + sandbox.stub(env.ampdoc, 'whenNextVisible').returns( new Promise(resolve => { resolve_ = resolve; }) ); expect(document.activeElement).to.not.equal(button1); - viewer.whenNextVisible().then(() => { + env.ampdoc.whenNextVisible().then(() => { expect(document.activeElement).to.equal(button1); }); return timer.promise(1).then(() => resolve_()); diff --git a/extensions/amp-fx-collection/0.1/amp-fx-collection.js b/extensions/amp-fx-collection/0.1/amp-fx-collection.js index 676cb1485ee7..9c8c69bd1cd6 100644 --- a/extensions/amp-fx-collection/0.1/amp-fx-collection.js +++ b/extensions/amp-fx-collection/0.1/amp-fx-collection.js @@ -21,7 +21,6 @@ import { FxType, // eslint-disable-line no-unused-vars getFxTypes, } from './fx-type'; -import {Services} from '../../../src/services'; import {devAssert, rethrowAsync} from '../../../src/log'; import { installPositionBoundFx, @@ -48,18 +47,13 @@ export class AmpFxCollection { /** @private @const {!Array} */ this.seen_ = []; - /** @private @const {!../../../src/service/viewer-interface.ViewerInterface} */ - this.viewer_ = Services.viewerForDoc(ampdoc); - - Promise.all([ampdoc.whenReady(), this.viewer_.whenFirstVisible()]).then( - () => { - const root = this.ampdoc_.getRootNode(); - // Scan when page becomes visible. - this.scan_(); - // Rescan as DOM changes happen. - listen(root, AmpEvents.DOM_UPDATE, () => this.scan_()); - } - ); + Promise.all([ampdoc.whenReady(), ampdoc.whenFirstVisible()]).then(() => { + const root = this.ampdoc_.getRootNode(); + // Scan when page becomes visible. + this.scan_(); + // Rescan as DOM changes happen. + listen(root, AmpEvents.DOM_UPDATE, () => this.scan_()); + }); } /** @@ -89,7 +83,7 @@ export class AmpFxCollection { register_(element) { devAssert(element.hasAttribute('amp-fx')); devAssert(!this.seen_.includes(element)); - devAssert(this.viewer_.isVisible()); + devAssert(this.ampdoc_.isVisible()); getFxTypes(element).forEach(type => { this.install_(element, type); diff --git a/extensions/amp-instagram/0.1/amp-instagram.js b/extensions/amp-instagram/0.1/amp-instagram.js index 7d14667b4131..903fce5a157b 100644 --- a/extensions/amp-instagram/0.1/amp-instagram.js +++ b/extensions/amp-instagram/0.1/amp-instagram.js @@ -36,7 +36,6 @@ */ import {CSS} from '../../../build/amp-instagram-0.1.css'; -import {Services} from '../../../src/services'; import {getData, listen} from '../../../src/event-helper'; import {isLayoutSizeDefined} from '../../../src/layout'; import {isObject} from '../../../src/types'; @@ -111,7 +110,7 @@ class AmpInstagram extends AMP.BaseElement { // This will redirect to the image URL. By experimentation this is // always the same URL that is actually used inside of the embed. - Services.viewerForDoc(this.element) + this.getAmpDoc() .whenFirstVisible() .then(() => { image.setAttribute( diff --git a/extensions/amp-instagram/0.1/test/test-amp-instagram.js b/extensions/amp-instagram/0.1/test/test-amp-instagram.js index 6f74755b0285..ee9c2682714b 100644 --- a/extensions/amp-instagram/0.1/test/test-amp-instagram.js +++ b/extensions/amp-instagram/0.1/test/test-amp-instagram.js @@ -15,7 +15,6 @@ */ import '../amp-instagram'; -import {Services} from '../../../../src/services'; describes.realWin( 'amp-instagram', @@ -51,7 +50,7 @@ describes.realWin( ins.setAttribute('data-captioned', ''); } const visibilityPromise = env.sandbox.stub( - Services.viewerForDoc(doc), + env.ampdoc, 'whenFirstVisible' ); visibilityPromise.returns( diff --git a/extensions/amp-install-serviceworker/0.1/amp-install-serviceworker.js b/extensions/amp-install-serviceworker/0.1/amp-install-serviceworker.js index e8abcde1844e..837a309aabd9 100644 --- a/extensions/amp-install-serviceworker/0.1/amp-install-serviceworker.js +++ b/extensions/amp-install-serviceworker/0.1/amp-install-serviceworker.js @@ -124,7 +124,7 @@ export class AmpInstallServiceWorker extends AMP.BaseElement { whenLoadedAndVisiblePromise_() { return Promise.all([ this.loadPromise(this.win), - Services.viewerForDoc(this.getAmpDoc()).whenFirstVisible(), + this.getAmpDoc().whenFirstVisible(), ]); } diff --git a/extensions/amp-install-serviceworker/0.1/test/test-amp-install-serviceworker.js b/extensions/amp-install-serviceworker/0.1/test/test-amp-install-serviceworker.js index fcdba4d9ece6..59771361eafe 100644 --- a/extensions/amp-install-serviceworker/0.1/test/test-amp-install-serviceworker.js +++ b/extensions/amp-install-serviceworker/0.1/test/test-amp-install-serviceworker.js @@ -638,7 +638,7 @@ describes.fakeWin( expect(preloadStub).to.not.be.called; return loadPromise(win) .then(() => { - return viewer.whenFirstVisible(); + return ampdoc.whenFirstVisible(); }) .then(() => { expect(preloadStub).to.be.calledOnce; diff --git a/extensions/amp-lightbox-gallery/0.1/amp-lightbox-gallery.js b/extensions/amp-lightbox-gallery/0.1/amp-lightbox-gallery.js index 7cffac9ddc3e..ff1b25ab7bfa 100644 --- a/extensions/amp-lightbox-gallery/0.1/amp-lightbox-gallery.js +++ b/extensions/amp-lightbox-gallery/0.1/amp-lightbox-gallery.js @@ -215,8 +215,7 @@ export class AmpLightboxGallery extends AMP.BaseElement { this.manager_ = manager; this.history_ = Services.historyForDoc(this.getAmpDoc()); this.action_ = Services.actionServiceForDoc(this.element); - const viewer = Services.viewerForDoc(this.getAmpDoc()); - return viewer.whenFirstVisible(); + return this.getAmpDoc().whenFirstVisible(); }) .then(() => { this.container_ = htmlFor(/** @type {!Document} */ (this.doc_))` diff --git a/extensions/amp-live-list/0.1/live-list-manager.js b/extensions/amp-live-list/0.1/live-list-manager.js index e7a549d36cd6..e1c34f352595 100644 --- a/extensions/amp-live-list/0.1/live-list-manager.js +++ b/extensions/amp-live-list/0.1/live-list-manager.js @@ -53,9 +53,6 @@ export class LiveListManager { /** @private @const {!Object} */ this.liveLists_ = Object.create(null); - /** @private @const {!../../../src/service/viewer-interface.ViewerInterface} */ - this.viewer_ = Services.viewerForDoc(this.ampdoc); - /** @private @const {!../../../src/service/extensions-impl.Extensions} */ this.extensions_ = Services.extensionsFor(this.ampdoc.win); @@ -80,10 +77,10 @@ export class LiveListManager { /** @private @const {boolean} */ this.isTransformed_ = isDocTransformed(ampdoc.getRootNode()); - // Only start polling when doc is ready and when the viewer is visible. + // Only start polling when doc is ready and when the doc is visible. this.whenDocReady_().then(() => { // Switch out the poller interval if we can find a lower one and - // then make sure to stop polling if viewer is not visible. + // then make sure to stop polling if doc is not visible. this.interval_ = Math.min.apply(Math, this.intervals_); const initialUpdateTimes = Object.keys(this.liveLists_).map(key => @@ -107,7 +104,7 @@ export class LiveListManager { this.poller_ = new Poller(this.ampdoc.win, this.interval_, this.work_); // If no live-list is active on dom ready, we don't need to poll at all. - if (this.viewer_.isVisible() && this.hasActiveLiveLists_()) { + if (this.ampdoc.isVisible() && this.hasActiveLiveLists_()) { this.poller_.start(); } this.setupVisibilityHandler_(); @@ -281,7 +278,7 @@ export class LiveListManager { // Polling may not be started yet if no live lists were registered by // doc ready in LiveListManager's constructor. - if (liveList.isEnabled() && this.poller_ && this.viewer_.isVisible()) { + if (liveList.isEnabled() && this.poller_ && this.ampdoc.isVisible()) { this.poller_.start(); } } @@ -296,13 +293,13 @@ export class LiveListManager { } /** - * Listens to he viewer visibility changed event. + * Listens to he doc visibility changed event. * @private */ setupVisibilityHandler_() { // Polling should always be stopped when document is no longer visible. - this.viewer_.onVisibilityChanged(() => { - if (this.viewer_.isVisible()) { + this.ampdoc.onVisibilityChanged(() => { + if (this.ampdoc.isVisible()) { // We use immediate so that the user starts getting updates // right away when they've switched back to the page. this.poller_.start(/** immediate */ true); diff --git a/extensions/amp-live-list/0.1/test/test-live-list-manager.js b/extensions/amp-live-list/0.1/test/test-live-list-manager.js index 698546e73b76..b8732dae98bc 100644 --- a/extensions/amp-live-list/0.1/test/test-live-list-manager.js +++ b/extensions/amp-live-list/0.1/test/test-live-list-manager.js @@ -18,7 +18,6 @@ import { AMP_LIVE_LIST_CUSTOM_SLOT_ID, LiveListManager, } from '../live-list-manager'; -import {Services} from '../../../../src/services'; const XHR_BUFFER_SIZE = 2; @@ -30,7 +29,6 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { let liveList; let xhrs; let clock; - let viewer; let ready; let sandbox; @@ -42,7 +40,6 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { clock = sandbox.useFakeTimers(); xhrs = setUpMockXhrs(sandbox); - viewer = Services.viewerForDoc(ampdoc); manager = new LiveListManager(ampdoc); const docReadyPromise = new Promise(resolve => { @@ -138,7 +135,7 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { }); it('should start poller when doc is ready', () => { - sandbox.stub(viewer, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'isVisible').returns(true); expect(manager.poller_).to.be.null; liveList.buildCallback(); ready(); @@ -148,7 +145,7 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { }); it('should not start poller when no live-list is registered', () => { - sandbox.stub(viewer, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'isVisible').returns(true); expect(manager.poller_).to.be.null; ready(); return manager.whenDocReady_().then(() => { @@ -558,7 +555,7 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { it('should recover after transient 415 response', () => { sandbox.stub(Math, 'random').callsFake(() => 1); - sandbox.stub(viewer, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'isVisible').returns(true); ready(); const fetchSpy = sandbox.spy(manager, 'work_'); liveList.buildCallback(); @@ -603,7 +600,7 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { }); it( - 'should stop all polling if viewer is not visible ' + + 'should stop all polling if ampdoc is not visible ' + 'and immediately fetch when visible', () => { ready(); @@ -611,31 +608,21 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { expect(fetchSpy).to.have.not.been.called; liveList.buildCallback(); return manager.whenDocReady_().then(() => { - expect(viewer.isVisible()).to.be.true; + expect(ampdoc.isVisible()).to.be.true; expect(manager.poller_.isRunning()).to.be.true; - viewer.receiveMessage('visibilitychange', { - state: 'hidden', - }); + ampdoc.overrideVisibilityState('hidden'); expect(fetchSpy).to.have.not.been.called; expect(manager.poller_.isRunning()).to.be.false; - viewer.receiveMessage('visibilitychange', { - state: 'visible', - }); + ampdoc.overrideVisibilityState('visible'); expect(fetchSpy).to.be.calledOnce; expect(manager.poller_.isRunning()).to.be.true; - viewer.receiveMessage('visibilitychange', { - state: 'inactive', - }); + ampdoc.overrideVisibilityState('inactive'); expect(fetchSpy).to.be.calledOnce; expect(manager.poller_.isRunning()).to.be.false; - viewer.receiveMessage('visibilitychange', { - state: 'visible', - }); + ampdoc.overrideVisibilityState('visible'); expect(fetchSpy).to.have.callCount(2); expect(manager.poller_.isRunning()).to.be.true; - viewer.receiveMessage('visibilitychange', { - state: 'prerender', - }); + ampdoc.overrideVisibilityState('prerender'); expect(fetchSpy).to.have.callCount(2); expect(manager.poller_.isRunning()).to.be.false; clock.tick(20000); @@ -646,7 +633,7 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { it('should fetch with url', () => { sandbox.stub(Math, 'random').callsFake(() => 1); - sandbox.stub(viewer, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'isVisible').returns(true); manager.url_ = 'www.example.com/foo/bar?hello=world#dev=1'; ready(); const fetchSpy = sandbox.spy(manager, 'work_'); @@ -671,7 +658,7 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { 'and is transformed', () => { sandbox.stub(Math, 'random').callsFake(() => 1); - sandbox.stub(viewer, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'isVisible').returns(true); manager.url_ = 'https://www.example.com/foo/bar?hello=world#dev=1'; manager.isTransformed_ = true; ready(); @@ -700,7 +687,7 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { 'and is not transformed', () => { sandbox.stub(Math, 'random').callsFake(() => 1); - sandbox.stub(viewer, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'isVisible').returns(true); manager.url_ = 'www.example.com/foo/bar?hello=world#dev=1'; manager.isTransformed_ = false; manager.location_ = @@ -744,7 +731,7 @@ describes.fakeWin('LiveListManager', {amp: true}, env => { it('should add amp_latest_update_time on requests', () => { sandbox.stub(Math, 'random').callsFake(() => 1); - sandbox.stub(viewer, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'isVisible').returns(true); manager.url_ = 'www.example.com/foo/bar?hello=world#dev=1'; sandbox.stub(liveList, 'update').returns(2500); ready(); diff --git a/extensions/amp-orientation-observer/0.1/amp-orientation-observer.js b/extensions/amp-orientation-observer/0.1/amp-orientation-observer.js index 90d9587fb71a..6ad1171e7400 100644 --- a/extensions/amp-orientation-observer/0.1/amp-orientation-observer.js +++ b/extensions/amp-orientation-observer/0.1/amp-orientation-observer.js @@ -62,8 +62,7 @@ export class AmpOrientationObserver extends AMP.BaseElement { // layoutCallback is meaningless. We delay the heavy work until // we become visible. this.action_ = Services.actionServiceForDoc(this.element); - const viewer = Services.viewerForDoc(this.ampdoc_); - viewer.whenFirstVisible().then(this.init_.bind(this)); + this.ampdoc_.whenFirstVisible().then(this.init_.bind(this)); } /** diff --git a/extensions/amp-position-observer/0.1/amp-position-observer.js b/extensions/amp-position-observer/0.1/amp-position-observer.js index d723cbe362f9..6ea60727bfd4 100644 --- a/extensions/amp-position-observer/0.1/amp-position-observer.js +++ b/extensions/amp-position-observer/0.1/amp-position-observer.js @@ -112,8 +112,9 @@ export class AmpVisibilityObserver extends AMP.BaseElement { // Since this is a functional component and not visual, // layoutCallback is meaningless. We delay the heavy work until // we become visible. - const viewer = Services.viewerForDoc(this.getAmpDoc()); - viewer.whenFirstVisible().then(this.init_.bind(this)); + this.getAmpDoc() + .whenFirstVisible() + .then(this.init_.bind(this)); this.runOnce_ = this.element.hasAttribute('once'); } diff --git a/extensions/amp-skimlinks/0.1/amp-skimlinks.js b/extensions/amp-skimlinks/0.1/amp-skimlinks.js index 9bb630436563..a239c7e9a528 100644 --- a/extensions/amp-skimlinks/0.1/amp-skimlinks.js +++ b/extensions/amp-skimlinks/0.1/amp-skimlinks.js @@ -123,16 +123,12 @@ export class AmpSkimlinks extends AMP.BaseElement { sendImpressionTracking_(beaconData) { // Update tracking service with extra info. this.trackingService_.setTrackingInfo({guid: beaconData['guid']}); - const viewer = Services.viewerForDoc( - /** @type {!../../../src/service/ampdoc-impl.AmpDoc} */ - (this.ampDoc_) - ); /* WARNING: Up to here, the code may have been executed during page - pre-rendering. Wait for the page to be visible in the viewer before + pre-rendering. Wait for the page to be visible in the doc before sending impression tracking. */ - viewer.whenFirstVisible().then(() => { + this.ampDoc_.whenFirstVisible().then(() => { this.trackingService_.sendImpressionTracking( this.skimlinksLinkRewriter_.getAnchorReplacementList() ); diff --git a/extensions/amp-skimlinks/0.1/test/test-amp-skimlinks.js b/extensions/amp-skimlinks/0.1/test/test-amp-skimlinks.js index 64e5b7058cef..7defdd75120a 100644 --- a/extensions/amp-skimlinks/0.1/test/test-amp-skimlinks.js +++ b/extensions/amp-skimlinks/0.1/test/test-amp-skimlinks.js @@ -369,12 +369,9 @@ describes.fakeWin( it('Should wait until visible to send the impression tracking', () => { const isVisibleDefer = new Deferred(); - const fakeViewer = { - whenFirstVisible: env.sandbox - .stub() - .returns(isVisibleDefer.promise), - }; - helpers.mockServiceGetter('viewerForDoc', fakeViewer); + sandbox + .stub(ampdoc, 'whenFirstVisible') + .returns(isVisibleDefer.promise); return ampSkimlinks.onPageScanned_().then(() => { const stub = ampSkimlinks.trackingService_.sendImpressionTracking; diff --git a/extensions/amp-smartlinks/0.1/amp-smartlinks.js b/extensions/amp-smartlinks/0.1/amp-smartlinks.js index b4754265b405..25c7c1d3147a 100644 --- a/extensions/amp-smartlinks/0.1/amp-smartlinks.js +++ b/extensions/amp-smartlinks/0.1/amp-smartlinks.js @@ -76,7 +76,7 @@ export class AmpSmartlinks extends AMP.BaseElement { .then(() => viewer.getReferrerUrl()) .then(referrer => { this.referrer_ = referrer; - viewer.whenFirstVisible().then(() => { + this.ampDoc_.whenFirstVisible().then(() => { this.runSmartlinks_(); }); }); diff --git a/extensions/amp-smartlinks/0.1/test/test-amp-smartlinks.js b/extensions/amp-smartlinks/0.1/test/test-amp-smartlinks.js index d7f4b6b39b25..95ee169995f3 100644 --- a/extensions/amp-smartlinks/0.1/test/test-amp-smartlinks.js +++ b/extensions/amp-smartlinks/0.1/test/test-amp-smartlinks.js @@ -127,8 +127,6 @@ describes.fakeWin( }); describe('runSmartlinks_', () => { - let fakeViewer; - beforeEach(() => { const options = { 'nrtv-account-name': 'thisisnotapublisher', @@ -137,7 +135,6 @@ describes.fakeWin( }; ampSmartlinks = helpers.createAmpSmartlinks(options); - fakeViewer = Services.viewerForDoc(env.ampdoc); env.sandbox .stub(ampSmartlinks, 'getLinkmateOptions_') @@ -149,7 +146,7 @@ describes.fakeWin( env.sandbox.spy(ampSmartlinks, 'postPageImpression_'); return ampSmartlinks.buildCallback().then(() => { - fakeViewer.whenFirstVisible().then(() => { + env.ampdoc.whenFirstVisible().then(() => { expect(ampSmartlinks.postPageImpression_.calledOnce).to.be.true; }); }); @@ -159,7 +156,7 @@ describes.fakeWin( env.sandbox.spy(ampSmartlinks, 'initLinkRewriter_'); return ampSmartlinks.buildCallback().then(() => { - fakeViewer.whenFirstVisible().then(() => { + env.ampdoc.whenFirstVisible().then(() => { expect(ampSmartlinks.initLinkRewriter_.calledOnce).to.be.true; }); }); diff --git a/extensions/amp-story/0.1/amp-story.js b/extensions/amp-story/0.1/amp-story.js index 8b117d67d72c..14070c85bdaa 100644 --- a/extensions/amp-story/0.1/amp-story.js +++ b/extensions/amp-story/0.1/amp-story.js @@ -655,7 +655,7 @@ export class AmpStory extends AMP.BaseElement { // Story is being prerendered: resolve the layoutCallback when the first // page is built. Other pages will only build if the document becomes // visible. - if (!Services.viewerForDoc(this.element).hasBeenVisible()) { + if (!this.getAmpDoc().hasBeenVisible()) { return whenUpgradedToCustomElement(firstPageEl).then(() => firstPageEl.whenBuilt() ); diff --git a/extensions/amp-story/1.0/amp-story.js b/extensions/amp-story/1.0/amp-story.js index eee8dfd5147c..1e13ea41d025 100644 --- a/extensions/amp-story/1.0/amp-story.js +++ b/extensions/amp-story/1.0/amp-story.js @@ -772,7 +772,7 @@ export class AmpStory extends AMP.BaseElement { } }); - this.viewer_.onVisibilityChanged(() => this.onVisibilityChanged_()); + this.getAmpDoc().onVisibilityChanged(() => this.onVisibilityChanged_()); this.getViewport().onResize(debounce(this.win, () => this.onResize(), 300)); this.installGestureRecognizers_(); @@ -988,7 +988,7 @@ export class AmpStory extends AMP.BaseElement { // Story is being prerendered: resolve the layoutCallback when the first // page is built. Other pages will only build if the document becomes // visible. - if (!this.viewer_.hasBeenVisible()) { + if (!this.getAmpDoc().hasBeenVisible()) { return whenUpgradedToCustomElement(firstPageEl).then(() => { return Promise.all([ firstPageEl.whenBuilt(), @@ -1747,7 +1747,7 @@ export class AmpStory extends AMP.BaseElement { * @private */ onVisibilityChanged_() { - this.viewer_.isVisible() ? this.resumeCallback() : this.pauseCallback(); + this.getAmpDoc().isVisible() ? this.resumeCallback() : this.pauseCallback(); } /** diff --git a/extensions/amp-story/1.0/test/test-amp-story.js b/extensions/amp-story/1.0/test/test-amp-story.js index 88696757a410..3ba9bf0cbe0e 100644 --- a/extensions/amp-story/1.0/test/test-amp-story.js +++ b/extensions/amp-story/1.0/test/test-amp-story.js @@ -50,7 +50,7 @@ describes.realWin( }, }, env => { - let win; + let win, ampdoc; let element; let hasSwipeCapability = false; let story; @@ -100,6 +100,7 @@ describes.realWin( beforeEach(() => { win = env.win; + ampdoc = env.ampdoc; replaceStateStub = sandbox.stub(win.history, 'replaceState'); // Required by the bookend code. @@ -680,9 +681,9 @@ describes.realWin( it('should pause the story when tab becomes inactive', () => { createPages(story.element, 2, ['cover', 'page-1']); - sandbox.stub(story.viewer_, 'isVisible').returns(false); + sandbox.stub(ampdoc, 'isVisible').returns(false); const onVisibilityChangedStub = sandbox.stub( - story.viewer_, + ampdoc, 'onVisibilityChanged' ); @@ -702,9 +703,9 @@ describes.realWin( it('should play the story when tab becomes active', () => { createPages(story.element, 2, ['cover', 'page-1']); - sandbox.stub(story.viewer_, 'isVisible').returns(true); + sandbox.stub(ampdoc, 'isVisible').returns(true); const onVisibilityChangedStub = sandbox.stub( - story.viewer_, + ampdoc, 'onVisibilityChanged' ); diff --git a/extensions/amp-subscriptions/0.1/amp-subscriptions.js b/extensions/amp-subscriptions/0.1/amp-subscriptions.js index bc25abaf2630..9e0552e84069 100644 --- a/extensions/amp-subscriptions/0.1/amp-subscriptions.js +++ b/extensions/amp-subscriptions/0.1/amp-subscriptions.js @@ -285,7 +285,7 @@ export class SubscriptionService { // page to become visible, all others wait for whenFirstVisible() const visiblePromise = subscriptionPlatform.isPrerenderSafe() ? Promise.resolve() - : this.viewer_.whenFirstVisible(); + : this.ampdoc_.whenFirstVisible(); return visiblePromise.then(() => { return this.timer_ .timeoutPromise(timeout, subscriptionPlatform.getEntitlements()) diff --git a/extensions/amp-subscriptions/0.1/test/test-amp-subscriptions.js b/extensions/amp-subscriptions/0.1/test/test-amp-subscriptions.js index eeb006e85eaa..d51367b1fa0a 100644 --- a/extensions/amp-subscriptions/0.1/test/test-amp-subscriptions.js +++ b/extensions/amp-subscriptions/0.1/test/test-amp-subscriptions.js @@ -615,7 +615,7 @@ describes.fakeWin('AmpSubscriptions', {amp: true}, env => { beforeEach(() => { serviceAdapter = new ServiceAdapter(subscriptionService); firstVisibleStub = sandbox - .stub(subscriptionService.viewer_, 'whenFirstVisible') + .stub(ampdoc, 'whenFirstVisible') .callsFake(() => Promise.resolve()); subscriptionService.pageConfig_ = pageConfig; platform = localSubscriptionPlatformFactory( diff --git a/extensions/amp-subscriptions/0.1/test/test-viewer-tracker.js b/extensions/amp-subscriptions/0.1/test/test-viewer-tracker.js index b108f0f18635..0bded1806c89 100644 --- a/extensions/amp-subscriptions/0.1/test/test-viewer-tracker.js +++ b/extensions/amp-subscriptions/0.1/test/test-viewer-tracker.js @@ -31,7 +31,7 @@ describes.realWin('ViewerTracker', {amp: true}, env => { describe('scheduleView', () => { it('should call `reportWhenViewed_`, if viewer is visible', () => { const whenViewedStub = sandbox.stub(viewTracker, 'reportWhenViewed_'); - sandbox.stub(viewTracker.viewer_, 'isVisible').callsFake(() => true); + sandbox.stub(ampdoc, 'isVisible').returns(true); return viewTracker.scheduleView(2000).then(() => { expect(whenViewedStub).to.be.calledOnce; }); @@ -40,12 +40,9 @@ describes.realWin('ViewerTracker', {amp: true}, env => { it('should call `reportWhenViewed_`, when viewer gets visible', () => { let visibleState = false; const whenViewedStub = sandbox.stub(viewTracker, 'reportWhenViewed_'); - const visibilityChangedStub = sandbox.stub( - viewTracker.viewer_, - 'onVisibilityChanged' - ); + const visibilityChangedStub = sandbox.stub(ampdoc, 'onVisibilityChanged'); const visibilitySandbox = sandbox - .stub(viewTracker.viewer_, 'isVisible') + .stub(ampdoc, 'isVisible') .callsFake(() => visibleState); const viewPromise = viewTracker.scheduleView(2000); diff --git a/extensions/amp-subscriptions/0.1/viewer-tracker.js b/extensions/amp-subscriptions/0.1/viewer-tracker.js index 4ebfa89ea0bd..88792dbb588d 100644 --- a/extensions/amp-subscriptions/0.1/viewer-tracker.js +++ b/extensions/amp-subscriptions/0.1/viewer-tracker.js @@ -29,9 +29,6 @@ export class ViewerTracker { /** @private */ this.ampdoc_ = ampdoc; - /** @private @const {!../../../src/service/viewer-interface.ViewerInterface} */ - this.viewer_ = Services.viewerForDoc(ampdoc); - /** @private {?Promise} */ this.reportViewPromise_ = null; @@ -50,11 +47,11 @@ export class ViewerTracker { this.reportViewPromise_ = null; return this.ampdoc_.whenReady().then(() => { return new Promise(resolve => { - if (this.viewer_.isVisible()) { + if (this.ampdoc_.isVisible()) { resolve(); } - this.viewer_.onVisibilityChanged(() => { - if (this.viewer_.isVisible()) { + this.ampdoc_.onVisibilityChanged(() => { + if (this.ampdoc_.isVisible()) { resolve(); } }); @@ -102,8 +99,8 @@ export class ViewerTracker { return new Promise((resolve, reject) => { // 1. Document becomes invisible again: cancel. unlistenSet.push( - this.viewer_.onVisibilityChanged(() => { - if (!this.viewer_.isVisible()) { + this.ampdoc_.onVisibilityChanged(() => { + if (!this.ampdoc_.isVisible()) { reject(cancellation()); } }) diff --git a/extensions/amp-user-notification/0.1/amp-user-notification.js b/extensions/amp-user-notification/0.1/amp-user-notification.js index 2b95677c8f3a..ab965de80d9b 100644 --- a/extensions/amp-user-notification/0.1/amp-user-notification.js +++ b/extensions/amp-user-notification/0.1/amp-user-notification.js @@ -472,15 +472,12 @@ export class UserNotificationManager { /** @private @const {!Object} */ this.deferRegistry_ = Object.create(null); - /** @private @const {!../../../src/service/viewer-interface.ViewerInterface} */ - this.viewer_ = Services.viewerForDoc(this.ampdoc); - /** @private @const {!Promise} */ this.documentReadyPromise_ = this.ampdoc.whenReady(); /** @private @const {!Promise} */ this.managerReadyPromise_ = Promise.all([ - this.viewer_.whenFirstVisible(), + this.ampdoc.whenFirstVisible(), this.documentReadyPromise_, ]); diff --git a/extensions/amp-video/0.1/amp-video.js b/extensions/amp-video/0.1/amp-video.js index 1f5a2ce2a6e5..01224df04867 100644 --- a/extensions/amp-video/0.1/amp-video.js +++ b/extensions/amp-video/0.1/amp-video.js @@ -312,14 +312,15 @@ class AmpVideo extends AMP.BaseElement { // If we are in prerender mode, only propagate cached sources and then // when document becomes visible propagate origin sources and other children // If not in prerender mode, propagate everything. - const viewer = Services.viewerForDoc(this.getAmpDoc()); - if (viewer.getVisibilityState() == VisibilityState.PRERENDER) { + if (this.getAmpDoc().getVisibilityState() == VisibilityState.PRERENDER) { if (!this.element.hasAttribute('preload')) { this.video_.setAttribute('preload', 'auto'); } - viewer.whenFirstVisible().then(() => { - this.propagateLayoutChildren_(); - }); + this.getAmpDoc() + .whenFirstVisible() + .then(() => { + this.propagateLayoutChildren_(); + }); } else { this.propagateLayoutChildren_(); } diff --git a/extensions/amp-video/0.1/test/test-amp-video.js b/extensions/amp-video/0.1/test/test-amp-video.js index 5d477a8d694f..93cd71a55c75 100644 --- a/extensions/amp-video/0.1/test/test-amp-video.js +++ b/extensions/amp-video/0.1/test/test-amp-video.js @@ -19,7 +19,6 @@ import {Services} from '../../../../src/services'; import {VideoEvents} from '../../../../src/video-interface'; import {VisibilityState} from '../../../../src/visibility-state'; import {listenOncePromise} from '../../../../src/event-helper'; -import {mockServiceForDoc} from '../../../../testing/test-helper'; import {toggleExperiment} from '../../../../src/experiments'; describes.realWin( @@ -650,18 +649,18 @@ describes.realWin( let makeVisible; let visiblePromise; let video; - let viewerMock; + let visibilityStubs; beforeEach(() => { - viewerMock = mockServiceForDoc(sandbox, env.ampdoc, 'viewer', [ - 'getVisibilityState', - 'whenFirstVisible', - ]); - viewerMock.getVisibilityState.returns(VisibilityState.PRERENDER); + visibilityStubs = { + getVisibilityState: sandbox.stub(env.ampdoc, 'getVisibilityState'), + whenFirstVisible: sandbox.stub(env.ampdoc, 'whenFirstVisible'), + }; + visibilityStubs.getVisibilityState.returns(VisibilityState.PRERENDER); visiblePromise = new Promise(resolve => { makeVisible = resolve; }); - viewerMock.whenFirstVisible.returns(visiblePromise); + visibilityStubs.whenFirstVisible.returns(visiblePromise); }); describe('should not prerender if no cached sources', () => { diff --git a/extensions/amp-viewer-integration/0.1/highlight-handler.js b/extensions/amp-viewer-integration/0.1/highlight-handler.js index 46f009212442..de364f3a7b75 100644 --- a/extensions/amp-viewer-integration/0.1/highlight-handler.js +++ b/extensions/amp-viewer-integration/0.1/highlight-handler.js @@ -196,8 +196,8 @@ export class HighlightHandler { onVisibleOnce(handler) { // TODO(yunabe): Unregister the handler. handler = once(handler); - this.viewer_.onVisibilityChanged(() => { - if (this.viewer_.getVisibilityState() != 'visible') { + this.ampdoc_.onVisibilityChanged(() => { + if (this.ampdoc_.getVisibilityState() != 'visible') { return; } handler(); @@ -237,7 +237,7 @@ export class HighlightHandler { }); } - const visibility = this.viewer_.getVisibilityState(); + const visibility = this.ampdoc_.getVisibilityState(); if (!highlightInfo.skipScrollAnimation) { if (visibility == 'visible') { this.animateScrollToTop_(scrollTop); diff --git a/extensions/amp-viewer-integration/0.1/test/test-highlight-handler.js b/extensions/amp-viewer-integration/0.1/test/test-highlight-handler.js index 0f16a8361010..51173e7dd60d 100644 --- a/extensions/amp-viewer-integration/0.1/test/test-highlight-handler.js +++ b/extensions/amp-viewer-integration/0.1/test/test-highlight-handler.js @@ -344,7 +344,7 @@ describes.realWin( 'setScrollTop' ); sandbox - .stub(Services.viewerForDoc(ampdoc), 'getVisibilityState') + .stub(ampdoc, 'getVisibilityState') .returns(VisibilityState.PRERENDER); new HighlightHandler(ampdoc, {sentences: ['amp', 'highlight']}); diff --git a/src/chunk.js b/src/chunk.js index 426d6d8fee45..bdb2ec1139e2 100644 --- a/src/chunk.js +++ b/src/chunk.js @@ -248,9 +248,6 @@ class StartupTask extends Task { constructor(fn, win, chunks) { super(fn); - /** @private @const */ - this.win_ = win; - /** @private @const */ this.chunks_ = chunks; } @@ -270,11 +267,10 @@ class StartupTask extends Task { /** @override */ useRequestIdleCallback_() { - // We only start using requestIdleCallback when the viewer has + // We only start using requestIdleCallback when the core runtime has // been initialized. Otherwise we risk starving ourselves - // before we get into a state where the viewer can tell us - // that we are visible. - return !!this.chunks_.viewer; + // before the render-critical work is done. + return this.chunks_.coreReady_; } /** @@ -282,16 +278,7 @@ class StartupTask extends Task { * @private */ isVisible_() { - // Ask the viewer first. - if (this.chunks_.viewer) { - return this.chunks_.viewer.isVisible(); - } - // There is no viewer yet. Lets try to guess whether we are visible. - if (this.win_.document.hidden) { - return false; - } - // Viewers send a URL param if we are not visible. - return !/visibilityState=(hidden|prerender)/.test(this.win_.location.hash); + return this.chunks_.ampdoc.isVisible(); } } @@ -303,6 +290,8 @@ class Chunks { * @param {!./service/ampdoc-impl.AmpDoc} ampDoc */ constructor(ampDoc) { + /** @protected @const {!./service/ampdoc-impl.AmpDoc} */ + this.ampdoc = ampDoc; /** @private @const {!Window} */ this.win_ = ampDoc.win; /** @private @const {!PriorityQueue} */ @@ -335,17 +324,18 @@ class Chunks { } }); - /** @private @const {!Promise} */ - this.viewerPromise_ = Services.viewerPromiseForDoc(ampDoc); - /** @protected {?./service/viewer-interface.ViewerInterface} */ - this.viewer = null; - this.viewerPromise_.then(viewer => { - this.viewer = viewer; - viewer.onVisibilityChanged(() => { - if (viewer.isVisible()) { - this.schedule_(); - } - }); + /** @protected {boolean} */ + this.coreReady_ = false; + Services.viewerPromiseForDoc(ampDoc).then(() => { + // Once the viewer has been resolved, most of core runtime has been + // initialized as well. + this.coreReady_ = true; + }); + + ampDoc.onVisibilityChanged(() => { + if (ampDoc.isVisible()) { + this.schedule_(); + } }); } diff --git a/src/iframe-attributes.js b/src/iframe-attributes.js index efc299d34c28..31ff329f20f1 100644 --- a/src/iframe-attributes.js +++ b/src/iframe-attributes.js @@ -53,6 +53,7 @@ export function getContextMetadata( locationHref = parentWindow.parent.location.href; } + const ampdoc = Services.ampdoc(element); const docInfo = Services.documentInfoForDoc(element); const viewer = Services.viewerForDoc(element); const referrer = viewer.getUnconfirmedReferrerUrl(); @@ -85,7 +86,7 @@ export function getContextMetadata( 'tagName': element.tagName, 'mode': getModeObject(), 'canary': isCanary(parentWindow), - 'hidden': !viewer.isVisible(), + 'hidden': !ampdoc.isVisible(), 'initialLayoutRect': layoutRect ? { 'left': layoutRect.left, diff --git a/src/impression.js b/src/impression.js index cef1abd24a49..81d4913690bf 100644 --- a/src/impression.js +++ b/src/impression.js @@ -186,7 +186,8 @@ export function isTrustedReferrer(referrer) { * @return {!Promise} */ function handleClickUrl(win) { - const viewer = Services.viewerForDoc(win.document.documentElement); + const ampdoc = Services.ampdoc(win.document.documentElement); + const viewer = Services.viewerForDoc(ampdoc); /** @const {?string} */ const clickUrl = viewer.getParam('click'); @@ -211,7 +212,7 @@ function handleClickUrl(win) { } // TODO(@zhouyx) need test with a real response. - return viewer + return ampdoc .whenFirstVisible() .then(() => { return invoke(win, dev().assertString(clickUrl)); diff --git a/src/inabox/inabox-viewer.js b/src/inabox/inabox-viewer.js index 060387592909..e7642d655b83 100644 --- a/src/inabox/inabox-viewer.js +++ b/src/inabox/inabox-viewer.js @@ -89,46 +89,6 @@ class InaboxViewer { return false; } - /** @override */ - getVisibilityState() { - return this.ampdoc_.getVisibilityState(); - } - - /** @override */ - onVisibilityChanged(handler) { - return this.ampdoc_.onVisibilityChanged(handler); - } - - /** @override */ - isVisible() { - return this.ampdoc_.isVisible(); - } - - /** @override */ - hasBeenVisible() { - return this.ampdoc_.getLastVisibleTime() != null; - } - - /** @override */ - whenFirstVisible() { - return this.ampdoc_.whenFirstVisible(); - } - - /** @override */ - whenNextVisible() { - return this.ampdoc_.whenNextVisible(); - } - - /** @override */ - getFirstVisibleTime() { - return this.ampdoc_.getFirstVisibleTime(); - } - - /** @override */ - getLastVisibleTime() { - return this.ampdoc_.getLastVisibleTime(); - } - /** @override */ getPrerenderSize() { return 0; diff --git a/src/service/ampdoc-impl.js b/src/service/ampdoc-impl.js index e9a765bd84c2..cffb25aef410 100644 --- a/src/service/ampdoc-impl.js +++ b/src/service/ampdoc-impl.js @@ -649,6 +649,16 @@ export class AmpDoc { return this.visibilityState_ == VisibilityState.VISIBLE; } + /** + * Whether the AMP document has been ever visible before. Since the visiblity + * state of a document can be flipped back and forth we sometimes want to know + * if a document has ever been visible. + * @return {boolean} + */ + hasBeenVisible() { + return this.getLastVisibleTime() != null; + } + /** * Adds a "visibilitychange" event listener for viewer events. The * callback can check {@link isVisible} and {@link getPrefetchCount} diff --git a/src/service/cid-impl.js b/src/service/cid-impl.js index a87af6677b8e..88d37d8f775d 100644 --- a/src/service/cid-impl.js +++ b/src/service/cid-impl.js @@ -186,7 +186,7 @@ class Cid { ); return consent .then(() => { - return Services.viewerForDoc(this.ampdoc).whenFirstVisible(); + return this.ampdoc.whenFirstVisible(); }) .then(() => { // Check if user has globally opted out of CID, we do this after diff --git a/src/service/performance-impl.js b/src/service/performance-impl.js index 9803ffe653dd..ac03d37ae2b4 100644 --- a/src/service/performance-impl.js +++ b/src/service/performance-impl.js @@ -84,6 +84,9 @@ export class Performance { /** @const @private {!Array} */ this.events_ = []; + /** @private {?./ampdoc-impl.AmpDoc} */ + this.ampdoc_ = null; + /** @private {?./viewer-interface.ViewerInterface} */ this.viewer_ = null; @@ -189,7 +192,7 @@ export class Performance { } this.boundOnVisibilityChange_ = this.onVisibilityChange_.bind(this); - this.onViewerVisibilityChange_ = this.onViewerVisibilityChange_.bind(this); + this.onAmpDocVisibilityChange_ = this.onAmpDocVisibilityChange_.bind(this); // Add RTV version as experiment ID, so we can slice the data by version. this.addEnabledExperiment('rtv-' + getMode(this.win).rtvVersion); @@ -214,6 +217,7 @@ export class Performance { */ coreServicesAvailable() { const {documentElement} = this.win.document; + this.ampdoc_ = Services.ampdoc(documentElement); this.viewer_ = Services.viewerForDoc(documentElement); this.resources_ = Services.resourcesForDoc(documentElement); @@ -221,7 +225,7 @@ export class Performance { this.viewer_.isEmbedded() && this.viewer_.getParam('csi') === '1'; // This is for redundancy. Call flush on any visibility change. - this.viewer_.onVisibilityChanged(this.flush.bind(this)); + this.ampdoc_.onVisibilityChanged(this.flush.bind(this)); // Does not need to wait for messaging ready since it will be queued // if it isn't ready. @@ -231,7 +235,7 @@ export class Performance { // and has no messaging channel. const channelPromise = this.viewer_.whenMessagingReady(); - this.viewer_.whenFirstVisible().then(() => { + this.ampdoc_.whenFirstVisible().then(() => { this.tick('ofv'); this.flush(); }); @@ -245,7 +249,7 @@ export class Performance { {capture: true} ); - this.viewer_.onVisibilityChanged(this.onViewerVisibilityChange_); + this.ampdoc_.onVisibilityChanged(this.onAmpDocVisibilityChange_); } if ( @@ -260,7 +264,7 @@ export class Performance { {capture: true} ); - this.viewer_.onVisibilityChanged(this.onViewerVisibilityChange_); + this.ampdoc_.onVisibilityChanged(this.onAmpDocVisibilityChange_); } // We don't check `isPerformanceTrackingOn` here since there are some @@ -453,6 +457,7 @@ export class Performance { /** * When the visibility state of the document changes to hidden, * send the layout jank score. + * @private */ onVisibilityChange_() { if (this.win.document.visibilityState === 'hidden') { @@ -471,9 +476,10 @@ export class Performance { /** * When the viewer visibility state of the document changes to inactive, * send the layout jank score. + * @private */ - onViewerVisibilityChange_() { - if (this.viewer_.getVisibilityState() === VisibilityState.INACTIVE) { + onAmpDocVisibilityChange_() { + if (this.ampdoc_.getVisibilityState() === VisibilityState.INACTIVE) { if (this.win.PerformanceLayoutJank) { this.tickLayoutJankScore_(); } @@ -581,12 +587,12 @@ export class Performance { * @private */ measureUserPerceivedVisualCompletenessTime_() { - const didStartInPrerender = !this.viewer_.hasBeenVisible(); + const didStartInPrerender = !this.ampdoc_.hasBeenVisible(); let docVisibleTime = didStartInPrerender ? -1 : this.initTime_; - // This will only be relevant if the viewer is in prerender mode. + // This will only be relevant if the ampdoc is in prerender mode. // (hasn't been visible yet, ever at this point) - this.viewer_.whenFirstVisible().then(() => { + this.ampdoc_.whenFirstVisible().then(() => { docVisibleTime = this.win.Date.now(); // Mark this first visible instance in the browser timeline. this.mark('visible'); @@ -599,7 +605,7 @@ export class Performance { ? this.win.Date.now() - docVisibleTime : // Prerender was complete before visibility. 0; - this.viewer_.whenFirstVisible().then(() => { + this.ampdoc_.whenFirstVisible().then(() => { // We only tick this if the page eventually becomes visible, // since otherwise we heavily skew the metric towards the // 0 case, since pre-renders that are never used are highly @@ -721,7 +727,7 @@ export class Performance { */ tickSinceVisible(label) { const now = this.win.Date.now(); - const visibleTime = this.viewer_ ? this.viewer_.getFirstVisibleTime() : 0; + const visibleTime = this.ampdoc_ ? this.ampdoc_.getFirstVisibleTime() : 0; const v = visibleTime ? Math.max(now - visibleTime, 0) : 0; this.tickDelta(label, v); } diff --git a/src/service/resources-impl.js b/src/service/resources-impl.js index e7b2009831cd..e7ffb713f331 100644 --- a/src/service/resources-impl.js +++ b/src/service/resources-impl.js @@ -111,7 +111,7 @@ export class ResourcesImpl { this.buildAttemptsCount_ = 0; /** @private {boolean} */ - this.visible_ = this.viewer_.isVisible(); + this.visible_ = this.ampdoc.isVisible(); /** @private {number} */ this.prerenderSize_ = this.viewer_.getPrerenderSize(); @@ -209,7 +209,7 @@ export class ResourcesImpl { /** @private @const {!FiniteStateMachine} */ this.visibilityStateMachine_ = new FiniteStateMachine( - this.viewer_.getVisibilityState() + this.ampdoc.getVisibilityState() ); // When viewport is resized, we have to re-measure all elements. @@ -228,8 +228,8 @@ export class ResourcesImpl { // When document becomes visible, e.g. from "prerender" mode, do a // simple pass. - this.viewer_.onVisibilityChanged(() => { - if (this.firstVisibleTime_ == -1 && this.viewer_.isVisible()) { + this.ampdoc.onVisibilityChanged(() => { + if (this.firstVisibleTime_ == -1 && this.ampdoc.isVisible()) { this.firstVisibleTime_ = Date.now(); } this.schedulePass(); @@ -388,7 +388,7 @@ export class ResourcesImpl { // Most documents have 10 or less AMP tags. By building 20 we should not // change the behavior for the vast majority of docs, and almost always // catch everything in the first viewport. - return this.buildAttemptsCount_ < 20 || this.viewer_.hasBeenVisible(); + return this.buildAttemptsCount_ < 20 || this.ampdoc.hasBeenVisible(); } /** @@ -412,7 +412,7 @@ export class ResourcesImpl { // prerendered. This avoids wasting our prerender build quota. // See isUnderBuildQuota_() for more details. const shouldBuildResource = - this.viewer_.getVisibilityState() != VisibilityState.PRERENDER || + this.ampdoc.getVisibilityState() != VisibilityState.PRERENDER || resource.prerenderAllowed(); if (buildingEnabled && shouldBuildResource) { @@ -772,7 +772,7 @@ export class ResourcesImpl { return; } - this.visible_ = this.viewer_.isVisible(); + this.visible_ = this.ampdoc.isVisible(); this.prerenderSize_ = this.viewer_.getPrerenderSize(); const firstPassAfterDocumentReady = @@ -820,7 +820,7 @@ export class ResourcesImpl { this.pass_.cancel(); this.vsyncScheduled_ = false; - this.visibilityStateMachine_.setState(this.viewer_.getVisibilityState()); + this.visibilityStateMachine_.setState(this.ampdoc.getVisibilityState()); if ( this.documentReady_ && this.ampInitialized_ && @@ -1782,7 +1782,7 @@ export class ResourcesImpl { // (and they can't prerender). if (!this.visible_) { if ( - this.viewer_.getVisibilityState() != VisibilityState.PRERENDER || + this.ampdoc.getVisibilityState() != VisibilityState.PRERENDER || !resource.prerenderAllowed() ) { return false; diff --git a/src/service/url-replacements-impl.js b/src/service/url-replacements-impl.js index cafef1920bb3..d1ac9b55856e 100644 --- a/src/service/url-replacements-impl.js +++ b/src/service/url-replacements-impl.js @@ -659,7 +659,7 @@ export class GlobalVariableSource extends VariableSource { this.set('AMP_VERSION', () => internalRuntimeVersion()); this.set('BACKGROUND_STATE', () => { - return Services.viewerForDoc(this.ampdoc).isVisible() ? '0' : '1'; + return this.ampdoc.isVisible() ? '0' : '1'; }); this.setAsync('VIDEO_STATE', (id, property) => { diff --git a/src/service/video-manager-impl.js b/src/service/video-manager-impl.js index 3ad2a936498b..193d5d449ef0 100644 --- a/src/service/video-manager-impl.js +++ b/src/service/video-manager-impl.js @@ -719,7 +719,7 @@ class VideoEntry { * @private */ loadedVideoVisibilityChanged_() { - if (!Services.viewerForDoc(this.ampdoc_).isVisible()) { + if (!this.ampdoc_.isVisible()) { return; } this.supportsAutoplay_().then(supportsAutoplay => { diff --git a/src/service/viewer-impl.js b/src/service/viewer-impl.js index d87fb5c2bb98..39cad5ff71cd 100644 --- a/src/service/viewer-impl.js +++ b/src/service/viewer-impl.js @@ -257,7 +257,7 @@ export class ViewerImpl { // This fragment may get cleared by impression tracking. If so, it will be // restored afterward. - this.whenFirstVisible().then(() => { + this.ampdoc.whenFirstVisible().then(() => { this.maybeUpdateFragmentForCct(); }); } @@ -421,11 +421,6 @@ export class ViewerImpl { return this.overtakeHistory_; } - /** @override */ - getVisibilityState() { - return this.ampdoc.getVisibilityState(); - } - /** * Sets the viewer defined visibility state. * @param {?string|undefined} state @@ -449,37 +444,11 @@ export class ViewerImpl { } this.ampdoc.overrideVisibilityState(state); - dev().fine(TAG_, 'visibilitychange event:', this.getVisibilityState()); - } - - /** @override */ - isVisible() { - return this.ampdoc.isVisible(); - } - - /** @override */ - hasBeenVisible() { - return this.ampdoc.getLastVisibleTime() != null; - } - - /** @override */ - whenFirstVisible() { - return this.ampdoc.whenFirstVisible(); - } - - /** @override */ - whenNextVisible() { - return this.ampdoc.whenNextVisible(); - } - - /** @override */ - getFirstVisibleTime() { - return this.ampdoc.getFirstVisibleTime(); - } - - /** @override */ - getLastVisibleTime() { - return this.ampdoc.getLastVisibleTime(); + dev().fine( + TAG_, + 'visibilitychange event:', + this.ampdoc.getVisibilityState() + ); } /** @override */ @@ -602,11 +571,6 @@ export class ViewerImpl { return urls.trustedViewerHosts.some(th => th.test(url.hostname)); } - /** @override */ - onVisibilityChanged(handler) { - return this.ampdoc.onVisibilityChanged(handler); - } - /** @override */ onMessage(eventType, handler) { let observable = this.messageObservables_[eventType]; diff --git a/src/service/viewer-interface.js b/src/service/viewer-interface.js index f482ab7ae4e6..299c605db525 100644 --- a/src/service/viewer-interface.js +++ b/src/service/viewer-interface.js @@ -101,65 +101,6 @@ export class ViewerInterface { */ isOvertakeHistory() {} - /** - * Returns visibility state configured by the viewer. - * See {@link isVisible}. - * @return {!../visibility-state.VisibilityState} - * TODO(#22733): deprecate/remove when ampdoc-fie is launched. - */ - getVisibilityState() {} - - /** - * Whether the AMP document currently visible. The reasons why it might not - * be visible include user switching to another tab, browser running the - * document in the prerender mode or viewer running the document in the - * prerender mode. - * @return {boolean} - * TODO(#22733): deprecate/remove when ampdoc-fie is launched. - */ - isVisible() {} - - /** - * Whether the AMP document has been ever visible before. Since the visiblity - * state of a document can be flipped back and forth we sometimes want to know - * if a document has ever been visible. - * @return {boolean} - * TODO(#22733): deprecate/remove when ampdoc-fie is launched. - */ - hasBeenVisible() {} - - /** - * Returns a Promise that only ever resolved when the current - * AMP document first becomes visible. - * @return {!Promise} - * TODO(#22733): deprecate/remove when ampdoc-fie is launched. - */ - whenFirstVisible() {} - - /** - * Returns a Promise that resolve when current doc becomes visible. - * The promise resolves immediately if doc is already visible. - * @return {!Promise} - * TODO(#22733): deprecate/remove when ampdoc-fie is launched. - */ - whenNextVisible() {} - - /** - * Returns the time when the document has become visible for the first time. - * If document has not yet become visible, the returned value is `null`. - * @return {?time} - * TODO(#22733): deprecate/remove when ampdoc-fie is launched. - */ - getFirstVisibleTime() {} - - /** - * Returns the time when the document has become visible for the last time. - * If document has not yet become visible, the returned value is `null`. - * @return {?time} - * TODO(#22733): deprecate/remove when ampdoc-fie is launched. - */ - getLastVisibleTime() {} - /** * How much the viewer has requested the runtime to prerender the document. * The values are in number of screens. @@ -212,16 +153,6 @@ export class ViewerInterface { */ getViewerOrigin() {} - /** - * Adds a "visibilitychange" event listener for viewer events. The - * callback can check {@link isVisible} and {@link getPrefetchCount} - * methods for more info. - * @param {function()} handler - * @return {!UnlistenDef} - * TODO(#22733): deprecate/remove when ampdoc-fie is launched. - */ - onVisibilityChanged(handler) {} - /** * Adds a eventType listener for viewer events. * @param {string} eventType diff --git a/src/service/viewport/viewport-impl.js b/src/service/viewport/viewport-impl.js index 4f125ad0692d..4bc8e1685763 100644 --- a/src/service/viewport/viewport-impl.js +++ b/src/service/viewport/viewport-impl.js @@ -161,7 +161,7 @@ export class ViewportImpl { /** @private {boolean} */ this.visible_ = false; - this.viewer_.onVisibilityChanged(this.updateVisibility_.bind(this)); + this.ampdoc.onVisibilityChanged(this.updateVisibility_.bind(this)); this.updateVisibility_(); // Top-level mode classes. @@ -215,7 +215,7 @@ export class ViewportImpl { /** @private */ updateVisibility_() { - const visible = this.viewer_.isVisible(); + const visible = this.ampdoc.isVisible(); if (visible != this.visible_) { this.visible_ = visible; if (visible) { @@ -273,7 +273,7 @@ export class ViewportImpl { this.size_ = this.binding_.getSize(); if (this.size_.width == 0 || this.size_.height == 0) { // Only report when the visibility is "visible" or "prerender". - const visibilityState = this.viewer_.getVisibilityState(); + const visibilityState = this.ampdoc.getVisibilityState(); if ( visibilityState == VisibilityState.PRERENDER || visibilityState == VisibilityState.VISIBLE diff --git a/src/service/vsync-impl.js b/src/service/vsync-impl.js index 76a518a4cea6..1f998e5a32d4 100644 --- a/src/service/vsync-impl.js +++ b/src/service/vsync-impl.js @@ -132,21 +132,15 @@ export class Vsync { FRAME_TIME * 2.5 ); - /** @private {?./viewer-interface.ViewerInterface} */ - this.singleDocViewer_ = null; - // When the document changes visibility, vsync has to reschedule the queue // processing. const boundOnVisibilityChanged = this.onVisibilityChanged_.bind(this); if (this.ampdocService_.isSingleDoc()) { // In a single-doc mode, the visibility of the doc == global visibility. // Thus, it's more efficient to only listen to it once. - Services.viewerPromiseForDoc(this.ampdocService_.getSingleDoc()).then( - viewer => { - this.singleDocViewer_ = viewer; - viewer.onVisibilityChanged(boundOnVisibilityChanged); - } - ); + this.ampdocService_ + .getSingleDoc() + .onVisibilityChanged(boundOnVisibilityChanged); } else { // In multi-doc mode, we track separately the global visibility and // per-doc visibility when necessary. @@ -280,14 +274,14 @@ export class Vsync { } // Single doc: animations allowed when single doc is visible. - if (this.singleDocViewer_) { - return this.singleDocViewer_.isVisible(); + if (this.ampdocService_.isSingleDoc()) { + return this.ampdocService_.getSingleDoc().isVisible(); } // Multi-doc: animations depend on the state of the relevant doc. if (opt_contextNode) { const ampdoc = this.ampdocService_.getAmpDocIfAvailable(opt_contextNode); - return !ampdoc || Services.viewerForDoc(ampdoc).isVisible(); + return !ampdoc || ampdoc.isVisible(); } return true; diff --git a/src/utils/xhr-utils.js b/src/utils/xhr-utils.js index 86c935ca57c6..a7c0b77a54f0 100644 --- a/src/utils/xhr-utils.js +++ b/src/utils/xhr-utils.js @@ -200,10 +200,10 @@ export function getViewerInterceptResponse(win, ampdocSingle, input, init) { return Promise.resolve(); } - const viewer = Services.viewerForDoc(ampdocSingle); const whenUnblocked = init.prerenderSafe ? Promise.resolve() - : viewer.whenFirstVisible(); + : ampdocSingle.whenFirstVisible(); + const viewer = Services.viewerForDoc(ampdocSingle); const urlIsProxy = isProxyOrigin(input); const viewerCanIntercept = viewer.hasCapability('xhrInterceptor'); const interceptorDisabledForLocalDev = diff --git a/test/integration/test-amp-pixel.js b/test/integration/test-amp-pixel.js index 3e34ee31cd7e..f86a8fc00f72 100644 --- a/test/integration/test-amp-pixel.js +++ b/test/integration/test-amp-pixel.js @@ -16,7 +16,6 @@ import {AmpPixel} from '../../builtins/amp-pixel'; import {BrowserController, RequestBank} from '../../testing/test-helper'; -import {Services} from '../../src/services'; import {createElementWithAttributes} from '../../src/dom'; describe.configure().run('amp-pixel', function() { @@ -121,10 +120,7 @@ describes.fakeWin('amp-pixel with img (inabox)', {amp: true}, env => { createElementWithAttributes(env.win.document, 'img', {src}) ); env.win.document.body.appendChild(pixelElem); - const viewer = Services.viewerForDoc(env.win.document); - env.sandbox.stub(viewer, 'whenFirstVisible').callsFake(() => { - return Promise.resolve(); - }); + env.sandbox.stub(env.ampdoc, 'whenFirstVisible').returns(Promise.resolve()); const pixel = new AmpPixel(pixelElem); pixel.buildCallback(); expect(pixelElem.querySelectorAll('img').length).to.equal(1); diff --git a/test/integration/test-video-manager.js b/test/integration/test-video-manager.js index a20a93deea01..796741f2562e 100644 --- a/test/integration/test-video-manager.js +++ b/test/integration/test-video-manager.js @@ -108,10 +108,7 @@ describe video.setAttribute('autoplay', ''); videoManager.register(impl); - const visibilityStub = sandbox.stub( - Services.viewerForDoc(env.ampdoc), - 'isVisible' - ); + const visibilityStub = sandbox.stub(env.ampdoc, 'isVisible'); visibilityStub.onFirstCall().returns(true); const entry = videoManager.getEntryForVideo_(impl); @@ -133,10 +130,7 @@ describe video.setAttribute('autoplay', ''); videoManager.register(impl); - const visibilityStub = sandbox.stub( - Services.viewerForDoc(env.ampdoc), - 'isVisible' - ); + const visibilityStub = sandbox.stub(env.ampdoc, 'isVisible'); visibilityStub.onFirstCall().returns(true); const entry = videoManager.getEntryForVideo_(impl); @@ -220,10 +214,7 @@ describe videoManager.register(impl); - const visibilityStub = sandbox.stub( - Services.viewerForDoc(env.ampdoc), - 'isVisible' - ); + const visibilityStub = sandbox.stub(env.ampdoc, 'isVisible'); visibilityStub.onFirstCall().returns(true); const entry = videoManager.getEntryForVideo_(impl); diff --git a/test/unit/test-activity.js b/test/unit/test-activity.js index 86602b9b5263..f6276a872654 100644 --- a/test/unit/test-activity.js +++ b/test/unit/test-activity.js @@ -32,7 +32,6 @@ describe('Activity getTotalEngagedTime', () => { let fakeDoc; let fakeWin; let ampdoc; - let viewer; let viewport; let activity; let whenFirstVisibleResolve; @@ -108,14 +107,13 @@ describe('Activity getTotalEngagedTime', () => { installVsyncService(fakeWin); installPlatformService(fakeWin); installViewerServiceForDoc(ampdoc); - viewer = Services.viewerForDoc(ampdoc); const whenFirstVisiblePromise = new Promise(resolve => { whenFirstVisibleResolve = resolve; }); - sandbox.stub(viewer, 'whenFirstVisible').returns(whenFirstVisiblePromise); - sandbox.stub(viewer, 'onVisibilityChanged').callsFake(handler => { - visibilityObservable.add(handler); + sandbox.stub(ampdoc, 'whenFirstVisible').returns(whenFirstVisiblePromise); + sandbox.stub(ampdoc, 'onVisibilityChanged').callsFake(handler => { + return visibilityObservable.add(handler); }); installViewportServiceForDoc(ampdoc); @@ -137,17 +135,13 @@ describe('Activity getTotalEngagedTime', () => { sandbox.restore(); }); - it('should use the stubbed viewer in tests', () => { - return expect(activity.viewer_).to.equal(viewer); - }); - it('should have 0 engaged time if there is no activity', () => { return expect(activity.getTotalEngagedTime()).to.equal(0); }); - it('should have 5 seconds of engaged time after viewer becomes visible', () => { + it('should have 5 seconds of engaged time after doc becomes visible', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(10000); return expect(activity.getTotalEngagedTime()).to.equal(5); }); @@ -155,7 +149,7 @@ describe('Activity getTotalEngagedTime', () => { it('should have 4 seconds of engaged time 4 seconds after visible', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(4000); return expect(activity.getTotalEngagedTime()).to.equal(4); }); @@ -163,7 +157,7 @@ describe('Activity getTotalEngagedTime', () => { it('should have 10 seconds of engaged time', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(6000); mousedownObservable.fire(); clock.tick(20000); @@ -173,7 +167,7 @@ describe('Activity getTotalEngagedTime', () => { it('should have the same engaged time in separate requests', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(3456); mousedownObservable.fire(); clock.tick(10232); @@ -184,9 +178,9 @@ describe('Activity getTotalEngagedTime', () => { }); it('should not accumulate engaged time after inactivity', () => { - const isVisibleStub = sandbox.stub(viewer, 'isVisible').returns(true); + const isVisibleStub = sandbox.stub(ampdoc, 'isVisible').returns(true); whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(3000); mousedownObservable.fire(); clock.tick(1000); @@ -199,7 +193,7 @@ describe('Activity getTotalEngagedTime', () => { it('should accumulate engaged time over multiple activities', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(10000); mousedownObservable.fire(); clock.tick(10000); @@ -237,7 +231,7 @@ describe('Activity getTotalEngagedTime', () => { activity.boundHandleActivity_ ); whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { expect(addEventListenerSpy.getCall(0).args[0]).to.equal('mousedown'); expect(addEventListenerSpy.getCall(1).args[0]).to.equal('mouseup'); expect(addEventListenerSpy.getCall(2).args[0]).to.equal('mousemove'); @@ -254,7 +248,6 @@ describe('Activity getIncrementalEngagedTime', () => { let fakeDoc; let fakeWin; let ampdoc; - let viewer; let viewport; let activity; let whenFirstVisibleResolve; @@ -330,14 +323,13 @@ describe('Activity getIncrementalEngagedTime', () => { installVsyncService(fakeWin); installPlatformService(fakeWin); installViewerServiceForDoc(ampdoc); - viewer = Services.viewerForDoc(ampdoc); const whenFirstVisiblePromise = new Promise(resolve => { whenFirstVisibleResolve = resolve; }); - sandbox.stub(viewer, 'whenFirstVisible').returns(whenFirstVisiblePromise); - sandbox.stub(viewer, 'onVisibilityChanged').callsFake(handler => { - visibilityObservable.add(handler); + sandbox.stub(ampdoc, 'whenFirstVisible').returns(whenFirstVisiblePromise); + sandbox.stub(ampdoc, 'onVisibilityChanged').callsFake(handler => { + return visibilityObservable.add(handler); }); installViewportServiceForDoc(ampdoc); @@ -364,11 +356,11 @@ describe('Activity getIncrementalEngagedTime', () => { }); it( - 'should have 5 seconds of incremental engaged time after viewer ' + + 'should have 5 seconds of incremental engaged time after doc ' + 'becomes visible', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(10000); return expect(activity.getIncrementalEngagedTime('tests')).to.equal(5); }); @@ -377,7 +369,7 @@ describe('Activity getIncrementalEngagedTime', () => { it('should have 4 seconds of incremental engaged time after 4 seconds', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(4000); return expect(activity.getIncrementalEngagedTime('tests')).to.equal(4); }); @@ -385,7 +377,7 @@ describe('Activity getIncrementalEngagedTime', () => { it('should reset incremental engaged time after each poll', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(10000); mousedownObservable.fire(); const first = activity.getIncrementalEngagedTime('tests'); @@ -401,7 +393,7 @@ describe('Activity getIncrementalEngagedTime', () => { it('should not reset incremental engaged time if reset is false', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { // don't reset mousedownObservable.fire(); clock.tick(10000); @@ -432,7 +424,7 @@ describe('Activity getIncrementalEngagedTime', () => { it('should keep individual incremental engaged times per name', () => { whenFirstVisibleResolve(); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(10000); mousedownObservable.fire(); const alpha = activity.getIncrementalEngagedTime('alpha'); diff --git a/test/unit/test-amp-pixel.js b/test/unit/test-amp-pixel.js index 35939986f821..03c9a233e1d9 100644 --- a/test/unit/test-amp-pixel.js +++ b/test/unit/test-amp-pixel.js @@ -25,12 +25,11 @@ describes.realWin('amp-pixel', {amp: true}, env => { beforeEach(() => { win = env.win; - const viewer = win.__AMP_SERVICES.viewer.obj; whenFirstVisiblePromise = new Promise(resolve => { whenFirstVisibleResolver = resolve; }); sandbox - .stub(viewer, 'whenFirstVisible') + .stub(env.ampdoc, 'whenFirstVisible') .callsFake(() => whenFirstVisiblePromise); createPixel('https://pubads.g.doubleclick.net/activity;dc_iu=1/abc;ord=1?'); }); @@ -164,21 +163,19 @@ describes.realWin( } } - let win, parentWin; + let win; let whenFirstVisiblePromise, whenFirstVisibleResolver; let pixel; let implementation; beforeEach(() => { win = env.win; - parentWin = env.parentWin; - const viewer = parentWin.__AMP_SERVICES.viewer.obj; whenFirstVisiblePromise = new Promise(resolve => { whenFirstVisibleResolver = resolve; }); sandbox - .stub(viewer, 'whenFirstVisible') + .stub(env.ampdoc, 'whenFirstVisible') .callsFake(() => whenFirstVisiblePromise); installUrlReplacementsForEmbed(env.ampdoc, win, new TestVariableSource()); diff --git a/test/unit/test-cid.js b/test/unit/test-cid.js index 2c194a837724..22041527427c 100644 --- a/test/unit/test-cid.js +++ b/test/unit/test-cid.js @@ -122,7 +122,7 @@ describes.sandboxed('cid', {}, () => { installViewerServiceForDoc(ampdoc); storageGetStub = stubServiceForDoc(sandbox, ampdoc, 'storage', 'get'); viewer = Services.viewerForDoc(ampdoc); - sandbox.stub(viewer, 'whenFirstVisible').callsFake(function() { + sandbox.stub(ampdoc, 'whenFirstVisible').callsFake(function() { return whenFirstVisible; }); sandbox diff --git a/test/unit/test-impression.js b/test/unit/test-impression.js index 5203b8d86283..0946019b0625 100644 --- a/test/unit/test-impression.js +++ b/test/unit/test-impression.js @@ -29,6 +29,7 @@ import {user} from '../../src/log'; describe('impression', () => { let sandbox; + let ampdoc; let viewer; let xhr; let isTrustedViewer; @@ -37,6 +38,7 @@ describe('impression', () => { beforeEach(() => { sandbox = sinon.sandbox; + ampdoc = Services.ampdoc(window.document); viewer = Services.viewerForDoc(window.document); sandbox.stub(viewer, 'getParam'); sandbox.stub(viewer, 'hasCapability'); @@ -51,7 +53,7 @@ describe('impression', () => { }, }) ); - sandbox.stub(viewer, 'whenFirstVisible').returns(Promise.resolve()); + sandbox.stub(ampdoc, 'whenFirstVisible').returns(Promise.resolve()); isTrustedViewer = false; sandbox.stub(viewer, 'isTrustedViewer').callsFake(() => { return Promise.resolve(isTrustedViewer); diff --git a/test/unit/test-performance.js b/test/unit/test-performance.js index 561f9f9de06b..364f1e9da6d7 100644 --- a/test/unit/test-performance.js +++ b/test/unit/test-performance.js @@ -284,7 +284,7 @@ describes.realWin('performance', {amp: true}, env => { return Promise.all([ perf.coreServicesAvailable(), - viewer.whenFirstVisible(), + ampdoc.whenFirstVisible(), ]).then(() => { expect(flushSpy).to.have.callCount(4); expect(perf.isMessagingReady_).to.be.false; @@ -302,7 +302,7 @@ describes.realWin('performance', {amp: true}, env => { tickDeltaStub = sandbox.stub(perf, 'tickDelta'); firstVisibleTime = null; sandbox - .stub(viewer, 'getFirstVisibleTime') + .stub(ampdoc, 'getFirstVisibleTime') .callsFake(() => firstVisibleTime); }); @@ -482,7 +482,7 @@ describes.realWin('performance', {amp: true}, env => { it('should call the flush callback', () => { // Make sure "first visible" arrives after "channel ready". const firstVisiblePromise = new Promise(() => {}); - sandbox.stub(viewer, 'whenFirstVisible').returns(firstVisiblePromise); + sandbox.stub(ampdoc, 'whenFirstVisible').returns(firstVisiblePromise); expect(viewerSendMessageStub.withArgs('sendCsi')).to.have.callCount( 0 ); @@ -553,7 +553,7 @@ describes.realWin('performance', {amp: true}, env => { let whenViewportLayoutCompleteResolve; function stubHasBeenVisible(visibility) { - sandbox.stub(viewer, 'hasBeenVisible').returns(visibility); + sandbox.stub(ampdoc, 'hasBeenVisible').returns(visibility); } function getPerformanceMarks() { @@ -575,7 +575,7 @@ describes.realWin('performance', {amp: true}, env => { whenViewportLayoutCompleteResolve = resolve; }); - sandbox.stub(viewer, 'whenFirstVisible').returns(whenFirstVisiblePromise); + sandbox.stub(ampdoc, 'whenFirstVisible').returns(whenFirstVisiblePromise); sandbox .stub(perf, 'whenViewportLayoutComplete_') .returns(whenViewportLayoutCompletePromise); @@ -597,7 +597,7 @@ describes.realWin('performance', {amp: true}, env => { .withArgs('csi') .returns('1'); sandbox.stub(viewer, 'isEmbedded').returns(true); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(400); whenViewportLayoutCompleteResolve(); return perf.whenViewportLayoutComplete_().then(() => { @@ -624,7 +624,7 @@ describes.realWin('performance', {amp: true}, env => { .stub(viewer, 'getParam') .withArgs('csi') .returns(null); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(400); whenViewportLayoutCompleteResolve(); return perf.whenViewportLayoutComplete_().then(() => { @@ -643,7 +643,7 @@ describes.realWin('performance', {amp: true}, env => { clock.tick(100); whenFirstVisibleResolve(); expect(tickSpy).to.have.callCount(3); - return viewer.whenFirstVisible().then(() => { + return ampdoc.whenFirstVisible().then(() => { clock.tick(400); expect(tickSpy).to.have.callCount(4); whenViewportLayoutCompleteResolve(); @@ -1109,14 +1109,16 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => { const unresolvedPromise = new Promise(() => {}); const viewportSize = {width: 0, height: 0}; - sandbox.stub(Services, 'viewerForDoc').returns({ - isEmbedded: () => {}, + sandbox.stub(Services, 'ampdoc').returns({ hasBeenVisible: () => {}, onVisibilityChanged: () => {}, whenFirstVisible: () => unresolvedPromise, - whenMessagingReady: () => {}, getVisibilityState: () => viewerVisibilityState, }); + sandbox.stub(Services, 'viewerForDoc').returns({ + isEmbedded: () => {}, + whenMessagingReady: () => {}, + }); sandbox.stub(Services, 'resourcesForDoc').returns({ getResourcesInRect: () => unresolvedPromise, whenFirstPass: () => Promise.resolve(), @@ -1214,7 +1216,7 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => { const perf = getPerformance(); perf.coreServicesAvailable(); viewerVisibilityState = VisibilityState.INACTIVE; - perf.onViewerVisibilityChange_(); + perf.onAmpDocVisibilityChange_(); expect(perf.events_.length).to.equal(1); expect(perf.events_[0]).to.be.jsonEqual({ @@ -1274,14 +1276,16 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => { const unresolvedPromise = new Promise(() => {}); const viewportSize = {width: 0, height: 0}; - sandbox.stub(Services, 'viewerForDoc').returns({ - isEmbedded: () => {}, + sandbox.stub(Services, 'ampdoc').returns({ hasBeenVisible: () => {}, onVisibilityChanged: () => {}, whenFirstVisible: () => unresolvedPromise, - whenMessagingReady: () => {}, getVisibilityState: () => viewerVisibilityState, }); + sandbox.stub(Services, 'viewerForDoc').returns({ + isEmbedded: () => {}, + whenMessagingReady: () => {}, + }); sandbox.stub(Services, 'resourcesForDoc').returns({ getResourcesInRect: () => unresolvedPromise, whenFirstPass: () => Promise.resolve(), @@ -1466,7 +1470,7 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => { }); viewerVisibilityState = VisibilityState.INACTIVE; - perf.onViewerVisibilityChange_(); + perf.onAmpDocVisibilityChange_(); expect(perf.events_.length).to.equal(1); expect(perf.events_[0]).to.be.jsonEqual({ diff --git a/test/unit/test-resources.js b/test/unit/test-resources.js index aabe6320f87d..d6f0b5d3e93d 100644 --- a/test/unit/test-resources.js +++ b/test/unit/test-resources.js @@ -282,7 +282,7 @@ describe('Resources', () => { }; resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.PRERENDER); resources.scheduleLayoutOrPreload(resource, true); expect(resources.queue_.getSize()).to.equal(0); @@ -305,7 +305,7 @@ describe('Resources', () => { }; resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.PRERENDER); resources.scheduleLayoutOrPreload(resource, true); expect(resources.queue_.getSize()).to.equal(1); @@ -328,7 +328,7 @@ describe('Resources', () => { }; resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.HIDDEN); resources.scheduleLayoutOrPreload(resource, true); expect(resources.queue_.getSize()).to.equal(0); @@ -706,7 +706,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { it('should measure unbuilt elements', () => { resources.visible_ = true; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.VISIBLE); viewportMock.expects('getRect').returns(layoutRectLtwh(0, 0, 300, 400)); resource1.isBuilt = () => false; @@ -723,7 +723,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { it('should render two screens when visible', () => { resources.visible_ = true; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.VISIBLE); viewportMock.expects('getRect').returns(layoutRectLtwh(0, 0, 300, 400)); @@ -739,7 +739,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { resource2.state_ = ResourceState.LAYOUT_COMPLETE; resources.visible_ = true; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.VISIBLE); viewportMock.expects('getRect').returns(layoutRectLtwh(0, 0, 300, 400)); @@ -759,7 +759,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { layoutRectLtwh(10, 1010, 100, 101); resources.visible_ = true; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.VISIBLE); resources.relayoutAll_ = false; resources.relayoutTop_ = 1000; @@ -777,7 +777,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { it('should prerender only one screen with prerenderSize = 1', () => { resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.PRERENDER); resources.prerenderSize_ = 1; viewportMock.expects('getRect').returns(layoutRectLtwh(0, 0, 300, 1009)); @@ -791,7 +791,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { it('should NOT prerender anything with prerenderSize = 0', () => { resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.PRERENDER); resources.prerenderSize_ = 0; viewportMock.expects('getRect').returns(layoutRectLtwh(0, 0, 300, 400)); @@ -807,7 +807,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { resource2.state_ = ResourceState.LAYOUT_COMPLETE; resources.visible_ = true; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.VISIBLE); viewportMock.expects('getRect').returns(layoutRectLtwh(0, 0, 300, 400)); @@ -862,7 +862,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { resource1.unlayoutCallback = () => true; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.VISIBLE); viewportMock .expects('getRect') @@ -962,7 +962,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .callsFake(() => 'prerender'); sandbox.stub(resource1, 'isInViewport').callsFake(() => true); sandbox.stub(resource1, 'prerenderAllowed').callsFake(() => true); @@ -983,7 +983,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .callsFake(() => 'prerender'); sandbox.stub(resource1, 'isInViewport').callsFake(() => true); sandbox.stub(resource1, 'prerenderAllowed').callsFake(() => false); @@ -1004,7 +1004,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .callsFake(() => 'hidden'); sandbox.stub(resource1, 'isInViewport').callsFake(() => true); sandbox.stub(resource1, 'prerenderAllowed').callsFake(() => true); @@ -1023,7 +1023,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { it.skip('should update inViewport before scheduling layouts', () => { resources.visible_ = true; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.VISIBLE); viewportMock.expects('getRect').returns(layoutRectLtwh(0, 0, 300, 400)); const setInViewport = sandbox.spy(resource1, 'setInViewport'); @@ -1085,7 +1085,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { it('should NOT build non-prerenderable resources in prerender', () => { sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.PRERENDER); sandbox.stub(resources, 'schedule_'); resources.documentReady_ = true; @@ -1102,7 +1102,7 @@ describes.realWin('Resources discoverWork', {amp: true}, env => { }); it('should NOT build when quota reached', () => { - sandbox.stub(resources.viewer_, 'hasBeenVisible').callsFake(() => false); + sandbox.stub(resources.ampdoc, 'hasBeenVisible').callsFake(() => false); sandbox.stub(resources, 'schedule_'); resources.documentReady_ = true; resources.buildAttemptsCount_ = 21; // quota is 20 @@ -1745,7 +1745,7 @@ describe('Resources changeSize', () => { .run('should change size when document is invisible', () => { resources.visible_ = false; sandbox - .stub(resources.viewer_, 'getVisibilityState') + .stub(resources.ampdoc, 'getVisibilityState') .returns(VisibilityState.PRERENDER); resources.scheduleChangeSize_( resource1, diff --git a/test/unit/test-runtime.js b/test/unit/test-runtime.js index 14c1c727dd16..26128aff23e6 100644 --- a/test/unit/test-runtime.js +++ b/test/unit/test-runtime.js @@ -1342,37 +1342,34 @@ describes.realWin( it('should start as visible by default', () => { win.AMP.attachShadowDoc(hostElement, importDoc, docUrl); - const viewer = getServiceForDoc(ampdoc, 'viewer'); - expect(viewer.getVisibilityState()).to.equal('visible'); + expect(ampdoc.getVisibilityState()).to.equal('visible'); }); it('should start as prerender when requested', () => { win.AMP.attachShadowDoc(hostElement, importDoc, docUrl, { 'visibilityState': 'prerender', }); - const viewer = getServiceForDoc(ampdoc, 'viewer'); - expect(viewer.getVisibilityState()).to.equal('prerender'); + expect(ampdoc.getVisibilityState()).to.equal('prerender'); }); it('should expose visibility method', () => { const amp = win.AMP.attachShadowDoc(hostElement, importDoc, docUrl); - const viewer = getServiceForDoc(ampdoc, 'viewer'); expect(amp.setVisibilityState).to.be.a('function'); - expect(viewer.getVisibilityState()).to.equal('visible'); + expect(ampdoc.getVisibilityState()).to.equal('visible'); amp.setVisibilityState('inactive'); - expect(viewer.getVisibilityState()).to.equal('inactive'); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); }); it('should expose close method and dispose services', () => { const amp = win.AMP.attachShadowDoc(hostElement, importDoc, docUrl); const viewer = getServiceForDoc(ampdoc, 'viewer'); expect(amp.close).to.be.a('function'); - expect(viewer.getVisibilityState()).to.equal('visible'); + expect(ampdoc.getVisibilityState()).to.equal('visible'); viewer.dispose = sandbox.spy(); amp.close(); - expect(viewer.getVisibilityState()).to.equal('inactive'); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); expect(viewer.dispose).to.be.calledOnce; }); @@ -1734,8 +1731,7 @@ describes.realWin( writer = shadowDoc.writer; writer.write(''); return ampdoc.waitForBodyOpen().then(() => { - const viewer = getServiceForDoc(ampdoc, 'viewer'); - expect(viewer.getVisibilityState()).to.equal('visible'); + expect(ampdoc.getVisibilityState()).to.equal('visible'); }); }); @@ -1746,8 +1742,7 @@ describes.realWin( writer = shadowDoc.writer; writer.write(''); return ampdoc.waitForBodyOpen().then(() => { - const viewer = getServiceForDoc(ampdoc, 'viewer'); - expect(viewer.getVisibilityState()).to.equal('prerender'); + expect(ampdoc.getVisibilityState()).to.equal('prerender'); }); }); @@ -1756,12 +1751,11 @@ describes.realWin( writer = shadowDoc.writer; writer.write(''); return ampdoc.waitForBodyOpen().then(() => { - const viewer = getServiceForDoc(ampdoc, 'viewer'); expect(shadowDoc.setVisibilityState).to.be.a('function'); - expect(viewer.getVisibilityState()).to.equal('visible'); + expect(ampdoc.getVisibilityState()).to.equal('visible'); shadowDoc.setVisibilityState('inactive'); - expect(viewer.getVisibilityState()).to.equal('inactive'); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); }); }); @@ -1772,11 +1766,11 @@ describes.realWin( return ampdoc.waitForBodyOpen().then(() => { const viewer = getServiceForDoc(ampdoc, 'viewer'); expect(shadowDoc.close).to.be.a('function'); - expect(viewer.getVisibilityState()).to.equal('visible'); + expect(ampdoc.getVisibilityState()).to.equal('visible'); viewer.dispose = sandbox.spy(); shadowDoc.close(); - expect(viewer.getVisibilityState()).to.equal('inactive'); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); expect(viewer.dispose).to.be.calledOnce; }); }); diff --git a/test/unit/test-url-replacements.js b/test/unit/test-url-replacements.js index 1a6d072e1e98..711091fc649d 100644 --- a/test/unit/test-url-replacements.js +++ b/test/unit/test-url-replacements.js @@ -922,9 +922,8 @@ describes.sandboxed('UrlReplacements', {}, () => { it('Should replace BACKGROUND_STATE with 0', () => { const win = getFakeWindow(); - win.__AMP_SERVICES.viewer = { - obj: {isVisible: () => true}, - }; + const {ampdoc} = win; + sandbox.stub(ampdoc, 'isVisible').returns(true); return Services.urlReplacementsForDoc(win.document.documentElement) .expandUrlAsync('?sh=BACKGROUND_STATE') .then(res => { @@ -934,9 +933,8 @@ describes.sandboxed('UrlReplacements', {}, () => { it('Should replace BACKGROUND_STATE with 1', () => { const win = getFakeWindow(); - win.__AMP_SERVICES.viewer = { - obj: {isVisible: () => false}, - }; + const {ampdoc} = win; + sandbox.stub(ampdoc, 'isVisible').returns(false); return Services.urlReplacementsForDoc(win.document.documentElement) .expandUrlAsync('?sh=BACKGROUND_STATE') .then(res => { diff --git a/test/unit/test-viewer.js b/test/unit/test-viewer.js index d7cf0e2a3e97..bf69b1455613 100644 --- a/test/unit/test-viewer.js +++ b/test/unit/test-viewer.js @@ -174,7 +174,7 @@ describes.sandboxed('Viewer', {}, () => { // windowApi.location.hash = ''; const viewer = new ViewerImpl(ampdoc); expect(viewer.isCctEmbedded()).to.be.true; - yield viewer.whenFirstVisible(); + yield ampdoc.whenFirstVisible(); expect(windowApi.history.replaceState).to.be.calledWith( {}, '', @@ -188,7 +188,7 @@ describes.sandboxed('Viewer', {}, () => { const viewer = new ViewerImpl(ampdoc); expect(viewer.getParam('test')).to.equal('1'); expect(viewer.isCctEmbedded()).to.be.true; - yield viewer.whenFirstVisible(); + yield ampdoc.whenFirstVisible(); expect(windowApi.history.replaceState).to.be.calledWith( {}, '', @@ -206,7 +206,7 @@ describes.sandboxed('Viewer', {}, () => { const viewer = new ViewerImpl(ampdoc); expect(viewer.getParam('test')).to.equal('1'); expect(viewer.isCctEmbedded()).to.be.true; - yield viewer.whenFirstVisible(); + yield ampdoc.whenFirstVisible(); expect(windowApi.history.replaceState).to.be.calledWith( {}, '', @@ -223,7 +223,7 @@ describes.sandboxed('Viewer', {}, () => { const viewer = new ViewerImpl(ampdoc); expect(viewer.getParam('test')).to.equal('1'); expect(viewer.isCctEmbedded()).to.be.true; - yield viewer.whenFirstVisible(); + yield ampdoc.whenFirstVisible(); expect(windowApi.history.replaceState).to.be.calledWith( {}, '', @@ -246,7 +246,7 @@ describes.sandboxed('Viewer', {}, () => { const viewer = new ViewerImpl(ampdoc); expect(viewer.getParam('test')).to.equal('1'); expect(viewer.isCctEmbedded()).to.be.true; - yield viewer.whenFirstVisible(); + yield ampdoc.whenFirstVisible(); expect(windowApi.history.replaceState).to.be.calledWith( {}, '', @@ -265,7 +265,7 @@ describes.sandboxed('Viewer', {}, () => { expect(viewer.getParam('test')).to.equal('1'); expect(viewer.getParam('note')).to.equal('ok'); expect(viewer.isCctEmbedded()).to.be.true; - yield viewer.whenFirstVisible(); + yield ampdoc.whenFirstVisible(); expect(windowApi.history.replaceState).to.be.calledWith( {}, '', @@ -293,7 +293,7 @@ describes.sandboxed('Viewer', {}, () => { 'http://www.example.com/?amp_gsa=1&_js_v=a0' ); expect(viewer.getParam('click')).to.equal('abc'); - yield viewer.whenFirstVisible(); + yield ampdoc.whenFirstVisible(); expect(windowApi.history.replaceState).to.be.calledWith( {}, '', @@ -301,24 +301,20 @@ describes.sandboxed('Viewer', {}, () => { ); }); - it('should configure visibilityState visible by default', () => { - expect(viewer.getVisibilityState()).to.equal('visible'); - expect(viewer.isVisible()).to.equal(true); + it('should configure prerenderSize by default', () => { expect(viewer.getPrerenderSize()).to.equal(1); - expect(viewer.getFirstVisibleTime()).to.equal(0); - expect(viewer.getLastVisibleTime()).to.equal(0); }); it('should return promise that resolve on visible', function*() { const viewer = new ViewerImpl(ampdoc); - expect(viewer.isVisible()).to.be.true; - let promise = viewer.whenNextVisible(); + expect(ampdoc.isVisible()).to.be.true; + let promise = ampdoc.whenNextVisible(); yield promise; viewer.receiveMessage('visibilitychange', { state: 'hidden', }); - promise = viewer.whenNextVisible(); - expect(viewer.isVisible()).to.be.false; + promise = ampdoc.whenNextVisible(); + expect(ampdoc.isVisible()).to.be.false; viewer.receiveMessage('visibilitychange', { state: 'visible', }); @@ -328,36 +324,36 @@ describes.sandboxed('Viewer', {}, () => { it('should initialize firstVisibleTime when doc becomes visible', () => { params['prerenderSize'] = '3'; const viewer = new ViewerImpl(ampdoc); - expect(viewer.isVisible()).to.be.true; - expect(viewer.getFirstVisibleTime()).to.equal(0); - expect(viewer.getLastVisibleTime()).to.equal(0); + expect(ampdoc.isVisible()).to.be.true; + expect(ampdoc.getFirstVisibleTime()).to.equal(0); + expect(ampdoc.getLastVisibleTime()).to.equal(0); // Becomes invisible. clock.tick(1); viewer.receiveMessage('visibilitychange', { state: 'hidden', }); - expect(viewer.isVisible()).to.be.false; - expect(viewer.getFirstVisibleTime()).to.equal(0); - expect(viewer.getLastVisibleTime()).to.equal(0); + expect(ampdoc.isVisible()).to.be.false; + expect(ampdoc.getFirstVisibleTime()).to.equal(0); + expect(ampdoc.getLastVisibleTime()).to.equal(0); // Back to visible. clock.tick(1); viewer.receiveMessage('visibilitychange', { state: 'visible', }); - expect(viewer.isVisible()).to.be.true; - expect(viewer.getFirstVisibleTime()).to.equal(0); - expect(viewer.getLastVisibleTime()).to.equal(2); + expect(ampdoc.isVisible()).to.be.true; + expect(ampdoc.getFirstVisibleTime()).to.equal(0); + expect(ampdoc.getLastVisibleTime()).to.equal(2); // Back to invisible again. clock.tick(1); viewer.receiveMessage('visibilitychange', { state: 'hidden', }); - expect(viewer.isVisible()).to.be.false; - expect(viewer.getFirstVisibleTime()).to.equal(0); - expect(viewer.getLastVisibleTime()).to.equal(2); + expect(ampdoc.isVisible()).to.be.false; + expect(ampdoc.getFirstVisibleTime()).to.equal(0); + expect(ampdoc.getLastVisibleTime()).to.equal(2); }); it('should configure prerenderSize', () => { @@ -501,24 +497,21 @@ describes.sandboxed('Viewer', {}, () => { viewer.receiveMessage('visibilitychange', { state: 'paused', }); - expect(viewer.getVisibilityState()).to.equal('paused'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('paused'); }); it('should receive "paused" visibilityState', () => { viewer.receiveMessage('visibilitychange', { state: 'paused', }); - expect(viewer.getVisibilityState()).to.equal('paused'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('paused'); }); it('should receive "inactive" visibilityState', () => { viewer.receiveMessage('visibilitychange', { state: 'inactive', }); - expect(viewer.getVisibilityState()).to.equal('inactive'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); }); it('should parse "hidden" as "prerender" before first visible', () => { @@ -526,8 +519,7 @@ describes.sandboxed('Viewer', {}, () => { viewer.receiveMessage('visibilitychange', { state: 'hidden', }); - expect(viewer.getVisibilityState()).to.equal('prerender'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('prerender'); }); it('should parse "hidden" as "inactive" after first visible', () => { @@ -535,8 +527,7 @@ describes.sandboxed('Viewer', {}, () => { viewer.receiveMessage('visibilitychange', { state: 'hidden', }); - expect(viewer.getVisibilityState()).to.equal('inactive'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); }); it('should reject unknown values', () => { @@ -550,30 +541,25 @@ describes.sandboxed('Viewer', {}, () => { }); }).to.throw('Unknown VisibilityState value'); }); - expect(viewer.getVisibilityState()).to.equal('paused'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('paused'); }); it('should be inactive when the viewer tells us we are inactive', () => { viewer.receiveMessage('visibilitychange', { state: 'inactive', }); - expect(viewer.getVisibilityState()).to.equal('inactive'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); changeVisibility('hidden'); - expect(viewer.getVisibilityState()).to.equal('inactive'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); }); it('should be prerender when the viewer tells us we are prerender', () => { viewer.receiveMessage('visibilitychange', { state: 'prerender', }); - expect(viewer.getVisibilityState()).to.equal('prerender'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('prerender'); changeVisibility('visible'); - expect(viewer.getVisibilityState()).to.equal('prerender'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('prerender'); }); it('should be hidden when the browser document is hidden', () => { @@ -581,18 +567,15 @@ describes.sandboxed('Viewer', {}, () => { viewer.receiveMessage('visibilitychange', { state: 'visible', }); - expect(viewer.getVisibilityState()).to.equal('hidden'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('hidden'); viewer.receiveMessage('visibilitychange', { state: 'paused', }); - expect(viewer.getVisibilityState()).to.equal('hidden'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('hidden'); viewer.receiveMessage('visibilitychange', { state: 'visible', }); - expect(viewer.getVisibilityState()).to.equal('hidden'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('hidden'); }); it( @@ -603,8 +586,7 @@ describes.sandboxed('Viewer', {}, () => { viewer.receiveMessage('visibilitychange', { state: 'paused', }); - expect(viewer.getVisibilityState()).to.equal('paused'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('paused'); } ); @@ -613,58 +595,47 @@ describes.sandboxed('Viewer', {}, () => { viewer.receiveMessage('visibilitychange', { state: 'visible', }); - expect(viewer.getVisibilityState()).to.equal('visible'); - expect(viewer.isVisible()).to.equal(true); + expect(ampdoc.getVisibilityState()).to.equal('visible'); }); it('should change visibility on visibilitychange event', () => { changeVisibility('hidden'); - expect(viewer.getVisibilityState()).to.equal('hidden'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('hidden'); changeVisibility('visible'); - expect(viewer.getVisibilityState()).to.equal('visible'); - expect(viewer.isVisible()).to.equal(true); + expect(ampdoc.getVisibilityState()).to.equal('visible'); clock.tick(1); viewer.receiveMessage('visibilitychange', { state: 'hidden', }); changeVisibility('hidden'); - expect(viewer.getVisibilityState()).to.equal('inactive'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); changeVisibility('visible'); - expect(viewer.getVisibilityState()).to.equal('inactive'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); viewer.receiveMessage('visibilitychange', { state: 'inactive', }); changeVisibility('hidden'); - expect(viewer.getVisibilityState()).to.equal('inactive'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); changeVisibility('visible'); - expect(viewer.getVisibilityState()).to.equal('inactive'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('inactive'); viewer.receiveMessage('visibilitychange', { state: 'paused', }); changeVisibility('hidden'); - expect(viewer.getVisibilityState()).to.equal('hidden'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('hidden'); changeVisibility('visible'); - expect(viewer.getVisibilityState()).to.equal('paused'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('paused'); viewer.receiveMessage('visibilitychange', { state: 'visible', }); changeVisibility('hidden'); - expect(viewer.getVisibilityState()).to.equal('hidden'); - expect(viewer.isVisible()).to.equal(false); + expect(ampdoc.getVisibilityState()).to.equal('hidden'); changeVisibility('visible'); - expect(viewer.getVisibilityState()).to.equal('visible'); - expect(viewer.isVisible()).to.equal(true); + expect(ampdoc.getVisibilityState()).to.equal('visible'); }); }); diff --git a/test/unit/test-viewport.js b/test/unit/test-viewport.js index 2b2827701ffd..2df88b29bf7c 100644 --- a/test/unit/test-viewport.js +++ b/test/unit/test-viewport.js @@ -60,6 +60,7 @@ describes.fakeWin('Viewport', {}, env => { let updatedPaddingTop; let viewportSize; let vsyncTasks; + let onVisibilityHandlers; beforeEach(() => { sandbox = env.sandbox; @@ -91,9 +92,6 @@ describes.fakeWin('Viewport', {}, env => { } }, sendMessage: sandbox.spy(), - getVisibilityState: () => visibilityState, - isVisible: () => visibilityState == 'visible', - onVisibilityChanged: () => {}, }; viewerMock = sandbox.mock(viewer); installTimerService(windowApi); @@ -101,8 +99,23 @@ describes.fakeWin('Viewport', {}, env => { installPlatformService(windowApi); installDocService(windowApi, /* isSingleDoc */ true); installGlobalDocumentStateService(windowApi); + ampdoc = Services.ampdocServiceFor(windowApi).getSingleDoc(); installViewerServiceForDoc(ampdoc); + sandbox.stub(ampdoc, 'getVisibilityState').callsFake(() => visibilityState); + sandbox + .stub(ampdoc, 'isVisible') + .callsFake(() => visibilityState == 'visible'); + onVisibilityHandlers = []; + sandbox.stub(ampdoc, 'onVisibilityChanged').callsFake(handler => { + onVisibilityHandlers.push(handler); + return function() { + const index = onVisibilityHandlers.indexOf(handler); + if (index != -1) { + onVisibilityHandlers.splice(index, 1); + } + }; + }); binding = new ViewportBindingDef(); viewportSize = {width: 111, height: 222}; @@ -144,6 +157,11 @@ describes.fakeWin('Viewport', {}, env => { viewerMock.verify(); }); + function changeVisibilityState(value) { + visibilityState = value; + onVisibilityHandlers.forEach(handler => handler()); + } + function runVsync() { const tasks = vsyncTasks.slice(0); vsyncTasks = []; @@ -353,11 +371,10 @@ describes.fakeWin('Viewport', {}, env => { }); it('should connect binding later when visibility changes', () => { + onVisibilityHandlers.length = 0; + changeVisibilityState('hidden'); binding.connect = sandbox.spy(); binding.disconnect = sandbox.spy(); - viewer.isVisible = () => false; - let onVisibilityHandler; - viewer.onVisibilityChanged = handler => (onVisibilityHandler = handler); viewport = new ViewportImpl(ampdoc, binding, viewer); // Hasn't been called at first. @@ -366,29 +383,26 @@ describes.fakeWin('Viewport', {}, env => { expect(viewport.size_).to.be.null; // When becomes visible - it gets called. - viewer.isVisible = () => true; - onVisibilityHandler(); + changeVisibilityState('visible'); expect(binding.connect).to.be.calledOnce; expect(binding.disconnect).to.not.be.called; // Repeat visibility calls do not affect anything. - onVisibilityHandler(); + changeVisibilityState('visible'); expect(binding.connect).to.be.calledOnce; expect(binding.disconnect).to.not.be.called; // When becomes invisible - it gets disconnected. - viewer.isVisible = () => false; - onVisibilityHandler(); + changeVisibilityState('hidden'); expect(binding.connect).to.be.calledOnce; expect(binding.disconnect).to.be.calledOnce; }); it('should resize only after size has been initialed', () => { + onVisibilityHandlers.length = 0; + changeVisibilityState('visible'); binding.connect = sandbox.spy(); binding.disconnect = sandbox.spy(); - viewer.isVisible = () => true; - let onVisibilityHandler; - viewer.onVisibilityChanged = handler => (onVisibilityHandler = handler); viewport = new ViewportImpl(ampdoc, binding, viewer); // Size has not be initialized yet. @@ -397,16 +411,14 @@ describes.fakeWin('Viewport', {}, env => { expect(viewport.size_).to.be.null; // Disconnect: ignore resizing. - viewer.isVisible = () => false; - onVisibilityHandler(); + changeVisibilityState('hidden'); expect(binding.connect).to.be.calledOnce; expect(binding.disconnect).to.be.calledOnce; expect(viewport.size_).to.be.null; // Size has been initialized. viewport.size_ = {width: 0, height: 0}; - viewer.isVisible = () => true; - onVisibilityHandler(); + changeVisibilityState('visible'); expect(binding.connect).to.be.calledTwice; expect(binding.disconnect).to.be.calledOnce; expect(viewport.size_).to.deep.equal(viewportSize); diff --git a/test/unit/test-vsync.js b/test/unit/test-vsync.js index 9b3a9e2167b9..6da79e810180 100644 --- a/test/unit/test-vsync.js +++ b/test/unit/test-vsync.js @@ -22,8 +22,6 @@ import {installTimerService} from '../../src/service/timer-impl'; describes.sandboxed('vsync', {}, () => { let clock; let win; - let viewer; - let viewerVisibilityChangedHandler; let docState; let docVisibilityHandler; let contextNode; @@ -50,13 +48,6 @@ describes.sandboxed('vsync', {}, () => { installTimerService(win); - viewerVisibilityChangedHandler = undefined; - viewer = { - isVisible: () => true, - onVisibilityChanged: handler => - (viewerVisibilityChangedHandler = handler), - }; - docVisibilityHandler = undefined; docState = { isHidden: () => false, @@ -74,21 +65,21 @@ describes.sandboxed('vsync', {}, () => { describe('single-doc', () => { let ampdoc; + let isVisibleStub; + let onVisibilityChangedStub; let vsync; beforeEach(() => { installDocService(win, /* isSingleDoc */ true); ampdoc = Services.ampdocServiceFor(win).getSingleDoc(); - win.__AMP_SERVICES['viewer'] = {obj: viewer}; + isVisibleStub = sandbox.stub(ampdoc, 'isVisible').returns(true); + onVisibilityChangedStub = sandbox.stub(ampdoc, 'onVisibilityChanged'); vsync = new Vsync(win); - return Services.viewerPromiseForDoc(ampdoc); }); - afterEach(() => {}); - it('should init correctly', () => { expect(vsync.canAnimate(contextNode)).to.be.true; - expect(viewerVisibilityChangedHandler).to.exist; + expect(onVisibilityChangedStub).to.be.calledOnce; expect(docVisibilityHandler).to.not.exist; }); @@ -270,7 +261,7 @@ describes.sandboxed('vsync', {}, () => { it('should schedule via animation frames when doc is visible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => true; + isVisibleStub.returns(true); let result = ''; vsync.run({ @@ -296,7 +287,7 @@ describes.sandboxed('vsync', {}, () => { it('should schedule via timer frames when doc is not visible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => false; + isVisibleStub.returns(false); let result = ''; vsync.run({ @@ -322,7 +313,7 @@ describes.sandboxed('vsync', {}, () => { vsync.raf_ = function() { // intentionally empty }; - viewer.isVisible = () => true; + isVisibleStub.returns(true); let result = ''; vsync.run({ @@ -355,7 +346,7 @@ describes.sandboxed('vsync', {}, () => { it('should re-schedule when doc goes invisible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => true; + isVisibleStub.returns(true); let result = ''; vsync.run({ @@ -369,8 +360,8 @@ describes.sandboxed('vsync', {}, () => { expect(rafHandler).to.exist; expect(vsync.invisiblePass_.isPending()).to.be.false; - viewer.isVisible = () => false; - viewerVisibilityChangedHandler(); + isVisibleStub.returns(false); + onVisibilityChangedStub.args[0][0](); expect(vsync.tasks_).to.have.length(1); expect(vsync.scheduled_).to.be.true; @@ -386,7 +377,7 @@ describes.sandboxed('vsync', {}, () => { it('should re-schedule when doc goes visible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => false; + isVisibleStub.returns(false); let result = ''; vsync.run({ @@ -400,8 +391,8 @@ describes.sandboxed('vsync', {}, () => { expect(rafHandler).to.be.undefined; expect(vsync.invisiblePass_.isPending()).to.be.true; - viewer.isVisible = () => true; - viewerVisibilityChangedHandler(); + isVisibleStub.returns(true); + onVisibilityChangedStub.args[0][0](); expect(vsync.tasks_).to.have.length(1); expect(vsync.scheduled_).to.be.true; @@ -416,15 +407,15 @@ describes.sandboxed('vsync', {}, () => { it('should NOT re-schedule when no tasks pending', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => true; + isVisibleStub.returns(true); expect(vsync.tasks_).to.have.length(0); expect(vsync.scheduled_).to.be.false; expect(rafHandler).to.be.undefined; expect(vsync.invisiblePass_.isPending()).to.be.false; - viewer.isVisible = () => false; - viewerVisibilityChangedHandler(); + isVisibleStub.returns(false); + onVisibilityChangedStub.args[0][0](); expect(vsync.tasks_).to.have.length(0); expect(vsync.scheduled_).to.be.false; @@ -435,7 +426,7 @@ describes.sandboxed('vsync', {}, () => { it('should run anim task when visible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => true; + isVisibleStub.returns(true); let result = ''; const res = vsync.runAnim(contextNode, { @@ -455,7 +446,7 @@ describes.sandboxed('vsync', {}, () => { it('should create and run anim task when visible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => true; + isVisibleStub.returns(true); let result = ''; const task = vsync.createAnimTask(contextNode, { @@ -476,7 +467,7 @@ describes.sandboxed('vsync', {}, () => { it('should NOT run anim task when invisible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => false; + isVisibleStub.returns(false); let result = ''; // eslint-disable-line no-unused-vars const res = vsync.runAnim(contextNode, { @@ -493,7 +484,7 @@ describes.sandboxed('vsync', {}, () => { it('should create but NOT run anim task when invisible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => false; + isVisibleStub.returns(false); let result = ''; // eslint-disable-line no-unused-vars const task = vsync.createAnimTask(contextNode, { @@ -509,7 +500,7 @@ describes.sandboxed('vsync', {}, () => { }); it('should reject mutate series when invisible', () => { - viewer.isVisible = () => false; + isVisibleStub.returns(false); const mutatorSpy = sandbox.spy(); const promise = vsync.runAnimMutateSeries(contextNode, mutatorSpy); @@ -562,6 +553,8 @@ describes.sandboxed('vsync', {}, () => { describe('multi-doc', () => { let root; let ampdoc; + let isVisibleStub; + let onVisibilityChangedStub; let vsync; beforeEach(() => { @@ -569,8 +562,8 @@ describes.sandboxed('vsync', {}, () => { root = document.createElement('i-amphtml-shadow-root'); document.body.appendChild(root); ampdoc = new AmpDocShadow(win, 'https://acme.org/', root); - ampdoc.__AMP_SERVICES = {}; - ampdoc.__AMP_SERVICES['viewer'] = {obj: viewer}; + isVisibleStub = sandbox.stub(ampdoc, 'isVisible').returns(true); + onVisibilityChangedStub = sandbox.stub(ampdoc, 'onVisibilityChanged'); contextNode.ampdoc_ = ampdoc; vsync = new Vsync(win); }); @@ -582,13 +575,13 @@ describes.sandboxed('vsync', {}, () => { it('should init correctly', () => { expect(vsync.canAnimate(contextNode)).to.be.true; expect(docVisibilityHandler).to.exist; - expect(viewerVisibilityChangedHandler).to.not.exist; + expect(onVisibilityChangedStub).to.not.be.called; }); it('should schedule via animation frames when doc is visible', () => { let rafHandler; vsync.raf_ = handler => (rafHandler = handler); - viewer.isVisible = () => true; + isVisibleStub.returns(true); let result = ''; vsync.run({ diff --git a/test/unit/test-xhr-document-fetcher.js b/test/unit/test-xhr-document-fetcher.js index c26821568382..d3a0e7894d81 100644 --- a/test/unit/test-xhr-document-fetcher.js +++ b/test/unit/test-xhr-document-fetcher.js @@ -29,13 +29,11 @@ describes.realWin('DocumentFetcher', {amp: true}, function() { beforeEach(() => { ampdocServiceForStub = sandbox.stub(Services, 'ampdocServiceFor'); ampdocViewerStub = sandbox.stub(Services, 'viewerForDoc'); - ampdocViewerStub.returns({ - whenFirstVisible: () => Promise.resolve(), - }); + ampdocViewerStub.returns({}); ampdocServiceForStub.returns({ isSingleDoc: () => false, - getAmpDoc: () => ampdocViewerStub, - getSingleDoc: () => ampdocViewerStub, + getAmpDoc: () => null, + getSingleDoc: () => null, }); }); @@ -140,7 +138,10 @@ describes.realWin('DocumentFetcher', {amp: true}, function() { setupMockXhr(); optedInDoc = window.document.implementation.createHTMLDocument(''); optedInDoc.documentElement.setAttribute('allow-xhr-interception', ''); - const ampdoc = {getRootNode: () => optedInDoc}; + const ampdoc = { + getRootNode: () => optedInDoc, + whenFirstVisible: () => Promise.resolve(), + }; ampdocServiceForStub.returns({ isSingleDoc: () => true, getAmpDoc: () => ampdoc, diff --git a/test/unit/test-xhr.js b/test/unit/test-xhr.js index ac09d77f9972..cbdc369dfb7c 100644 --- a/test/unit/test-xhr.js +++ b/test/unit/test-xhr.js @@ -32,6 +32,7 @@ describe .run('XHR', function() { let sandbox; let ampdocServiceForStub; + let ampdoc; let ampdocViewerStub; let xhrCreated; let viewer; @@ -78,15 +79,17 @@ describe beforeEach(() => { sandbox = sinon.sandbox; ampdocServiceForStub = sandbox.stub(Services, 'ampdocServiceFor'); - ampdocViewerStub = sandbox.stub(Services, 'viewerForDoc'); - ampdocViewerStub.returns({ + ampdoc = { + getRootNode: () => null, whenFirstVisible: () => Promise.resolve(), - }); + }; ampdocServiceForStub.returns({ isSingleDoc: () => false, - getAmpDoc: () => ampdocViewerStub, - getSingleDoc: () => ampdocViewerStub, + getAmpDoc: () => ampdoc, + getSingleDoc: () => ampdoc, }); + ampdocViewerStub = sandbox.stub(Services, 'viewerForDoc'); + ampdocViewerStub.returns({}); location.href = 'https://acme.com/path'; }); @@ -255,23 +258,19 @@ describe return promise; }); - describe('viewer visibility', () => { + describe('doc visibility', () => { afterEach(() => { test.win.fetch.restore(); }); it('should not call fetch if view is not visible ', () => { const fetchCall = sandbox.spy(test.win, 'fetch'); - ampdocViewerStub.returns({ - whenFirstVisible: () => Promise.reject(), - }); + ampdoc.whenFirstVisible = () => Promise.reject(); xhr.fetchJson('/get', {ampCors: false}); expect(fetchCall.notCalled).to.be.true; }); it('should call fetch if view is visible ', () => { const fetchCall = sandbox.spy(test.win, 'fetch'); - ampdocViewerStub.returns({ - whenFirstVisible: () => Promise.resolve(), - }); + ampdoc.whenFirstVisible = () => Promise.resolve(); const fetch = xhr.fetchJson('/get', {ampCors: false}); fetch.then(() => { expect(fetchCall.calledOnce).to.be.true; @@ -665,7 +664,10 @@ describe optedInDoc = window.document.implementation.createHTMLDocument(''); optedInDoc.documentElement.setAttribute('allow-xhr-interception', ''); - const ampdoc = {getRootNode: () => optedInDoc}; + const ampdoc = { + getRootNode: () => optedInDoc, + whenFirstVisible: () => Promise.resolve(), + }; ampdocServiceForStub.returns({ isSingleDoc: () => true, getAmpDoc: () => ampdoc, @@ -698,7 +700,10 @@ describe }); it('should not intercept if AMP doc is not single', () => { - const ampdoc = {getRootNode: () => optedInDoc}; + const ampdoc = { + getRootNode: () => optedInDoc, + whenFirstVisible: () => Promise.resolve(), + }; ampdocServiceForStub.returns({ isSingleDoc: () => false, getAmpDoc: () => ampdoc, @@ -715,7 +720,10 @@ describe const nonOptedInDoc = window.document.implementation.createHTMLDocument( '' ); - const ampdoc = {getRootNode: () => nonOptedInDoc}; + const ampdoc = { + getRootNode: () => nonOptedInDoc, + whenFirstVisible: () => Promise.resolve(), + }; ampdocServiceForStub.returns({ isSingleDoc: () => true, getAmpDoc: () => ampdoc, diff --git a/test/unit/utils/test-xhr-utils.js b/test/unit/utils/test-xhr-utils.js index 4dfda347d40d..e3572e1c76e6 100644 --- a/test/unit/utils/test-xhr-utils.js +++ b/test/unit/utils/test-xhr-utils.js @@ -100,9 +100,10 @@ describes.sandboxed('utils/xhr-utils', {}, env => { beforeEach(() => { ampDocSingle = { - getRootNode: () => { + getRootNode() { return {documentElement: doc}; }, + whenFirstVisible: sandbox.stub().returns(Promise.resolve()), }; doc = document.createElement('html'); doc.setAttribute('allow-xhr-interception', 'true'); @@ -112,7 +113,6 @@ describes.sandboxed('utils/xhr-utils', {}, env => { hasCapability: unusedParam => true, isTrustedViewer: () => Promise.resolve(true), sendMessageAwaitResponse: sandbox.stub().returns(Promise.resolve({})), - whenFirstVisible: sandbox.stub().returns(Promise.resolve()), }; viewerForDoc = sandbox.stub(Services, 'viewerForDoc').returns(viewer); win = { @@ -201,7 +201,7 @@ describes.sandboxed('utils/xhr-utils', {}, env => { it('should wait for visibility', async () => { await getViewerInterceptResponse(win, ampDocSingle, input, init); - expect(viewer.whenFirstVisible).to.have.been.calledOnce; + expect(ampDocSingle.whenFirstVisible).to.have.been.calledOnce; }); it('should not wait for visibility if prerenderSafe', async () => { @@ -211,7 +211,7 @@ describes.sandboxed('utils/xhr-utils', {}, env => { await getViewerInterceptResponse(win, ampDocSingle, input, init); - expect(viewer.whenFirstVisible).to.not.have.been.called; + expect(ampDocSingle.whenFirstVisible).to.not.have.been.called; }); });