diff --git a/extensions/amp-story/1.0/page-advancement.js b/extensions/amp-story/1.0/page-advancement.js index d076a2003cf9..3e3f7681c7c6 100644 --- a/extensions/amp-story/1.0/page-advancement.js +++ b/extensions/amp-story/1.0/page-advancement.js @@ -237,7 +237,7 @@ export class AdvancementConfig { * Always provides a progress of 1.0. Advances when the user taps the * corresponding section, depending on language settings. */ -class ManualAdvancement extends AdvancementConfig { +export class ManualAdvancement extends AdvancementConfig { /** * @param {!Window} win The Window object. * @param {!Element} element The element that, when clicked, can cause @@ -657,7 +657,7 @@ class ManualAdvancement extends AdvancementConfig { * Provides progress and advancement based on a fixed duration of time, * specified in either seconds or milliseconds. */ -class TimeBasedAdvancement extends AdvancementConfig { +export class TimeBasedAdvancement extends AdvancementConfig { /** * @param {!Window} win The Window object. * @param {number} delayMs The duration to wait before advancing. @@ -799,7 +799,7 @@ class TimeBasedAdvancement extends AdvancementConfig { * having been executed before the amp-story-page buildCallback, which is not * guaranteed. */ -class MediaBasedAdvancement extends AdvancementConfig { +export class MediaBasedAdvancement extends AdvancementConfig { /** * @param {!Window} win * @param {!Array} elements @@ -909,7 +909,7 @@ class MediaBasedAdvancement extends AdvancementConfig { return this.element_; } else if ( this.element_.hasAttribute('background-audio') && - (tagName === 'amp-story' || tagName === 'amp-story-page') + tagName === 'amp-story-page' ) { return this.element_.querySelector('.i-amphtml-story-background-audio'); } else if (tagName === 'amp-audio') { @@ -1051,10 +1051,26 @@ class MediaBasedAdvancement extends AdvancementConfig { */ static fromAutoAdvanceString(autoAdvanceStr, win, element) { try { - const elements = element.querySelectorAll( - `[data-id=${escapeCssSelectorIdent(autoAdvanceStr)}], - #${escapeCssSelectorIdent(autoAdvanceStr)}` + // amp-video, amp-audio, as well as amp-story-page with a background audio + // are eligible for media based auto advance. + const elements = toArray( + element.querySelectorAll( + `amp-video[data-id=${escapeCssSelectorIdent(autoAdvanceStr)}], + amp-video#${escapeCssSelectorIdent(autoAdvanceStr)}, + amp-audio[data-id=${escapeCssSelectorIdent(autoAdvanceStr)}], + amp-audio#${escapeCssSelectorIdent(autoAdvanceStr)}` + ) ); + if ( + matches( + element, + `amp-story-page[background-audio]#${escapeCssSelectorIdent( + autoAdvanceStr + )}` + ) + ) { + elements.push(element); + } if (!elements.length) { if (autoAdvanceStr) { user().warn( @@ -1066,7 +1082,7 @@ class MediaBasedAdvancement extends AdvancementConfig { return null; } - return new MediaBasedAdvancement(win, toArray(elements)); + return new MediaBasedAdvancement(win, elements); } catch (e) { return null; } diff --git a/extensions/amp-story/1.0/test/test-page-advancement.js b/extensions/amp-story/1.0/test/test-page-advancement.js new file mode 100644 index 000000000000..6eae4abc39e2 --- /dev/null +++ b/extensions/amp-story/1.0/test/test-page-advancement.js @@ -0,0 +1,183 @@ +/** + * Copyright 2020 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AdvancementConfig, + ManualAdvancement, + MediaBasedAdvancement, + TimeBasedAdvancement, +} from '../page-advancement'; +import {htmlFor} from '../../../../src/static-template'; + +describes.realWin('page-advancement', {amp: true}, (env) => { + let html; + let win; + + beforeEach(() => { + html = htmlFor(env.win.document); + win = env.win; + }); + + describe('forElement', () => { + describe('ManualAdvancement', () => { + it('should return a manual advancement for an amp-story element', () => { + const storyEl = win.document.createElement('amp-story'); + const advancement = AdvancementConfig.forElement(win, storyEl); + + expect(advancement).to.be.instanceOf(ManualAdvancement); + }); + + it('should not return a manual advancement for a non amp-story element', () => { + const pageEl = win.document.createElement('amp-story-page'); + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.not.be.instanceOf(ManualAdvancement); + }); + }); + + describe('TimeBasedAdvancement', () => { + it('should return a time advancement from ms unit', () => { + const pageEl = html` + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.be.instanceOf(TimeBasedAdvancement); + }); + + it('should return a time advancement from s unit', () => { + const pageEl = html` + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.be.instanceOf(TimeBasedAdvancement); + }); + + it('should not return a time advancement if no unit', () => { + const pageEl = html` + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.not.be.instanceOf(TimeBasedAdvancement); + }); + + it('should not return a time advancement if random string', () => { + const pageEl = html` + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.not.be.instanceOf(TimeBasedAdvancement); + }); + }); + + describe('MediaBasedAdvancement', () => { + it('should return a media advancement for amp-video with id', () => { + const pageEl = html` + + + + + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.be.instanceOf(MediaBasedAdvancement); + }); + + it('should return a media advancement for amp-video with data-id', () => { + const pageEl = html` + + + + + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.be.instanceOf(MediaBasedAdvancement); + }); + + it('should return a media advancement for amp-audio with id', () => { + const pageEl = html` + + + + + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.be.instanceOf(MediaBasedAdvancement); + }); + + it('should return a media advancement for amp-audio with data-id', () => { + const pageEl = html` + + + + + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.be.instanceOf(MediaBasedAdvancement); + }); + + it('should return a media advancement for amp-story-page with background audio', () => { + const pageEl = html` + + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.be.instanceOf(MediaBasedAdvancement); + }); + + it('should not return a media based advancement for other elements', () => { + const pageEl = html` + + + + + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.not.be.instanceOf(MediaBasedAdvancement); + }); + + it('should not return a media based advancement if id does not exist', () => { + const pageEl = html` + + + + + + `; + const advancement = AdvancementConfig.forElement(win, pageEl); + + expect(advancement).to.not.be.instanceOf(MediaBasedAdvancement); + }); + }); + }); +});