Skip to content

Commit b78eee1

Browse files
authored
fix: Support cross-frame rendering in missing styles check (#3735)
1 parent c4f6133 commit b78eee1

File tree

4 files changed

+65
-19
lines changed

4 files changed

+65
-19
lines changed

src/internal/hooks/use-base-component/__tests__/styles-check-hook.test.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
import React from 'react';
3+
import React, { useRef } from 'react';
44
import { render, waitFor } from '@testing-library/react';
55

66
import { useMissingStylesCheck } from '../../../../../lib/components/internal/hooks/use-base-component/styles-check';
77

88
function Test() {
9-
useMissingStylesCheck();
10-
return null;
9+
const ref = useRef<HTMLDivElement>(null);
10+
useMissingStylesCheck(ref);
11+
return <div></div>;
1112
}
1213

1314
let consoleMock: jest.SpyInstance;

src/internal/hooks/use-base-component/__tests__/styles-check-pure.test.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ describe('checkMissingStyles', () => {
3535
--awsui-version-info-${GIT_SHA}: true;
3636
}
3737
`;
38-
checkMissingStyles();
38+
checkMissingStyles(document);
3939
expect(consoleWarnSpy).not.toHaveBeenCalled();
4040
expect(sendPanoramaMetricSpy).not.toHaveBeenCalled();
4141
});
4242

4343
test('should detect missing styles', () => {
44-
checkMissingStyles();
44+
checkMissingStyles(document);
4545
expect(consoleWarnSpy).toHaveBeenCalledWith(
4646
'Missing AWS-UI CSS for theme "default", version "3.0.0 (abc)", and git sha "abc".'
4747
);
@@ -54,12 +54,55 @@ describe('checkMissingStyles', () => {
5454
--awsui-version-info-c4d5e6: true;
5555
}
5656
`;
57-
checkMissingStyles();
57+
checkMissingStyles(document);
5858
expect(consoleWarnSpy).toHaveBeenCalledWith(
5959
'Missing AWS-UI CSS for theme "default", version "3.0.0 (abc)", and git sha "abc".'
6060
);
6161
expect(sendPanoramaMetricSpy).toHaveBeenCalledWith('awsui-missing-css-asset', {});
6262
});
63+
64+
describe('in iframe', () => {
65+
let iframe: HTMLIFrameElement;
66+
let iframeDocument: Document;
67+
68+
beforeEach(() => {
69+
iframe = document.createElement('iframe');
70+
document.body.appendChild(iframe);
71+
iframeDocument = iframe.contentDocument!;
72+
});
73+
74+
afterEach(() => {
75+
iframe.remove();
76+
});
77+
78+
test('should pass the check if styles found inside an iframe', () => {
79+
const iframeStyle = document.createElement('style');
80+
iframeDocument.body.append(iframeStyle);
81+
// using :root does not work in JSDOM: https://github.com/jsdom/jsdom/issues/3563
82+
iframeStyle.textContent = `
83+
body {
84+
--awsui-version-info-${GIT_SHA}: true;
85+
}
86+
`;
87+
checkMissingStyles(iframeDocument);
88+
expect(consoleWarnSpy).not.toHaveBeenCalled();
89+
expect(sendPanoramaMetricSpy).not.toHaveBeenCalled();
90+
});
91+
92+
test('should report missing styles if rendered in a different iframe', () => {
93+
style.textContent = `
94+
body {
95+
--awsui-version-info-${GIT_SHA}: true;
96+
}
97+
`;
98+
99+
checkMissingStyles(iframeDocument);
100+
expect(consoleWarnSpy).toHaveBeenCalledWith(
101+
'Missing AWS-UI CSS for theme "default", version "3.0.0 (abc)", and git sha "abc".'
102+
);
103+
expect(sendPanoramaMetricSpy).toHaveBeenCalledWith('awsui-missing-css-asset', {});
104+
});
105+
});
63106
});
64107

65108
describe('idleWithDelay', () => {

src/internal/hooks/use-base-component/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
import { MutableRefObject } from 'react';
3+
import React, { MutableRefObject } from 'react';
44

55
import {
66
ComponentConfiguration,
@@ -32,12 +32,12 @@ export default function useBaseComponent<T = any>(
3232
const isVisualRefresh = useVisualRefresh();
3333
const theme = getVisualTheme(THEME, isVisualRefresh);
3434
useComponentMetrics(componentName, { packageSource: PACKAGE_SOURCE, packageVersion: PACKAGE_VERSION, theme }, config);
35-
useMissingStylesCheck();
3635
const elementRef = useComponentMetadata<T>(
3736
componentName,
3837
{ packageName: PACKAGE_SOURCE, version: PACKAGE_VERSION, theme },
3938
analyticsMetadata as any
4039
);
41-
useFocusVisible(elementRef as MutableRefObject<HTMLElement>);
40+
useMissingStylesCheck(elementRef as React.RefObject<HTMLElement>);
41+
useFocusVisible(elementRef as React.RefObject<HTMLElement>);
4242
return { __internalRootRef: elementRef };
4343
}

src/internal/hooks/use-base-component/styles-check.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
import { useEffect } from 'react';
3+
import React, { useEffect } from 'react';
44

55
import { GIT_SHA, PACKAGE_VERSION, THEME } from '../../environment';
66
import { metrics } from '../../metrics';
77

8-
export function checkMissingStyles() {
9-
const result = getComputedStyle(document.body).getPropertyValue(`--awsui-version-info-${GIT_SHA}`);
8+
export function checkMissingStyles(ownerDocument: Document) {
9+
const result = getComputedStyle(ownerDocument.body).getPropertyValue(`--awsui-version-info-${GIT_SHA}`);
1010
if (!result) {
1111
console.error(`Missing AWS-UI CSS for theme "${THEME}", version "${PACKAGE_VERSION}", and git sha "${GIT_SHA}".`);
1212
metrics.sendOpsMetricObject('awsui-missing-css-asset', {});
@@ -37,16 +37,18 @@ export function idleWithDelay(cb: () => void) {
3737
};
3838
}
3939

40-
let checked = false;
41-
const checkMissingStylesOnce = () => {
40+
const checkedDocs = new WeakMap<Document, boolean>();
41+
const checkMissingStylesOnce = (elementRef: React.RefObject<HTMLElement>) => {
42+
const ownerDocument = elementRef.current?.ownerDocument ?? document;
43+
const checked = checkedDocs.get(ownerDocument);
4244
if (!checked) {
43-
checkMissingStyles();
44-
checked = true;
45+
checkMissingStyles(ownerDocument);
46+
checkedDocs.set(ownerDocument, true);
4547
}
4648
};
4749

48-
export function useMissingStylesCheck() {
50+
export function useMissingStylesCheck(elementRef: React.RefObject<HTMLElement>) {
4951
useEffect(() => {
50-
return idleWithDelay(() => checkMissingStylesOnce());
51-
}, []);
52+
return idleWithDelay(() => checkMissingStylesOnce(elementRef));
53+
}, [elementRef]);
5254
}

0 commit comments

Comments
 (0)