Skip to content

Commit

Permalink
Use an embed override for timer service (ampproject#31551)
Browse files Browse the repository at this point in the history
* Use an embed override for timer service

* fixed tests
  • Loading branch information
Dima Voytenko authored and Enriqe committed Dec 15, 2020
1 parent 7e9ac02 commit e75f58e
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 35 deletions.
4 changes: 1 addition & 3 deletions extensions/amp-a4a/0.1/amp-a4a.js
Original file line number Diff line number Diff line change
Expand Up @@ -1848,9 +1848,7 @@ export class AmpA4A extends AMP.BaseElement {
preinstallCallback_(embedWin, ampdoc) {
const parentAmpdoc = this.getAmpDoc();
installUrlReplacementsForEmbed(
// TODO(#22733): Cleanup `parentAmpdoc` once ampdoc-fie is launched.
ampdoc || parentAmpdoc,
embedWin,
ampdoc,
new A4AVariableSource(parentAmpdoc, embedWin)
);
}
Expand Down
4 changes: 1 addition & 3 deletions extensions/amp-a4a/0.1/friendly-frame-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ export function renderCreativeIntoFriendlyFrame(
(embedWin, ampdoc) => {
const parentAmpdoc = element.getAmpDoc();
installUrlReplacementsForEmbed(
// TODO(#22733): Cleanup `parentAmpdoc` once ampdoc-fie is launched.
ampdoc || parentAmpdoc,
embedWin,
ampdoc,
new A4AVariableSource(parentAmpdoc, embedWin)
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/friendly-iframe-embed.js
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ export class Installers {
* @param {!./service/ampdoc-impl.AmpDoc} ampdoc
*/
static installStandardServicesInEmbed(ampdoc) {
installAmpdocServicesForEmbed(ampdoc);
installTimerInEmbedWindow(ampdoc.win);
installAmpdocServicesForEmbed(ampdoc);
}
}
40 changes: 30 additions & 10 deletions src/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,11 @@ export class Disposable {

/**
* Installs a service override on amp-doc level.
* @param {!Window} embedWin
* @param {!./service/ampdoc-impl.AmpDoc} ampdoc
* @param {string} id
* @param {!Object} service The service.
*/
export function installServiceInEmbedScope(embedWin, id, service) {
// TODO(#22733): completely remove this method once ampdoc-fie launches.
const topWin = getTopWindow(embedWin);
devAssert(
embedWin != topWin,
'Service override can only be installed in embed window: %s',
id
);
const ampdoc = getAmpdoc(embedWin.document);
export function installServiceInEmbedDoc(ampdoc, id, service) {
registerServiceInternal(
getAmpdocServiceHolder(ampdoc),
ampdoc,
Expand All @@ -82,6 +74,22 @@ export function installServiceInEmbedScope(embedWin, id, service) {
);
}

/**
* Installs a service override in the scope of an embedded window.
* @param {!Window} embedWin
* @param {string} id
* @param {function(new:Object, !Window)} constructor
*/
export function registerServiceBuilderInEmbedWin(embedWin, id, constructor) {
registerServiceInternal(
embedWin,
embedWin,
id,
constructor,
/* override */ true
);
}

/**
* Registers a service given a class to be used as implementation.
* @param {!Window} win
Expand Down Expand Up @@ -146,6 +154,18 @@ export function getService(win, id) {
return getServiceInternal(win, id);
}

/**
* Returns a service for the given id and window (a per-window singleton). But
* it looks in the immediate window scope, not the top-level window.
* @param {!Window} win
* @param {string} id of the service.
* @template T
* @return {T}
*/
export function getServiceInEmbedWin(win, id) {
return getServiceInternal(win, id);
}

/**
* Returns a promise for a service for the given id and window. Also expects an
* element that has the actual implementation. The promise resolves when the
Expand Down
7 changes: 5 additions & 2 deletions src/service/timer-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
*/

import {getMode} from '../mode';
import {installServiceInEmbedScope, registerServiceBuilder} from '../service';
import {
registerServiceBuilder,
registerServiceBuilderInEmbedWin,
} from '../service';
import {reportError} from '../error';
import {user} from '../log';

Expand Down Expand Up @@ -186,7 +189,7 @@ export function installTimerService(window) {
* @param {!Window} embedWin
*/
export function installTimerInEmbedWindow(embedWin) {
installServiceInEmbedScope(embedWin, TAG, new Timer(embedWin));
registerServiceBuilderInEmbedWin(embedWin, TAG, Timer);
}

/**
Expand Down
9 changes: 4 additions & 5 deletions src/service/url-replacements-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
} from '../url';
import {dev, devAssert, user, userAssert} from '../log';
import {
installServiceInEmbedScope,
installServiceInEmbedDoc,
registerServiceBuilderForDoc,
} from '../service';

Expand Down Expand Up @@ -1149,12 +1149,11 @@ export function installUrlReplacementsServiceForDoc(ampdoc) {

/**
* @param {!./ampdoc-impl.AmpDoc} ampdoc
* @param {!Window} embedWin
* @param {!VariableSource} varSource
*/
export function installUrlReplacementsForEmbed(ampdoc, embedWin, varSource) {
installServiceInEmbedScope(
embedWin,
export function installUrlReplacementsForEmbed(ampdoc, varSource) {
installServiceInEmbedDoc(
ampdoc,
'url-replace',
new UrlReplacements(ampdoc, varSource)
);
Expand Down
3 changes: 2 additions & 1 deletion src/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
getService,
getServiceForDoc,
getServiceForDocOrNull,
getServiceInEmbedWin,
getServicePromiseForDoc,
} from './service';
import {
Expand Down Expand Up @@ -659,7 +660,7 @@ export class Services {
*/
static timerFor(window) {
// TODO(alabiaga): This will always return the top window's Timer service.
return /** @type {!./service/timer-impl.Timer} */ (getService(
return /** @type {!./service/timer-impl.Timer} */ (getServiceInEmbedWin(
window,
'timer'
));
Expand Down
2 changes: 1 addition & 1 deletion test/unit/test-amp-pixel.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ describes.realWin(
.stub(env.ampdoc, 'whenFirstVisible')
.callsFake(() => whenFirstVisiblePromise);

installUrlReplacementsForEmbed(env.ampdoc, win, new TestVariableSource());
installUrlReplacementsForEmbed(env.ampdoc, new TestVariableSource());

pixel = win.document.createElement('amp-pixel');
pixel.setAttribute(
Expand Down
12 changes: 8 additions & 4 deletions test/unit/test-element-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
isExtensionScriptInNode,
} from '../../src/element-service';
import {
installServiceInEmbedScope,
installServiceInEmbedDoc,
registerServiceBuilder,
registerServiceBuilderForDoc,
resetServiceForTesting,
Expand Down Expand Up @@ -411,6 +411,7 @@ describes.fakeWin('in embed scope', {amp: true}, (env) => {
let nodeInTopWin;
let frameElement;
let service;
let embedAmpDoc;

beforeEach(() => {
win = env.win;
Expand All @@ -422,7 +423,10 @@ describes.fakeWin('in embed scope', {amp: true}, (env) => {
embedWin.frameElement = frameElement;
setParentWindow(embedWin, win);

env.ampdocService.installFieDoc('https://example.org', embedWin);
embedAmpDoc = env.ampdocService.installFieDoc(
'https://example.org',
embedWin
);

nodeInEmbedWin = {
nodeType: Node.ELEMENT_NODE,
Expand All @@ -439,7 +443,7 @@ describes.fakeWin('in embed scope', {amp: true}, (env) => {
});

it('should return existing service', () => {
installServiceInEmbedScope(embedWin, 'foo', service);
installServiceInEmbedDoc(embedAmpDoc, 'foo', service);
return getElementServiceIfAvailableForDocInEmbedScope(
nodeInEmbedWin,
'foo',
Expand All @@ -456,7 +460,7 @@ describes.fakeWin('in embed scope', {amp: true}, (env) => {
'foo',
'amp-foo'
);
installServiceInEmbedScope(embedWin, 'foo', service);
installServiceInEmbedDoc(embedAmpDoc, 'foo', service);
return promise.then((returned) => {
expect(returned).to.equal(service);
});
Expand Down
13 changes: 8 additions & 5 deletions test/unit/test-friendly-iframe-embed.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ import {
import {Services} from '../../src/services';
import {Signals} from '../../src/utils/signals';
import {getFriendlyIframeEmbedOptional} from '../../src/iframe-helper';
import {installExtensionsService} from '../../src/service/extensions-impl';
import {
installServiceInEmbedScope,
getServiceInEmbedWin,
registerServiceBuilder,
registerServiceBuilderInEmbedWin,
setParentWindow,
} from '../../src/service';
import {installExtensionsService} from '../../src/service/extensions-impl';
import {isAnimationNone} from '../../testing/test-helper';
import {layoutRectLtwh} from '../../src/layout-rect';
import {loadPromise} from '../../src/event-helper';
Expand Down Expand Up @@ -368,7 +369,7 @@ describes.realWin('friendly-iframe-embed', {amp: true}, (env) => {
expect(customElementsDefineStub).to.be.calledWith('amp-test');
});

it.skip('should install and dispose services', () => {
it('should install and dispose services', () => {
const disposeSpy = env.sandbox.spy();
const embedService = {
dispose: disposeSpy,
Expand All @@ -381,11 +382,13 @@ describes.realWin('friendly-iframe-embed', {amp: true}, (env) => {
html: '<amp-test></amp-test>',
},
(embedWin) => {
installServiceInEmbedScope(embedWin, 'c', embedService);
registerServiceBuilderInEmbedWin(embedWin, 'c', function () {
return embedService;
});
}
);
return embedPromise.then((embed) => {
expect(embed.win.__AMP_SERVICES['c'].obj).to.equal(embedService);
expect(getServiceInEmbedWin(embed.win, 'c')).to.equal(embedService);
expect(disposeSpy).to.not.be.called;
embed.destroy();
expect(disposeSpy).to.be.calledOnce;
Expand Down
19 changes: 19 additions & 0 deletions test/unit/test-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import {
getService,
getServiceForDoc,
getServiceForDocOrNull,
getServiceInEmbedWin,
getServicePromise,
getServicePromiseForDoc,
getServicePromiseOrNull,
getServicePromiseOrNullForDoc,
isDisposable,
registerServiceBuilder,
registerServiceBuilderForDoc,
registerServiceBuilderInEmbedWin,
rejectServicePromiseForDoc,
resetServiceForTesting,
setParentWindow,
Expand Down Expand Up @@ -578,6 +580,23 @@ describe('service', () => {
.exist;
});

it('should override services on embedded window', () => {
const topService = {};
const embedService = {};
registerServiceBuilder(windowApi, 'A', function () {
return topService;
});
registerServiceBuilderInEmbedWin(childWin, 'A', function () {
return embedService;
});

expect(getService(windowApi, 'A')).to.equal(topService);
expect(getService(childWin, 'A')).to.equal(topService);

expect(getServiceInEmbedWin(windowApi, 'A')).to.equal(topService);
expect(getServiceInEmbedWin(childWin, 'A')).to.equal(embedService);
});

it('should dispose disposable services', () => {
const disposableFactory = function () {
return {
Expand Down

0 comments on commit e75f58e

Please sign in to comment.