From 1e132537a07b22bd78a66829b8316e40df76b80c Mon Sep 17 00:00:00 2001 From: Kristofer Baxter Date: Wed, 25 Aug 2021 17:36:26 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=AE=20Remove=20IE=20Support=20via=20Po?= =?UTF-8?q?lyfills=20and=20Conditional=20Statements=20(#35317)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Since we are not using the data, lets remove it * Remove all isIE checks and polyfills only used by IE * Remove URL changes * Integration tests were looking for IE specifics * remove transparent img, and ie tests * Skip all tests on IE, this functionality will be removed by the infra team following success * try using user agent directy in test configuration * Fix * Feedback on describe tests not needing configuration now * Remove unused files again * Fix build before main is repaired --- build-system/test-configs/dep-check-config.js | 2 - build-system/test-configs/forbidden-terms.js | 1 - src/core/dom/img.js | 21 -- src/custom-element.js | 5 +- src/friendly-iframe-embed.js | 2 - src/polyfills/domtokenlist.js | 54 --- src/polyfills/index.js | 2 - src/service/ie-intrinsic-bug.js | 39 --- src/service/ie-media-bug.js | 61 ---- src/service/navigation.js | 20 +- src/service/platform-impl.js | 17 - src/service/resources-impl.js | 12 +- src/static-layout.js | 22 +- test/integration/builtins/test-amp-img.js | 210 ++++------- test/integration/test-amp-ad-3p.js | 2 +- test/integration/test-amp-ad-doubleclick.js | 331 +++++++++--------- test/integration/test-shadow-dom-element.js | 1 - test/integration/test-toggle-display.js | 87 +++-- test/unit/core/dom/layout/test-layout.js | 187 +++++----- .../polyfills/test-domtokenlist-toggle.js | 128 ------- test/unit/test-ie-media-bug.js | 176 ---------- test/unit/test-mutator.js | 6 - test/unit/test-platform.js | 23 -- testing/test-config.js | 19 +- 24 files changed, 374 insertions(+), 1054 deletions(-) delete mode 100644 src/polyfills/domtokenlist.js delete mode 100644 src/service/ie-intrinsic-bug.js delete mode 100644 src/service/ie-media-bug.js delete mode 100644 test/unit/polyfills/test-domtokenlist-toggle.js delete mode 100644 test/unit/test-ie-media-bug.js diff --git a/build-system/test-configs/dep-check-config.js b/build-system/test-configs/dep-check-config.js index a19e2eaef2ec..223b928af413 100644 --- a/build-system/test-configs/dep-check-config.js +++ b/build-system/test-configs/dep-check-config.js @@ -424,7 +424,6 @@ exports.rules = [ '3p/polyfills.js->src/polyfills/string-starts-with.js', 'src/amp.js->src/polyfills/index.js', 'src/polyfills/index.js->src/polyfills/abort-controller.js', - 'src/polyfills/index.js->src/polyfills/domtokenlist.js', 'src/polyfills/index.js->src/polyfills/document-contains.js', 'src/polyfills/index.js->src/polyfills/fetch.js', 'src/polyfills/index.js->src/polyfills/get-bounding-client-rect.js', @@ -443,7 +442,6 @@ exports.rules = [ 'src/friendly-iframe-embed.js->src/polyfills/abort-controller.js', 'src/friendly-iframe-embed.js->src/polyfills/custom-elements.js', 'src/friendly-iframe-embed.js->src/polyfills/document-contains.js', - 'src/friendly-iframe-embed.js->src/polyfills/domtokenlist.js', 'src/friendly-iframe-embed.js->src/polyfills/intersection-observer.js', 'src/friendly-iframe-embed.js->src/polyfills/resize-observer.js', ], diff --git a/build-system/test-configs/forbidden-terms.js b/build-system/test-configs/forbidden-terms.js index 571490557dcd..ea912bc3156f 100644 --- a/build-system/test-configs/forbidden-terms.js +++ b/build-system/test-configs/forbidden-terms.js @@ -653,7 +653,6 @@ const forbiddenTermsGlobal = { message: 'SVG data images must use charset=utf-8: ' + '"data:image/svg+xml;charset=utf-8,..."', - allowlist: ['src/service/ie-intrinsic-bug.js'], }, 'new CustomEvent\\(': { message: 'Use createCustomEvent() helper instead.', diff --git a/src/core/dom/img.js b/src/core/dom/img.js index 04a6fe25a546..a435f065922f 100644 --- a/src/core/dom/img.js +++ b/src/core/dom/img.js @@ -15,24 +15,3 @@ export function guaranteeSrcForSrcsetUnsupportedBrowsers(img) { img.setAttribute('src', srcseturl); } } - -/** - * Generates a transparent PNG of a given width/height. - * - * @param {!Document} doc - * @param {number} width - * @param {number} height - * @return {string} - */ -export function transparentPng(doc, width, height) { - const canvas = /** @type {!HTMLCanvasElement} */ ( - doc.createElement('canvas') - ); - canvas.width = width; - canvas.height = height; - - // Canvases are fully transparent by default, so we don't actually need to - // draw anything. - - return canvas.toDataURL(); -} diff --git a/src/custom-element.js b/src/custom-element.js index 42dbd0a8d4f3..c716f3a44b9c 100644 --- a/src/custom-element.js +++ b/src/custom-element.js @@ -1175,10 +1175,7 @@ function createBaseCustomElementClass(win, elementConnectedCallback) { this.everAttached = true; try { - this.layout_ = applyStaticLayout( - this, - Services.platformFor(toWin(this.ownerDocument.defaultView)).isIe() - ); + this.layout_ = applyStaticLayout(this); this.initMediaAttrs_(); } catch (e) { reportError(e, this); diff --git a/src/friendly-iframe-embed.js b/src/friendly-iframe-embed.js index d276b638fefb..9f7ffc758a42 100644 --- a/src/friendly-iframe-embed.js +++ b/src/friendly-iframe-embed.js @@ -19,7 +19,6 @@ import {toWin} from '#core/window'; import {install as installAbortController} from '#polyfills/abort-controller'; import {install as installCustomElements} from '#polyfills/custom-elements'; import {install as installDocContains} from '#polyfills/document-contains'; -import {install as installDOMTokenList} from '#polyfills/domtokenlist'; import {installForChildWin as installIntersectionObserver} from '#polyfills/intersection-observer'; import {installForChildWin as installResizeObserver} from '#polyfills/resize-observer'; @@ -686,7 +685,6 @@ export class FriendlyIframeEmbed { function installPolyfillsInChildWindow(parentWin, childWin) { if (!mode.isEsm()) { installDocContains(childWin); - installDOMTokenList(childWin); } // The anonymous class parameter allows us to detect native classes vs // transpiled classes. diff --git a/src/polyfills/domtokenlist.js b/src/polyfills/domtokenlist.js deleted file mode 100644 index fa555d0e0480..000000000000 --- a/src/polyfills/domtokenlist.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Polyfill for `DOMTokenList.prototype.toggle(token, opt_force)` method. This - * is specially important because IE does not support `opt_force` attribute. See - * https://goo.gl/hgKNYY for details. - * @param {string} token - * @param {boolean=} opt_force - * @this {DOMTokenList} - * @return {boolean} - */ -function domTokenListTogglePolyfill(token, opt_force) { - // eslint-disable-next-line local/no-invalid-this - const remove = opt_force === undefined ? this.contains(token) : !opt_force; - if (remove) { - // eslint-disable-next-line local/no-invalid-this - this.remove(token); - return false; - } else { - // eslint-disable-next-line local/no-invalid-this - this.add(token); - return true; - } -} - -/** - * Polyfills `DOMTokenList.prototype.toggle` API and makes `.add` accepts N - * classes in IE. - * @param {!Window} win - */ -export function install(win) { - if (isIe(win) && win.DOMTokenList) { - win.Object.defineProperty(win.DOMTokenList.prototype, 'toggle', { - enumerable: false, - configurable: true, - writable: true, - value: domTokenListTogglePolyfill, - }); - - const {add} = win.DOMTokenList.prototype; - win.DOMTokenList.prototype.add = function () { - for (let i = 0; i < arguments.length; i++) { - add.call(this, arguments[i]); - } - }; - } -} - -/** - * Whether the current browser is a IE browser. - * @param {!Window} win - * @return {boolean} - */ -function isIe(win) { - return /Trident|MSIE|IEMobile/i.test(win.navigator.userAgent); -} diff --git a/src/polyfills/index.js b/src/polyfills/index.js index d70f22c5ef92..76beba37927e 100644 --- a/src/polyfills/index.js +++ b/src/polyfills/index.js @@ -6,7 +6,6 @@ import {install as installAbortController} from './abort-controller'; import {install as installArrayIncludes} from './array-includes'; import {install as installCustomElements} from './custom-elements'; import {install as installDocContains} from './document-contains'; -import {install as installDOMTokenList} from './domtokenlist'; import {install as installFetch} from './fetch'; import {install as installGetBoundingClientRect} from './get-bounding-client-rect'; import {install as installIntersectionObserver} from './intersection-observer'; @@ -36,7 +35,6 @@ if (!mode.isEsm()) { // Polyfills that depend on DOM availability if (self.document) { if (!mode.isEsm()) { - installDOMTokenList(self); installDocContains(self); installGetBoundingClientRect(self); } diff --git a/src/service/ie-intrinsic-bug.js b/src/service/ie-intrinsic-bug.js deleted file mode 100644 index ae8248338527..000000000000 --- a/src/service/ie-intrinsic-bug.js +++ /dev/null @@ -1,39 +0,0 @@ -import {transparentPng} from '#core/dom/img'; -import {getLengthNumeral} from '#core/dom/layout'; -import {closestAncestorElementBySelector} from '#core/dom/query'; - -import {Services} from '#service'; - -/** - * IE can't handle auto-scaling SVG images used for intrinsic layout. Generate - * a transparent PNG for SSR rendered sizers instead. - * @param {!Window} win - * @param {!../service/platform-impl.Platform=} opt_platform - * @package - */ -export function ieIntrinsicCheckAndFix(win, opt_platform) { - const platform = opt_platform || Services.platformFor(win); - if (!platform.isIe()) { - return; - } - - const {document} = win; - const intrinsics = document.querySelectorAll( - '.i-amphtml-intrinsic-sizer[src^="data:image/svg"]' - ); - for (let i = 0; i < intrinsics.length; i++) { - const intrinsic = intrinsics[i]; - const element = closestAncestorElementBySelector( - intrinsic, - '.i-amphtml-element' - ); - if (!element) { - continue; - } - const width = getLengthNumeral(element.getAttribute('width')); - const height = getLengthNumeral(element.getAttribute('height')); - if (width && height) { - intrinsic.src = transparentPng(document, width, height); - } - } -} diff --git a/src/service/ie-media-bug.js b/src/service/ie-media-bug.js deleted file mode 100644 index 55d19d4b29bb..000000000000 --- a/src/service/ie-media-bug.js +++ /dev/null @@ -1,61 +0,0 @@ -import {Services} from '#service'; - -import {dev} from '../log'; - -const TAG = 'ie-media-bug'; - -/** - * An ugly fix for IE's problem with `matchMedia` API, where media queries - * are evaluated incorrectly. See #2577 for more details. Returns the promise - * that will be resolved when the bug is fixed. - * @param {!Window} win - * @param {!../service/platform-impl.Platform=} opt_platform - * @return {?Promise} - * @package - */ -export function ieMediaCheckAndFix(win, opt_platform) { - const platform = opt_platform || Services.platformFor(win); - if (!platform.isIe() || matchMediaIeQuite(win)) { - return null; - } - - // Poll until the expression resolves correctly, but only up to a point. - return new Promise((resolve) => { - /** @const {number} */ - const endTime = Date.now() + 2000; - /** @const {number} */ - const interval = win.setInterval(() => { - const now = Date.now(); - const matches = matchMediaIeQuite(win); - if (matches || now > endTime) { - win.clearInterval(interval); - resolve(); - if (!matches) { - dev().error(TAG, 'IE media never resolved'); - } - } - }, 10); - }); -} - -/** - * @param {!Window} win - * @return {boolean} - * @private - */ -function matchMediaIeQuite(win) { - // The expression is `min-width <= W <= max-width`. - // In IE `min-width: X` actually compares string `<`, thus we add -1 to - // `min-width` and add +1 to `max-width`. Given the expression above, it's - // a non-essential correction by 1px. - const q = - `(min-width: ${win./*OK*/ innerWidth - 1}px)` + - ` AND (max-width: ${win./*OK*/ innerWidth + 1}px)`; - try { - return win.matchMedia(q).matches; - } catch (e) { - dev().error(TAG, 'IE matchMedia failed: ', e); - // Return `true` to avoid polling on a broken API. - return true; - } -} diff --git a/src/service/navigation.js b/src/service/navigation.js index 441de685f83b..dd461eccd3d5 100644 --- a/src/service/navigation.js +++ b/src/service/navigation.js @@ -1,8 +1,7 @@ import {PriorityQueue} from '#core/data-structures/priority-queue'; -import {isIframed, tryFocus} from '#core/dom'; +import {isIframed} from '#core/dom'; import {escapeCssSelectorIdent} from '#core/dom/css-selectors'; import {closestAncestorElementBySelector} from '#core/dom/query'; -import * as mode from '#core/mode'; import {dict} from '#core/types/object'; import {toWin} from '#core/window'; @@ -599,23 +598,6 @@ export class Navigation { * @private */ handleHashNavigation_(e, toLocation, fromLocation) { - // Anchor navigation in IE doesn't change input focus, which can result in - // confusing behavior e.g. when pressing "tab" button. - // @see https://humanwhocodes.com/blog/2013/01/15/fixing-skip-to-content-links/ - // @see https://github.com/ampproject/amphtml/issues/18671 - if (!mode.isEsm() && Services.platformFor(this.ampdoc.win).isIe()) { - const id = toLocation.hash.substring(1); - const elementWithId = this.ampdoc.getElementById(id); - if (elementWithId) { - if ( - !/^(?:a|select|input|button|textarea)$/i.test(elementWithId.tagName) - ) { - elementWithId.tabIndex = -1; - } - tryFocus(elementWithId); - } - } - // We prevent default so that the current click does not push // into the history stack as this messes up the external documents // history which contains the amp document. diff --git a/src/service/platform-impl.js b/src/service/platform-impl.js index 4603cbb40301..10d5b446ab7e 100644 --- a/src/service/platform-impl.js +++ b/src/service/platform-impl.js @@ -1,5 +1,3 @@ -import * as mode from '#core/mode'; - import {registerServiceBuilder} from '../service-helpers'; /** @@ -42,7 +40,6 @@ export class Platform { return ( /Safari/i.test(this.navigator_.userAgent) && !this.isChrome() && - !this.isIe() && !this.isEdge() && !this.isFirefox() && !this.isOpera() @@ -81,17 +78,6 @@ export class Platform { return /OPR\/|Opera|OPiOS/i.test(this.navigator_.userAgent); } - /** - * Whether the current browser is a IE browser. - * @return {boolean} - */ - isIe() { - if (mode.isEsm()) { - return false; - } - return /Trident|MSIE|IEMobile/i.test(this.navigator_.userAgent); - } - /** * Whether the current browser is an Edge browser. * @return {boolean} @@ -155,9 +141,6 @@ export class Platform { if (this.isOpera()) { return this.evalMajorVersion_(/(OPR|Opera|OPiOS)\/(\d+)/, 2); } - if (this.isIe()) { - return this.evalMajorVersion_(/MSIE\s(\d+)/, 1); - } if (this.isEdge()) { return this.evalMajorVersion_(/Edge\/(\d+)/, 1); } diff --git a/src/service/resources-impl.js b/src/service/resources-impl.js index 703951ba3a25..b706ad3e96f2 100644 --- a/src/service/resources-impl.js +++ b/src/service/resources-impl.js @@ -10,8 +10,6 @@ import {dict} from '#core/types/object'; import {Services} from '#service'; -import {ieIntrinsicCheckAndFix} from './ie-intrinsic-bug'; -import {ieMediaCheckAndFix} from './ie-media-bug'; import {Resource, ResourceState} from './resource'; import {READY_SCAN_SIGNAL, ResourcesInterface} from './resources-interface'; import {TaskQueue} from './task-queue'; @@ -242,16 +240,8 @@ export class ResourcesImpl { return; } - ieIntrinsicCheckAndFix(this.win); - - const fixPromise = ieMediaCheckAndFix(this.win); const remeasure = () => this.remeasurePass_.schedule(); - if (fixPromise) { - fixPromise.then(remeasure); - } else { - // No promise means that there's no problem. - remeasure(); - } + remeasure(); // Safari 10 and under incorrectly estimates font spacing for // `@font-face` fonts. This leads to wild measurement errors. The best diff --git a/src/static-layout.js b/src/static-layout.js index 400339d699ce..eabb6a774c33 100644 --- a/src/static-layout.js +++ b/src/static-layout.js @@ -1,10 +1,4 @@ -import { - devAssert, - devAssertNumber, - devAssertString, - userAssert, -} from '#core/assert'; -import {transparentPng} from '#core/dom/img'; +import {devAssert, devAssertString, userAssert} from '#core/assert'; import { Layout, getLayoutClass, @@ -16,7 +10,6 @@ import { } from '#core/dom/layout'; import {htmlFor} from '#core/dom/static-template'; import {setStyle, setStyles, toggle} from '#core/dom/style'; -import * as mode from '#core/mode'; import {toWin} from '#core/window'; import {isExperimentOn} from '#experiments'; @@ -124,10 +117,9 @@ export function getNaturalDimensions(element) { * implement SSR. For more information on SSR see bit.ly/amp-ssr. * * @param {!Element} element - * @param {boolean} fixIeIntrinsic * @return {!Layout} */ -export function applyStaticLayout(element, fixIeIntrinsic = false) { +export function applyStaticLayout(element) { // Check if the layout has already been done by server-side rendering or // client-side rendering and the element was cloned. The document may be // visible to the user if the boilerplate was removed so please take care in @@ -199,7 +191,7 @@ export function applyStaticLayout(element, fixIeIntrinsic = false) { } } else if (layout == Layout.INTRINSIC) { // Intrinsic uses an svg inside the sizer element rather than the padding - // trick Note a naked svg won't work becasue other thing expect the + // trick Note a naked svg won't work because other things expect the // i-amphtml-sizer element const sizer = htmlFor(element)` @@ -209,13 +201,7 @@ export function applyStaticLayout(element, fixIeIntrinsic = false) { const intrinsicSizer = sizer.firstElementChild; intrinsicSizer.setAttribute( 'src', - !mode.isEsm() && fixIeIntrinsic && element.ownerDocument - ? transparentPng( - element.ownerDocument, - devAssertNumber(getLengthNumeral(width)), - devAssertNumber(getLengthNumeral(height)) - ) - : `data:image/svg+xml;charset=utf-8,` + `data:image/svg+xml;charset=utf-8,` ); element.insertBefore(sizer, element.firstChild); element.sizerElement = sizer; diff --git a/test/integration/builtins/test-amp-img.js b/test/integration/builtins/test-amp-img.js index 64b2ad9bc243..6bf6d80acdd7 100644 --- a/test/integration/builtins/test-amp-img.js +++ b/test/integration/builtins/test-amp-img.js @@ -1,151 +1,77 @@ import {AmpEvents} from '#core/constants/amp-events'; -import { - createFixtureIframe, - expectBodyToBecomeVisible, - poll, -} from '#testing/iframe'; +import {createFixtureIframe, expectBodyToBecomeVisible} from '#testing/iframe'; import {createCustomEvent} from '../../../src/event-helper'; -describes.sandboxed - .configure() - .enableIe() - .run('Rendering of amp-img', {}, () => { - const timeout = window.ampTestRuntimeConfig.mochaTimeout; - - let fixture; - beforeEach(async () => { - fixture = await createFixtureIframe('test/fixtures/images.html', 500); - }); - - it('should show the body in image test', async () => { - await expectBodyToBecomeVisible(fixture.win, timeout); - }); - - it('should be present', async () => { - expect(fixture.doc.querySelectorAll('amp-img')).to.have.length(16); - // 5 image visible in 500 pixel height. Note that there will be no load - // event for the inabox image. - await fixture.awaitEvent(AmpEvents.LOAD_START, 3); - expect(fixture.doc.querySelectorAll('amp-img img[src]')).to.have.length( - 4 - ); - }); - - it('should resize and load more elements', async () => { - // Note that there will be no load event for the inabox image. - fixture.iframe.height = 1500; - fixture.win.dispatchEvent(createCustomEvent(fixture.win, 'resize', null)); - await fixture.awaitEvent(AmpEvents.LOAD_START, 11); - expect(fixture.doc.querySelectorAll('amp-img img[src]')).to.have.length( - 12 - ); - - fixture.iframe.height = 2000; - fixture.win.dispatchEvent(createCustomEvent(fixture.win, 'resize', null)); - await fixture.awaitEvent(AmpEvents.LOAD_START, 13); - expect(fixture.doc.querySelectorAll('amp-img img[src]')).to.have.length( - 14 - ); - }); - - it('should respect media queries', async () => { - await fixture.awaitEvent(AmpEvents.LOAD_START, 3); - await new Promise((res) => setTimeout(res, 1)); - - const smallScreen = fixture.doc.getElementById('img3'); - const largeScreen = fixture.doc.getElementById('img3_1'); - - expect(smallScreen.className).to.not.match( - /i-amphtml-hidden-by-media-query/ - ); - expect(largeScreen.className).to.match(/i-amphtml-hidden-by-media-query/); - expect(smallScreen.offsetHeight).to.not.equal(0); - expect(largeScreen.offsetHeight).to.equal(0); - expect(smallScreen.querySelector('img')).to.exist; - expect(largeScreen.querySelector('img')).to.not.exist; - - fixture.iframe.width = 600; - fixture.win.dispatchEvent(createCustomEvent(fixture.win, 'resize', null)); - - await largeScreen.whenLoaded(); - - expect(smallScreen.className).to.match(/i-amphtml-hidden-by-media-query/); - expect(largeScreen.className).to.not.match( - /i-amphtml-hidden-by-media-query/ - ); - expect(smallScreen.offsetHeight).to.equal(0); - expect(largeScreen.offsetHeight).to.not.equal(0); - expect(largeScreen.querySelector('img')).to.exist; - }); - - it('should not load image if already present (inabox)', async () => { - await fixture.awaitEvent(AmpEvents.LOAD_START, 3); - - const ampImage = fixture.doc.getElementById('img8'); - expect(ampImage).is.ok; - expect(ampImage.querySelectorAll('img').length).to.equal(1); - }); +describes.sandboxed.configure().run('Rendering of amp-img', {}, () => { + const timeout = window.ampTestRuntimeConfig.mochaTimeout; + + let fixture; + beforeEach(async () => { + fixture = await createFixtureIframe('test/fixtures/images.html', 500); + }); + + it('should show the body in image test', async () => { + await expectBodyToBecomeVisible(fixture.win, timeout); + }); + + it('should be present', async () => { + expect(fixture.doc.querySelectorAll('amp-img')).to.have.length(16); + // 5 image visible in 500 pixel height. Note that there will be no load + // event for the inabox image. + await fixture.awaitEvent(AmpEvents.LOAD_START, 3); + expect(fixture.doc.querySelectorAll('amp-img img[src]')).to.have.length(4); }); -// Move IE tests into its own `describe()` -// so that we can load a different fixture. -describes.sandboxed - .configure() - .enableIe() - .run('Rendering of amp-img', {}, () => { - let fixture; - beforeEach(async () => { - fixture = await createFixtureIframe('test/fixtures/images-ie.html', 500); - }); - - // IE doesn't support the srcset attribute, so if the developer - // provides a srcset but no src to amp-img, it should set the src - // attribute to the first entry in srcset. - describe - .configure() - .ifIe() - .run('srcset support - Internet Explorer edge cases', () => { - it('should guarantee src if srcset is not supported', async () => { - await waitForImageToLoad(fixture.doc, 'img[amp-img-id="srcset"]'); - - const img = fixture.doc.querySelector( - '#srcset img[amp-img-id="srcset"]' - ); - expect(img.getAttribute('src')).to.equal('/examples/img/hero@1x.jpg'); - }); - }); - - // IE can't scale SVG images, so intrinsic sizers use a PNG instead. - describe - .configure() - .enableIe() - .run('intrinsic layout', () => { - it('renders intrinsic layout with correct size', async () => { - await waitForImageToLoad(fixture.doc, 'img[amp-img-id="intrinsic"]'); - - const ampImg = fixture.doc.getElementById('intrinsic'); - const width = parseInt(ampImg.getAttribute('width'), 10); - const height = parseInt(ampImg.getAttribute('height'), 10); - const bounds = ampImg.getBoundingClientRect(); - - expect(bounds.width / bounds.height).to.be.closeTo( - width / height, - 0.001 - ); - }); - }); + it('should resize and load more elements', async () => { + // Note that there will be no load event for the inabox image. + fixture.iframe.height = 1500; + fixture.win.dispatchEvent(createCustomEvent(fixture.win, 'resize', null)); + await fixture.awaitEvent(AmpEvents.LOAD_START, 11); + expect(fixture.doc.querySelectorAll('amp-img img[src]')).to.have.length(12); + + fixture.iframe.height = 2000; + fixture.win.dispatchEvent(createCustomEvent(fixture.win, 'resize', null)); + await fixture.awaitEvent(AmpEvents.LOAD_START, 13); + expect(fixture.doc.querySelectorAll('amp-img img[src]')).to.have.length(14); }); -function waitForImageToLoad(document, selector) { - return poll( - 'wait for img to load', - () => { - const img = document.querySelector(selector); - return img !== null; - }, - () => {}, - 8000 - ); -} + it('should respect media queries', async () => { + await fixture.awaitEvent(AmpEvents.LOAD_START, 3); + await new Promise((res) => setTimeout(res, 1)); + + const smallScreen = fixture.doc.getElementById('img3'); + const largeScreen = fixture.doc.getElementById('img3_1'); + + expect(smallScreen.className).to.not.match( + /i-amphtml-hidden-by-media-query/ + ); + expect(largeScreen.className).to.match(/i-amphtml-hidden-by-media-query/); + expect(smallScreen.offsetHeight).to.not.equal(0); + expect(largeScreen.offsetHeight).to.equal(0); + expect(smallScreen.querySelector('img')).to.exist; + expect(largeScreen.querySelector('img')).to.not.exist; + + fixture.iframe.width = 600; + fixture.win.dispatchEvent(createCustomEvent(fixture.win, 'resize', null)); + + await largeScreen.whenLoaded(); + + expect(smallScreen.className).to.match(/i-amphtml-hidden-by-media-query/); + expect(largeScreen.className).to.not.match( + /i-amphtml-hidden-by-media-query/ + ); + expect(smallScreen.offsetHeight).to.equal(0); + expect(largeScreen.offsetHeight).to.not.equal(0); + expect(largeScreen.querySelector('img')).to.exist; + }); + + it('should not load image if already present (inabox)', async () => { + await fixture.awaitEvent(AmpEvents.LOAD_START, 3); + + const ampImage = fixture.doc.getElementById('img8'); + expect(ampImage).is.ok; + expect(ampImage.querySelectorAll('img').length).to.equal(1); + }); +}); diff --git a/test/integration/test-amp-ad-3p.js b/test/integration/test-amp-ad-3p.js index 3e6ff5260dd5..44d4d267adc8 100644 --- a/test/integration/test-amp-ad-3p.js +++ b/test/integration/test-amp-ad-3p.js @@ -109,7 +109,7 @@ describes.sandboxed('amp-ad 3P', {}, () => { // Nevertheless this only happens in test. In real world AMP will not // in srcdoc iframe. expect(context.sourceUrl).to.equal( - platform.isEdge() || platform.isIe() + platform.isEdge() ? 'http://localhost:9876/context.html' : 'about:srcdoc' ); diff --git a/test/integration/test-amp-ad-doubleclick.js b/test/integration/test-amp-ad-doubleclick.js index 3ba9b7bd3b28..7b280ee5c19e 100644 --- a/test/integration/test-amp-ad-doubleclick.js +++ b/test/integration/test-amp-ad-doubleclick.js @@ -1,182 +1,179 @@ import {createFixtureIframe, poll, pollForLayout} from '#testing/iframe'; -describes.sandboxed - .configure() - .enableIe() - .run('Rendering of one ad', {}, () => { - let fixture; - let beforeHref; +describes.sandboxed.configure().run('Rendering of one ad', {}, () => { + let fixture; + let beforeHref; - function replaceUrl(win) { - const path = '/test/fixtures/doubleclick.html?google_glade=0'; - // We pass down the parent URL. So we change that, which we - // can. We just need to change it back after the test. - beforeHref = win.parent.location.href; - win.parent.history.replaceState(null, null, path); - } + function replaceUrl(win) { + const path = '/test/fixtures/doubleclick.html?google_glade=0'; + // We pass down the parent URL. So we change that, which we + // can. We just need to change it back after the test. + beforeHref = win.parent.location.href; + win.parent.history.replaceState(null, null, path); + } - beforeEach(() => { - return createFixtureIframe( - 'test/fixtures/doubleclick.html', - 3000, - (win) => { - replaceUrl(win); - } - ).then((f) => { - fixture = f; - }); - }); - - afterEach(() => { - if (beforeHref) { - fixture.win.parent.history.replaceState(null, null, beforeHref); + beforeEach(() => { + return createFixtureIframe( + 'test/fixtures/doubleclick.html', + 3000, + (win) => { + replaceUrl(win); } + ).then((f) => { + fixture = f; }); + }); - // TODO(lannka, #3561): unmute the test. - // it.configure().skipEdge().run( - // 'should create an iframe loaded', function() { - it.skip('should create an iframe loaded', function () { - this.timeout(20000); - let iframe; - let ampAd; - const isEdge = navigator.userAgent.match(/Edge/); - return pollForLayout(fixture.win, 1, 5500) - .then(() => { - return poll('frame to be in DOM', () => { - return fixture.doc.querySelector('iframe'); - }); - }) - .then((iframeElement) => { - iframe = iframeElement; - expect(fixture.doc.querySelectorAll('iframe')).to.have.length(1); - ampAd = iframe.parentElement; - expect(iframe.src).to.contain('categoryExclusions'); - expect(iframe.src).to.contain('health'); - expect(iframe.src).to.contain('tagForChildDirectedTreatment'); - expect(iframe.src).to.match( - /http\:\/\/localhost:9876\/base\/dist\.3p\// + afterEach(() => { + if (beforeHref) { + fixture.win.parent.history.replaceState(null, null, beforeHref); + } + }); + + // TODO(lannka, #3561): unmute the test. + // it.configure().skipEdge().run( + // 'should create an iframe loaded', function() { + it.skip('should create an iframe loaded', function () { + this.timeout(20000); + let iframe; + let ampAd; + const isEdge = navigator.userAgent.match(/Edge/); + return pollForLayout(fixture.win, 1, 5500) + .then(() => { + return poll('frame to be in DOM', () => { + return fixture.doc.querySelector('iframe'); + }); + }) + .then((iframeElement) => { + iframe = iframeElement; + expect(fixture.doc.querySelectorAll('iframe')).to.have.length(1); + ampAd = iframe.parentElement; + expect(iframe.src).to.contain('categoryExclusions'); + expect(iframe.src).to.contain('health'); + expect(iframe.src).to.contain('tagForChildDirectedTreatment'); + expect(iframe.src).to.match( + /http\:\/\/localhost:9876\/base\/dist\.3p\// + ); + }) + .then(() => { + return poll('frame to load', () => { + return ( + iframe.contentWindow && + iframe.contentWindow.document && + iframe.contentWindow.document.getElementById('c') ); - }) - .then(() => { - return poll('frame to load', () => { - return ( - iframe.contentWindow && - iframe.contentWindow.document && - iframe.contentWindow.document.getElementById('c') - ); - }); - }) - .then((unusedCanvas) => { - return poll('3p JS to load.', () => iframe.contentWindow.context); - }) - .then((context) => { - expect(context.hidden).to.be.false; - // In some browsers the referrer is empty. But in Chrome it works, so - // we always check there. - if ( - context.referrer !== '' || - (navigator.userAgent.match(/Chrome/) && !isEdge) - ) { - expect(context.referrer).to.contain( - 'http://localhost:' + location.port - ); - } - expect(context.pageViewId).to.be.greaterThan(0); - expect(context.initialLayoutRect).to.exist; - expect(context.initialLayoutRect.top).to.exist; - expect(context.initialIntersection).to.exist; - expect(context.initialIntersection.rootBounds).to.exist; - expect(context.data.tagForChildDirectedTreatment).to.equal(0); - expect(context.data.categoryExclusions).to.be.jsonEqual(['health']); - expect(context.data.targeting).to.be.jsonEqual({'amptest': 'true'}); - return poll( - 'main ad JS is injected', - () => { - return iframe.contentWindow.document.querySelector( - 'script[src="https://www.googletagservices.com/tag/js/gpt.js"]' - ); - }, - undefined, - /* timeout */ 5000 + }); + }) + .then((unusedCanvas) => { + return poll('3p JS to load.', () => iframe.contentWindow.context); + }) + .then((context) => { + expect(context.hidden).to.be.false; + // In some browsers the referrer is empty. But in Chrome it works, so + // we always check there. + if ( + context.referrer !== '' || + (navigator.userAgent.match(/Chrome/) && !isEdge) + ) { + expect(context.referrer).to.contain( + 'http://localhost:' + location.port ); - }) - .then(() => { - return poll('render-start message received', () => { - return fixture.messages.filter((message) => { - return message.type == 'render-start'; - }).length; - }); - }) - .then(() => { - expect(iframe.style.visibility).to.equal(''); - const win = iframe.contentWindow; - return poll('GPT loaded', () => { - return ( - win.googletag && win.googletag.pubads && win.googletag.pubads() + } + expect(context.pageViewId).to.be.greaterThan(0); + expect(context.initialLayoutRect).to.exist; + expect(context.initialLayoutRect.top).to.exist; + expect(context.initialIntersection).to.exist; + expect(context.initialIntersection.rootBounds).to.exist; + expect(context.data.tagForChildDirectedTreatment).to.equal(0); + expect(context.data.categoryExclusions).to.be.jsonEqual(['health']); + expect(context.data.targeting).to.be.jsonEqual({'amptest': 'true'}); + return poll( + 'main ad JS is injected', + () => { + return iframe.contentWindow.document.querySelector( + 'script[src="https://www.googletagservices.com/tag/js/gpt.js"]' ); - }); - }) - .then((pubads) => { - const canvas = iframe.contentWindow.document.querySelector('#c'); - expect(pubads.get('page_url')).to.equal( - 'https://www.example.com/doubleclick.html' - ); - const {slot} = canvas; - expect(slot).to.not.be.null; - expect(slot.getCategoryExclusions()).to.jsonEqual(['health']); - expect(slot.getTargeting('amptest')).to.jsonEqual(['true']); - return poll( - 'ad iframe to be initialized. Means that an actual ad was loaded.', - () => { - return canvas.querySelector( - '[id="google_ads_iframe_/35096353/amptesting/kv_0"]' - ); - }, - null, - 5000 + }, + undefined, + /* timeout */ 5000 + ); + }) + .then(() => { + return poll('render-start message received', () => { + return fixture.messages.filter((message) => { + return message.type == 'render-start'; + }).length; + }); + }) + .then(() => { + expect(iframe.style.visibility).to.equal(''); + const win = iframe.contentWindow; + return poll('GPT loaded', () => { + return ( + win.googletag && win.googletag.pubads && win.googletag.pubads() ); - }) - .then(() => { - expect(iframe.contentWindow.context.hidden).to.be.false; - return new Promise((resolve) => { - // Listening to the "amp:visibilitychange" string literal because it's - // part of the public API. - // https://github.com/ampproject/amphtml/blob/main/ads/README.md#page-visibility - iframe.contentWindow.addEventListener( - 'amp:visibilitychange', - resolve + }); + }) + .then((pubads) => { + const canvas = iframe.contentWindow.document.querySelector('#c'); + expect(pubads.get('page_url')).to.equal( + 'https://www.example.com/doubleclick.html' + ); + const {slot} = canvas; + expect(slot).to.not.be.null; + expect(slot.getCategoryExclusions()).to.jsonEqual(['health']); + expect(slot.getTargeting('amptest')).to.jsonEqual(['true']); + return poll( + 'ad iframe to be initialized. Means that an actual ad was loaded.', + () => { + return canvas.querySelector( + '[id="google_ads_iframe_/35096353/amptesting/kv_0"]' ); - fixture.win.AMP.viewer.receiveMessage('visibilitychange', { - state: 'hidden', - }); - fixture.win.AMP.viewer.receiveMessage('visibilitychange', { - state: 'visible', - }); - }); - }) - .then(() => { - expect(iframe.getAttribute('width')).to.equal('300'); - expect(iframe.getAttribute('height')).to.equal('250'); - if (isEdge) { - // TODO(cramforce): Get this to pass in Edge - return; - } - return poll( - 'Creative id transmitted. Ad fully rendered.', - () => { - return ampAd.creativeId; - }, - null, - 15000 + }, + null, + 5000 + ); + }) + .then(() => { + expect(iframe.contentWindow.context.hidden).to.be.false; + return new Promise((resolve) => { + // Listening to the "amp:visibilitychange" string literal because it's + // part of the public API. + // https://github.com/ampproject/amphtml/blob/main/ads/README.md#page-visibility + iframe.contentWindow.addEventListener( + 'amp:visibilitychange', + resolve ); - }) - .then((creativeId) => { - if (isEdge) { - // TODO(cramforce): Get this to pass in Edge - return; - } - expect(creativeId).to.match(/^dfp-/); + fixture.win.AMP.viewer.receiveMessage('visibilitychange', { + state: 'hidden', + }); + fixture.win.AMP.viewer.receiveMessage('visibilitychange', { + state: 'visible', + }); }); - }); + }) + .then(() => { + expect(iframe.getAttribute('width')).to.equal('300'); + expect(iframe.getAttribute('height')).to.equal('250'); + if (isEdge) { + // TODO(cramforce): Get this to pass in Edge + return; + } + return poll( + 'Creative id transmitted. Ad fully rendered.', + () => { + return ampAd.creativeId; + }, + null, + 15000 + ); + }) + .then((creativeId) => { + if (isEdge) { + // TODO(cramforce): Get this to pass in Edge + return; + } + expect(creativeId).to.match(/^dfp-/); + }); }); +}); diff --git a/test/integration/test-shadow-dom-element.js b/test/integration/test-shadow-dom-element.js index a6683a993d2b..cd8b592ff253 100644 --- a/test/integration/test-shadow-dom-element.js +++ b/test/integration/test-shadow-dom-element.js @@ -6,7 +6,6 @@ import {createFixtureIframe} from '#testing/iframe'; describes.sandboxed .configure() - .enableIe() .run('Render a shadow-dom based element', {}, () => { let fixture; diff --git a/test/integration/test-toggle-display.js b/test/integration/test-toggle-display.js index d2b408867a0a..9445a3992f5d 100644 --- a/test/integration/test-toggle-display.js +++ b/test/integration/test-toggle-display.js @@ -2,49 +2,46 @@ import {setInitialDisplay, toggle} from '#core/dom/style'; import {BrowserController} from '#testing/test-helper'; -describes.integration - .configure() - .enableIe() - .run( - 'toggle display helper', - { - body: '', - }, - (env) => { - let browser, doc; - let img; - - beforeEach(async () => { - const {win} = env; - doc = win.document; - browser = new BrowserController(win); - - await browser.waitForElementLayout('amp-img'); - img = doc.querySelector('amp-img'); - }); - - function expectToggleDisplay(el) { - toggle(el, false); - expect(el).to.have.display('none'); - toggle(el, true); - expect(el).to.not.have.display('none'); - } - - it('toggles regular display', () => { - expectToggleDisplay(img); - }); - - it('toggles initial display style', () => { - setInitialDisplay(img, 'inline-block'); - expectToggleDisplay(img); - }); - - it('toggles stylesheet display style', () => { - const style = doc.createElement('style'); - style.innerText = 'amp-img { display: inline-block !important; }'; - doc.head.appendChild(style); - - expectToggleDisplay(img); - }); +describes.integration.configure().run( + 'toggle display helper', + { + body: '', + }, + (env) => { + let browser, doc; + let img; + + beforeEach(async () => { + const {win} = env; + doc = win.document; + browser = new BrowserController(win); + + await browser.waitForElementLayout('amp-img'); + img = doc.querySelector('amp-img'); + }); + + function expectToggleDisplay(el) { + toggle(el, false); + expect(el).to.have.display('none'); + toggle(el, true); + expect(el).to.not.have.display('none'); } - ); + + it('toggles regular display', () => { + expectToggleDisplay(img); + }); + + it('toggles initial display style', () => { + setInitialDisplay(img, 'inline-block'); + expectToggleDisplay(img); + }); + + it('toggles stylesheet display style', () => { + const style = doc.createElement('style'); + style.innerText = 'amp-img { display: inline-block !important; }'; + doc.head.appendChild(style); + + expectToggleDisplay(img); + }); + } +); diff --git a/test/unit/core/dom/layout/test-layout.js b/test/unit/core/dom/layout/test-layout.js index 06cb5fdc9be2..41267bd72a13 100644 --- a/test/unit/core/dom/layout/test-layout.js +++ b/test/unit/core/dom/layout/test-layout.js @@ -648,39 +648,36 @@ describes.realWin('ampshared.css', {amp: true}, function (env) { doc.body.appendChild(element); }); - describe - .configure() - .enableIe() - .run('overflow', function () { - let overflow; - - beforeEach(() => { - overflow = doc.createElement('div'); - overflow.setAttribute('overflow', ''); - overflow.style.height = '20px'; - element.appendChild(overflow); - }); - - it('should not allow overflow element to distort a size-defined layout', () => { - element.setAttribute('layout', 'responsive'); - element.setAttribute('width', 100); - element.setAttribute('height', 100); - expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); - - expect(element.offsetWidth).to.equal(element.offsetHeight); - expect(overflow.offsetHeight).to.equal(20); - expect(win.getComputedStyle(overflow).position).to.equal('absolute'); - }); - - it('should allow overflow element to distort container layout', () => { - element.setAttribute('layout', 'container'); - overflow.text = 'test'; - expect(applyStaticLayout(element)).to.equal(Layout.CONTAINER); - - expect(element.offsetHeight).to.equal(overflow.offsetHeight); - expect(win.getComputedStyle(overflow).position).to.equal('relative'); - }); + describe('overflow', function () { + let overflow; + + beforeEach(() => { + overflow = doc.createElement('div'); + overflow.setAttribute('overflow', ''); + overflow.style.height = '20px'; + element.appendChild(overflow); }); + + it('should not allow overflow element to distort a size-defined layout', () => { + element.setAttribute('layout', 'responsive'); + element.setAttribute('width', 100); + element.setAttribute('height', 100); + expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); + + expect(element.offsetWidth).to.equal(element.offsetHeight); + expect(overflow.offsetHeight).to.equal(20); + expect(win.getComputedStyle(overflow).position).to.equal('absolute'); + }); + + it('should allow overflow element to distort container layout', () => { + element.setAttribute('layout', 'container'); + overflow.text = 'test'; + expect(applyStaticLayout(element)).to.equal(Layout.CONTAINER); + + expect(element.offsetHeight).to.equal(overflow.offsetHeight); + expect(win.getComputedStyle(overflow).position).to.equal('relative'); + }); + }); }); describes.realWin('Layout: aspect-ratio CSS', {amp: true}, function (env) { @@ -706,73 +703,67 @@ describes.realWin('Layout: aspect-ratio CSS', {amp: true}, function (env) { resetShouldUseAspectRatioCssForTesting(); }); - describe - .configure() - .enableIe() - .run('aspect-ratio not supported', function () { - before(function () { - if (CSS.supports('aspect-ratio: 1/1')) { - this.skipTest(); - } - }); - - it('should apply legacy layout for layout=responsive', () => { - element.setAttribute('layout', 'responsive'); - element.setAttribute('width', 100); - element.setAttribute('height', 200); - expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); - expect(element.style.aspectRatio).to.not.be.ok; - expect(element.style.width).to.equal(''); - expect(element.style.height).to.equal(''); - expect(element).to.have.class('i-amphtml-layout-responsive'); - expect(element).to.have.class('i-amphtml-layout-size-defined'); - // Sizer has been added. - const sizer = element.querySelector('i-amphtml-sizer'); - expect(sizer).to.be.ok; - expect(getComputedStyle(sizer).display).to.equal('block'); - }); - - it('should pass through SSR sizer for responsive layout', () => { - element.setAttribute('i-amphtml-layout', 'responsive'); - element.appendChild(ssrSizer); - expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); - expect(element.sizerElement).to.equal(ssrSizer); - expect(ssrSizer.getAttribute('slot')).to.equal('i-amphtml-svc'); - expect(getComputedStyle(ssrSizer).display).to.equal('block'); - }); + describe('aspect-ratio not supported', function () { + before(function () { + if (CSS.supports('aspect-ratio: 1/1')) { + this.skipTest(); + } + }); + + it('should apply legacy layout for layout=responsive', () => { + element.setAttribute('layout', 'responsive'); + element.setAttribute('width', 100); + element.setAttribute('height', 200); + expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); + expect(element.style.aspectRatio).to.not.be.ok; + expect(element.style.width).to.equal(''); + expect(element.style.height).to.equal(''); + expect(element).to.have.class('i-amphtml-layout-responsive'); + expect(element).to.have.class('i-amphtml-layout-size-defined'); + // Sizer has been added. + const sizer = element.querySelector('i-amphtml-sizer'); + expect(sizer).to.be.ok; + expect(getComputedStyle(sizer).display).to.equal('block'); }); - describe - .configure() - .enableIe() - .run('aspect-ratio supported', function () { - before(function () { - if (!CSS.supports('aspect-ratio: 1/1')) { - this.skipTest(); - } - }); - - it('should apply layout=responsive via aspect-ratio', () => { - element.setAttribute('layout', 'responsive'); - element.setAttribute('width', 100); - element.setAttribute('height', 200); - expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); - expect(element.style.aspectRatio).to.equal('100 / 200'); - expect(element.style.width).to.equal(''); - expect(element.style.height).to.equal(''); - expect(element).to.have.class('i-amphtml-layout-responsive'); - expect(element).to.have.class('i-amphtml-layout-size-defined'); - // No sizer added. - expect(element.querySelector('i-amphtml-sizer')).to.be.null; - }); - - it('should disable SSR sizer for responsive layout', () => { - element.setAttribute('i-amphtml-layout', 'responsive'); - element.appendChild(ssrSizer); - expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); - expect(element.sizerElement).to.equal(ssrSizer); - expect(ssrSizer.getAttribute('slot')).to.equal('i-amphtml-svc'); - expect(getComputedStyle(ssrSizer).display).to.equal('none'); - }); + it('should pass through SSR sizer for responsive layout', () => { + element.setAttribute('i-amphtml-layout', 'responsive'); + element.appendChild(ssrSizer); + expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); + expect(element.sizerElement).to.equal(ssrSizer); + expect(ssrSizer.getAttribute('slot')).to.equal('i-amphtml-svc'); + expect(getComputedStyle(ssrSizer).display).to.equal('block'); }); + }); + + describe('aspect-ratio supported', function () { + before(function () { + if (!CSS.supports('aspect-ratio: 1/1')) { + this.skipTest(); + } + }); + + it('should apply layout=responsive via aspect-ratio', () => { + element.setAttribute('layout', 'responsive'); + element.setAttribute('width', 100); + element.setAttribute('height', 200); + expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); + expect(element.style.aspectRatio).to.equal('100 / 200'); + expect(element.style.width).to.equal(''); + expect(element.style.height).to.equal(''); + expect(element).to.have.class('i-amphtml-layout-responsive'); + expect(element).to.have.class('i-amphtml-layout-size-defined'); + // No sizer added. + expect(element.querySelector('i-amphtml-sizer')).to.be.null; + }); + + it('should disable SSR sizer for responsive layout', () => { + element.setAttribute('i-amphtml-layout', 'responsive'); + element.appendChild(ssrSizer); + expect(applyStaticLayout(element)).to.equal(Layout.RESPONSIVE); + expect(element.sizerElement).to.equal(ssrSizer); + expect(ssrSizer.getAttribute('slot')).to.equal('i-amphtml-svc'); + expect(getComputedStyle(ssrSizer).display).to.equal('none'); + }); + }); }); diff --git a/test/unit/polyfills/test-domtokenlist-toggle.js b/test/unit/polyfills/test-domtokenlist-toggle.js deleted file mode 100644 index 28f0d1cfc2a2..000000000000 --- a/test/unit/polyfills/test-domtokenlist-toggle.js +++ /dev/null @@ -1,128 +0,0 @@ -import {toArray} from '#core/types/array'; - -import {install} from '#polyfills/domtokenlist'; - -describes.fakeWin( - 'DOMTokenList.toggle/add on non-IE', - { - win: { - navigator: { - userAgent: 'Chrome', - }, - }, - }, - (env) => { - let originalToggle; - let originalAdd; - let element; - - beforeEach(() => { - originalToggle = env.win.DOMTokenList.prototype.toggle; - originalAdd = env.win.DOMTokenList.prototype.add; - - element = env.win.document.createElement('div'); - env.win.document.body.appendChild(element); - }); - - afterEach(() => { - env.win.DOMTokenList.prototype.toggle = originalToggle; - env.win.DOMTokenList.prototype.add = originalAdd; - if (element.parentNode) { - element.parentNode.removeChild(element); - } - }); - - it('should NOT override toggle in non-IE browsers', () => { - env.win.DOMTokenList = window.DOMTokenList; - install(env.win); - const newToggle = env.win.DOMTokenList.prototype.toggle; - expect(newToggle).to.equal(originalToggle); - }); - - it('should NOT override add in non-IE browsers', () => { - env.win.DOMTokenList = window.DOMTokenList; - install(env.win); - const newAdd = env.win.DOMTokenList.prototype.add; - expect(newAdd).to.equal(originalAdd); - }); - } -); - -describes.fakeWin( - 'DOMTokenList.toggle/add On IE', - { - win: { - navigator: { - userAgent: 'MSIE', - }, - }, - }, - (env) => { - let originalToggle; - let originalAdd; - let element; - - beforeEach(() => { - originalToggle = env.win.DOMTokenList.prototype.toggle; - originalAdd = env.win.DOMTokenList.prototype.add; - - element = env.win.document.createElement('div'); - env.win.document.body.appendChild(element); - }); - - afterEach(() => { - env.win.DOMTokenList.prototype.toggle = originalToggle; - env.win.DOMTokenList.prototype.add = originalAdd; - if (element.parentNode) { - element.parentNode.removeChild(element); - } - }); - - it('should polyfill DOMTokenList.toggle API', () => { - env.win.DOMTokenList = window.DOMTokenList; - install(env.win); - const polyfillToggle = env.win.DOMTokenList.prototype.toggle; - - expect(polyfillToggle).to.be.ok; - expect(polyfillToggle).to.not.equal(originalToggle); - - expect(toArray(element.classList)).to.not.contain('first'); - expect(polyfillToggle.call(element.classList, 'first')).to.be.true; - expect(toArray(element.classList)).to.contain('first'); - expect(polyfillToggle.call(element.classList, 'first')).to.be.false; - expect(toArray(element.classList)).to.not.contain('first'); - expect(polyfillToggle.call(element.classList, 'first')).to.be.true; - expect(toArray(element.classList)).to.contain('first'); - expect(polyfillToggle.call(element.classList, 'first', true)).to.be.true; - expect(toArray(element.classList)).to.contain('first'); - expect(polyfillToggle.call(element.classList, 'first', true)).to.be.true; - expect(toArray(element.classList)).to.contain('first'); - expect(polyfillToggle.call(element.classList, 'first', false)).to.be - .false; - expect(toArray(element.classList)).to.not.contain('first'); - expect(polyfillToggle.call(element.classList, 'first', false)).to.be - .false; - expect(toArray(element.classList)).to.not.contain('first'); - expect(polyfillToggle.call(element.classList, 'first', false)).to.be - .false; - expect(toArray(element.classList)).to.not.contain('first'); - }); - - it('should polyfill DOMTokenList.add API', () => { - env.win.DOMTokenList = window.DOMTokenList; - install(env.win); - const polyfillAdd = env.win.DOMTokenList.prototype.add; - - expect(polyfillAdd).to.be.ok; - expect(polyfillAdd).to.not.equal(originalToggle); - - element.classList.add('foo'); - expect(toArray(element.classList)).to.contain('foo'); - element.classList.add('one', 'two', 'three'); - expect(toArray(element.classList)).to.contain('foo'); - expect(toArray(element.classList)).to.contain('one'); - expect(toArray(element.classList)).to.contain('two'); - expect(toArray(element.classList)).to.contain('three'); - }); - } -); diff --git a/test/unit/test-ie-media-bug.js b/test/unit/test-ie-media-bug.js deleted file mode 100644 index 31ed18a5355c..000000000000 --- a/test/unit/test-ie-media-bug.js +++ /dev/null @@ -1,176 +0,0 @@ -import {ieMediaCheckAndFix} from '#service/ie-media-bug'; - -import {dev} from '../../src/log'; - -describes.sandboxed('ie-media-bug', {}, (env) => { - let clock; - let windowApi, windowMock; - let platform; - let platformMock; - let devErrorStub; - - beforeEach(() => { - clock = env.sandbox.useFakeTimers(); - platform = { - isIe: () => false, - }; - platformMock = env.sandbox.mock(platform); - devErrorStub = env.sandbox.stub(dev(), 'error'); - - windowApi = { - innerWidth: 320, - setInterval: () => {}, - clearInterval: () => {}, - matchMedia: () => {}, - }; - windowMock = env.sandbox.mock(windowApi); - }); - - afterEach(() => { - platformMock.verify(); - windowMock.verify(); - }); - - it('should bypass polling for non-IE browsers', () => { - platformMock.expects('isIe').returns(false); - windowMock.expects('matchMedia').never(); - windowMock.expects('setInterval').never(); - const promise = ieMediaCheckAndFix(windowApi, platform); - expect(promise).to.be.null; - expect(devErrorStub).to.have.not.been.called; - }); - - it('should bypass polling when matchMedia is not broken', () => { - platformMock.expects('isIe').returns(true); - windowMock - .expects('matchMedia') - .withExactArgs('(min-width: 319px) AND (max-width: 321px)') - .returns({matches: true}) - .once(); - windowMock.expects('setInterval').never(); - const promise = ieMediaCheckAndFix(windowApi, platform); - expect(promise).to.be.null; - expect(devErrorStub).to.have.not.been.called; - }); - - it('should poll when matchMedia is wrong, but eventually succeeds', () => { - platformMock.expects('isIe').returns(true); - - // Scheduling pass. - windowMock - .expects('matchMedia') - .withExactArgs('(min-width: 319px) AND (max-width: 321px)') - .returns({matches: false}) - .once(); - const intervalId = 111; - let intervalCallback; - windowMock - .expects('setInterval') - .withExactArgs( - env.sandbox.match((arg) => { - intervalCallback = arg; - return true; - }), - 10 - ) - .returns(intervalId) - .once(); - - const promise = ieMediaCheckAndFix(windowApi, platform); - expect(promise).to.be.not.null; - expect(devErrorStub).to.have.not.been.called; - expect(intervalCallback).to.exist; - windowMock.verify(); - windowMock./*OK*/ restore(); - - // Second pass. - clock.tick(10); - windowMock = env.sandbox.mock(windowApi); - windowMock - .expects('matchMedia') - .withExactArgs('(min-width: 319px) AND (max-width: 321px)') - .returns({matches: false}) - .once(); - windowMock.expects('clearInterval').never(); - intervalCallback(); - expect(devErrorStub).to.have.not.been.called; - windowMock.verify(); - windowMock./*OK*/ restore(); - - // Third pass - succeed. - clock.tick(10); - windowMock = env.sandbox.mock(windowApi); - windowMock - .expects('matchMedia') - .withExactArgs('(min-width: 319px) AND (max-width: 321px)') - .returns({matches: true}) - .once(); - windowMock.expects('clearInterval').withExactArgs(intervalId).once(); - intervalCallback(); - windowMock.verify(); - windowMock./*OK*/ restore(); - - return promise.then(() => { - expect(devErrorStub).to.have.not.been.called; - }); - }); - - it('should poll until times out', () => { - platformMock.expects('isIe').returns(true); - - // Scheduling pass. - windowMock - .expects('matchMedia') - .withExactArgs('(min-width: 319px) AND (max-width: 321px)') - .returns({matches: false}) - .atLeast(2); - const intervalId = 111; - let intervalCallback; - windowMock - .expects('setInterval') - .withExactArgs( - env.sandbox.match((arg) => { - intervalCallback = arg; - return true; - }), - 10 - ) - .returns(intervalId) - .once(); - windowMock.expects('clearInterval').withExactArgs(intervalId).once(); - - const promise = ieMediaCheckAndFix(windowApi, platform); - expect(promise).to.be.not.null; - expect(devErrorStub).to.have.not.been.called; - expect(intervalCallback).to.exist; - - // Second pass. - clock.tick(10); - intervalCallback(); - expect(devErrorStub).to.have.not.been.called; - - // Third pass - timeout. - clock.tick(2000); - intervalCallback(); - expect(devErrorStub).to.be.calledOnce; - - return promise.then(() => { - expect(devErrorStub).to.be.calledOnce; - }); - }); - - it('should tolerate matchMedia exceptions', () => { - platformMock.expects('isIe').returns(true); - - windowMock - .expects('matchMedia') - .withExactArgs('(min-width: 319px) AND (max-width: 321px)') - .throws(new Error('intentional')) - .once(); - windowMock.expects('setInterval').never(); - - const promise = ieMediaCheckAndFix(windowApi, platform); - expect(promise).to.be.null; - expect(devErrorStub).to.be.calledOnce; - }); -}); diff --git a/test/unit/test-mutator.js b/test/unit/test-mutator.js index 5231973ef707..999aec78816e 100644 --- a/test/unit/test-mutator.js +++ b/test/unit/test-mutator.js @@ -5,10 +5,8 @@ import {Signals} from '#core/data-structures/signals'; import {LayoutPriority} from '#core/dom/layout'; import {layoutRectLtwh} from '#core/dom/layout/rect'; -import {Services} from '#service'; import {AmpDocSingle} from '#service/ampdoc-impl'; import {MutatorImpl} from '#service/mutator-impl'; -import {installPlatformService} from '#service/platform-impl'; import {Resource, ResourceState} from '#service/resource'; import {ResourcesImpl} from '#service/resources-impl'; @@ -48,10 +46,6 @@ describes.realWin('mutator changeSize', {amp: true}, (env) => { mutator.win = resources.win; mutator.resources_ = resources; - installPlatformService(resources.win); - const platform = Services.platformFor(resources.win); - env.sandbox.stub(platform, 'isIe').returns(false); - installInputService(resources.win); viewportMock = env.sandbox.mock(mutator.viewport_); diff --git a/test/unit/test-platform.js b/test/unit/test-platform.js index 20bb0762b628..629f30dda034 100644 --- a/test/unit/test-platform.js +++ b/test/unit/test-platform.js @@ -7,7 +7,6 @@ describes.sandboxed('Platform', {}, (env) => { let isSafari; let isFirefox; let isOpera; - let isIe; let isEdge; let isWebKit; let isStandalone; @@ -23,7 +22,6 @@ describes.sandboxed('Platform', {}, (env) => { isSafari = false; isFirefox = false; isOpera = false; - isIe = false; isEdge = false; isWebKit = false; isStandalone = false; @@ -41,7 +39,6 @@ describes.sandboxed('Platform', {}, (env) => { expect(platform.isSafari()).to.equal(isSafari); expect(platform.isFirefox()).to.equal(isFirefox); expect(platform.isOpera()).to.equal(isOpera); - expect(platform.isIe()).to.equal(isIe); expect(platform.isEdge()).to.equal(isEdge); expect(platform.isWebKit()).to.equal(isWebKit); expect(platform.getMajorVersion()).to.equal(majorVersion); @@ -272,26 +269,6 @@ describes.sandboxed('Platform', {}, (env) => { testStandalone(userAgent, isStandalone); }); - it('IE', () => { - isIe = true; - majorVersion = 10; - userAgent = - 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 7.0;' + - ' InfoPath.3; .NET CLR 3.1.40767; Trident/6.0; en-IN)'; - testUserAgent(userAgent); - testStandalone(userAgent, isStandalone); - }); - - it('IEMobile', () => { - isIe = true; - majorVersion = 10; - userAgent = - 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0;' + - ' Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)'; - testUserAgent(userAgent); - testStandalone(userAgent, isStandalone); - }); - it('Edge', () => { isEdge = true; majorVersion = 12; diff --git a/testing/test-config.js b/testing/test-config.js index c287efb639b1..bb6660b4d525 100644 --- a/testing/test-config.js +++ b/testing/test-config.js @@ -7,7 +7,7 @@ import {Services} from '#service'; * using describes.configure(), describe.configure(), or it.configure(). * * Example usage: - * 1. describes.configure().skipChrome().enableIe().run(name, spec, function); + * 1. describes.configure().skipChrome().run(name, spec, function); * 2. describe.configure().skipFirefox().skipSafari().run(name, function); * 3. it.configure().skipEdge().run(name, function); */ @@ -43,12 +43,11 @@ export class TestConfig { this.runOnFirefox = this.platform.isFirefox.bind(this.platform); this.runOnSafari = this.platform.isSafari.bind(this.platform); this.runOnIos = this.platform.isIos.bind(this.platform); - this.runOnIe = this.platform.isIe.bind(this.platform); /** * By default, IE is skipped. Individual tests may opt in. */ - this.skip(this.runOnIe); + this.skip(() => /Trident|MSIE|IEMobile/i.test(window.navigator.userAgent)); } skipModuleBuild() { @@ -76,14 +75,7 @@ export class TestConfig { } skipIfPropertiesObfuscated() { - return this.skip(function () { - return window.__karma__.config.amp.propertiesObfuscated; - }); - } - - enableIe() { - this.skipMatchers.splice(this.skipMatchers.indexOf(this.runOnIe), 1); - return this; + return this.skip(() => window.__karma__.config.amp.propertiesObfuscated); } /** @@ -118,11 +110,6 @@ export class TestConfig { return this.if(this.runOnIos); } - ifIe() { - // It's necessary to first enable IE because we skip it by default. - return this.enableIe().if(this.runOnIe); - } - /** * @param {function():boolean} fn */