Skip to content

Commit 877403c

Browse files
Merge pull request #6053 from Hacker0x01/remoe-flushsync
Remove flushSync usage in ShadowRoot component
2 parents 0b9c1e0 + 1f3d68e commit 877403c

File tree

3 files changed

+38
-31
lines changed

3 files changed

+38
-31
lines changed

src/test/datepicker_test.test.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,9 @@ describe("DatePicker", () => {
922922
});
923923

924924
it("should not apply the calendarIconClassname to calendar icon with calendarIconClassName", () => {
925+
// Suppress expected deprecation warning
926+
const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
927+
925928
const customClassName = "customClassName";
926929
const customClassname = "customClassname";
927930
const { container } = render(
@@ -942,9 +945,14 @@ describe("DatePicker", () => {
942945

943946
expect(calendarIcon?.classList.contains(customClassName)).toBe(true);
944947
expect(calendarIcon?.classList.contains(customClassname)).toBe(false);
948+
949+
warnSpy.mockRestore();
945950
});
946951

947952
it("should apply the calendarIconClassname to calendar icon without calendarIconClassName", () => {
953+
// Suppress expected deprecation warning
954+
const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
955+
948956
const customClassname = "customClassName";
949957
const { container } = render(
950958
<DatePicker
@@ -962,6 +970,8 @@ describe("DatePicker", () => {
962970
);
963971

964972
expect(calendarIcon?.classList.contains(customClassname)).toBe(true);
973+
974+
warnSpy.mockRestore();
965975
});
966976

967977
it("should set the type attribute on the clear button to button", () => {

src/test/helper_components/shadow_root.tsx

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,28 @@
11
import React, {
22
type FC,
33
type PropsWithChildren,
4-
useLayoutEffect,
5-
useRef,
4+
useCallback,
65
useState,
76
} from "react";
8-
import { createPortal, flushSync } from "react-dom";
7+
import { createPortal } from "react-dom";
98

109
const ShadowRoot: FC<PropsWithChildren> = ({ children }) => {
1110
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);
1211

13-
const containerRef = useRef<HTMLDivElement>(null);
14-
const isInitializedRef = useRef(false);
15-
16-
useLayoutEffect(() => {
17-
const container = containerRef.current;
18-
if (isInitializedRef.current || !container) {
19-
return;
20-
}
21-
22-
const root =
23-
container.shadowRoot ?? container.attachShadow({ mode: "open" });
24-
isInitializedRef.current = true;
25-
// Use flushSync to synchronously update state within effect, avoiding cascading renders
26-
// while ensuring the shadow root is available immediately for tests
27-
flushSync(() => setShadowRoot(root));
28-
}, []);
12+
const containerRefCallback = useCallback(
13+
(container: HTMLDivElement | null) => {
14+
if (!container) {
15+
return;
16+
}
17+
const root =
18+
container.shadowRoot ?? container.attachShadow({ mode: "open" });
19+
setShadowRoot(root);
20+
},
21+
[],
22+
);
2923

3024
return (
31-
<div ref={containerRef}>
25+
<div ref={containerRefCallback}>
3226
{shadowRoot && createPortal(children, shadowRoot)}
3327
</div>
3428
);

src/test/index.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,22 @@ expect.extend(toHaveNoViolations);
77
const originalError = console.error;
88
beforeAll(() => {
99
console.error = (...args) => {
10-
// Check the first argument (the error message)
11-
const firstArg = args[0];
12-
const firstArgStr =
13-
typeof firstArg === "string"
14-
? firstArg
15-
: firstArg instanceof Error
16-
? firstArg.message
17-
: String(firstArg);
10+
// Convert all arguments to a single string for checking
11+
const fullMessage = args
12+
.map((arg) =>
13+
typeof arg === "string"
14+
? arg
15+
: arg instanceof Error
16+
? arg.message
17+
: String(arg),
18+
)
19+
.join(" ");
1820

19-
// Suppress floating-ui act warnings
21+
// Suppress floating-ui act warnings - these come from @floating-ui/react-dom
22+
// internally using flushSync, which is expected behavior
2023
if (
21-
firstArgStr.includes("An update to withFloating(PopperComponent)") &&
22-
firstArgStr.includes("inside a test was not wrapped in act")
24+
fullMessage.includes("withFloating(PopperComponent)") &&
25+
fullMessage.includes("not wrapped in act")
2326
) {
2427
return;
2528
}

0 commit comments

Comments
 (0)