diff --git a/src/internal/analytics-metadata/__integ__/page-scanner-utils-iframes.test.ts b/src/internal/analytics-metadata/__integ__/page-scanner-utils-iframes.test.ts new file mode 100644 index 0000000..e1bb703 --- /dev/null +++ b/src/internal/analytics-metadata/__integ__/page-scanner-utils-iframes.test.ts @@ -0,0 +1,72 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import useBrowser from '@cloudscape-design/browser-test-tools/use-browser'; +import { BasePageObject } from '@cloudscape-design/browser-test-tools/page-objects'; +import { Browser } from 'webdriverio'; +import { getComponentsTree } from '../page-scanner-utils'; + +// Extend the Window interface to include the getComponentsTree property +declare global { + interface Window { + getComponentsTree: typeof getComponentsTree; + } +} + +describe('getComponentsTree', () => { + const setupTest = (testFn: (page: BasePageObject, browser: Browser) => Promise) => { + return useBrowser(async browser => { + const page = new BasePageObject(browser); + await browser.url('/with-iframe'); + await testFn(page, browser); + }); + }; + + test( + 'gets component metadata, including iframes', + setupTest(async (page, browser) => { + await page.runInsideIframe('#iframe-1', true, async () => { + await page.runInsideIframe('#iframe-2', true, async () => { + await page.waitForVisible('#sub-sub-target'); + }); + }); + const tree = await browser.execute(() => { + return window.getComponentsTree(); + }); + expect(tree).toEqual([ + { + name: 'ComponentOne', + children: [ + { + name: 'ComponentTwo', + children: [ + { name: 'ComponentTwoInPortal' }, + { name: 'ComponentThree', children: [{ name: 'ComponentThreeInPortal' }] }, + ], + }, + ], + }, + ]); + }) + ); + test( + 'gets component metadata of sub-tree inside an iframe', + setupTest(async (page, browser) => { + await page.runInsideIframe('#iframe-1', true, async () => { + await page.runInsideIframe('#iframe-2', true, async () => { + await page.waitForVisible('#sub-sub-target'); + }); + }); + const tree = await browser.execute(() => { + const iframe = document.querySelector('#iframe-1') as HTMLIFrameElement; + const iframeDocument = iframe!.contentDocument; + const subTarget = iframeDocument!.querySelector('#sub-target') as HTMLElement; + return window.getComponentsTree(subTarget); + }); + expect(tree).toEqual([ + { name: 'ComponentTwoInPortal' }, + { name: 'ComponentThree', children: [{ name: 'ComponentThreeInPortal' }] }, + ]); + }) + ); +}); diff --git a/src/internal/analytics-metadata/__tests__/components.tsx b/src/internal/analytics-metadata/__tests__/components.tsx index ad371cc..6f8e523 100644 --- a/src/internal/analytics-metadata/__tests__/components.tsx +++ b/src/internal/analytics-metadata/__tests__/components.tsx @@ -1,8 +1,9 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import React, { ReactNode } from 'react'; +import React, { ReactNode, useEffect, useRef } from 'react'; import { METADATA_ATTRIBUTE, getAnalyticsMetadataAttribute, getAnalyticsLabelAttribute } from '../attributes'; +import ReactDOM from 'react-dom'; export const ComponentOne = ({ malformed }: { malformed?: boolean }) => (
(
); + +const NestedIframe = () => { + const ref = useRef(null); + + useEffect(() => { + const container = ref.current; + if (!container) { + return; + } + const iframeEl = container.ownerDocument.createElement('iframe'); + iframeEl.id = 'iframe-2'; + container.appendChild(iframeEl); + + const iframeDocument = iframeEl.contentDocument!; + iframeDocument.open(); + iframeDocument.writeln(''); + iframeDocument.close(); + iframeDocument.body.innerHTML = + '
inside iframe inside iframe
'; + + return () => { + container.removeChild(iframeEl); + }; + }); + + return ( + <> +

Nested title

+
+
inside iframe
+
+
;
+
+
+
+
+
+ + ); +}; + +export const AppWithIframe = () => { + const ref = useRef(null); + + useEffect(() => { + const container = ref.current; + if (!container) { + return; + } + const iframeEl = container.ownerDocument.createElement('iframe'); + iframeEl.id = 'iframe-1'; + container.appendChild(iframeEl); + + const iframeDocument = iframeEl.contentDocument!; + iframeDocument.open(); + iframeDocument.writeln(''); + iframeDocument.close(); + + const innerAppRoot = iframeDocument.createElement('div'); + iframeDocument.body.appendChild(innerAppRoot); + ReactDOM.render(, innerAppRoot); + return () => { + ReactDOM.unmountComponentAtNode(innerAppRoot); + container.removeChild(iframeEl); + }; + }); + + return ( +
+

Main title

+
; +