Skip to content

Commit 44c42a2

Browse files
authored
fix: fix "window is not defined" error in usewindowresize hook (#742) (#743)
* Fix SSR window is not defined error in useWindowResize hook * Remove SSR assumptions from test suite and update comments * Fix prettier formatting in useWindowResize test --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]>
1 parent b312990 commit 44c42a2

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

src/hooks/useWindowResize.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export const useWindowResize = (timeout = 200): WindowSize => {
1515
const [windowSize, setWindowSize] = useState<WindowSize>(getWindowSize());
1616

1717
useEffect(() => {
18+
// Skip event listener setup during static build when window is not available.
19+
if (typeof window === "undefined") return;
1820
/**
1921
* Resize event fired; window size recalculated.
2022
*/
@@ -42,6 +44,9 @@ export const useWindowResize = (timeout = 200): WindowSize => {
4244
* @returns window height and width.
4345
*/
4446
function getWindowSize(): WindowSize {
45-
const { innerHeight, innerWidth } = window;
47+
if (typeof window === "undefined") {
48+
return { height: 0, width: 0 };
49+
}
50+
const { innerHeight = 0, innerWidth = 0 } = window;
4651
return { height: innerHeight, width: innerWidth };
4752
}

tests/useWindowResize.test.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { jest } from "@jest/globals";
2+
import { act, renderHook } from "@testing-library/react";
3+
4+
const { useWindowResize } = await import("../src/hooks/useWindowResize");
5+
6+
describe("useWindowResize", () => {
7+
beforeEach(() => {
8+
jest.useFakeTimers();
9+
});
10+
11+
afterEach(() => {
12+
jest.clearAllTimers();
13+
jest.useRealTimers();
14+
});
15+
16+
test("returns current window dimensions", () => {
17+
// Set window dimensions
18+
Object.defineProperty(window, "innerWidth", {
19+
configurable: true,
20+
value: 1024,
21+
writable: true,
22+
});
23+
Object.defineProperty(window, "innerHeight", {
24+
configurable: true,
25+
value: 768,
26+
writable: true,
27+
});
28+
29+
const { result } = renderHook(() => useWindowResize());
30+
31+
expect(result.current).toEqual({ height: 768, width: 1024 });
32+
});
33+
34+
test("updates dimensions on window resize", () => {
35+
// Set initial dimensions
36+
Object.defineProperty(window, "innerWidth", {
37+
configurable: true,
38+
value: 1024,
39+
writable: true,
40+
});
41+
Object.defineProperty(window, "innerHeight", {
42+
configurable: true,
43+
value: 768,
44+
writable: true,
45+
});
46+
47+
const { result } = renderHook(() => useWindowResize(100));
48+
49+
expect(result.current).toEqual({ height: 768, width: 1024 });
50+
51+
// Simulate window resize
52+
act(() => {
53+
Object.defineProperty(window, "innerWidth", {
54+
configurable: true,
55+
value: 1920,
56+
writable: true,
57+
});
58+
Object.defineProperty(window, "innerHeight", {
59+
configurable: true,
60+
value: 1080,
61+
writable: true,
62+
});
63+
window.dispatchEvent(new Event("resize"));
64+
65+
// Fast-forward timeout
66+
jest.advanceTimersByTime(100);
67+
});
68+
69+
expect(result.current).toEqual({ height: 1080, width: 1920 });
70+
});
71+
72+
test("debounces resize events with the specified timeout", () => {
73+
Object.defineProperty(window, "innerWidth", {
74+
configurable: true,
75+
value: 1024,
76+
writable: true,
77+
});
78+
Object.defineProperty(window, "innerHeight", {
79+
configurable: true,
80+
value: 768,
81+
writable: true,
82+
});
83+
84+
const { result } = renderHook(() => useWindowResize(200));
85+
86+
// Simulate multiple rapid resize events
87+
act(() => {
88+
Object.defineProperty(window, "innerWidth", {
89+
configurable: true,
90+
value: 1920,
91+
writable: true,
92+
});
93+
Object.defineProperty(window, "innerHeight", {
94+
configurable: true,
95+
value: 1080,
96+
writable: true,
97+
});
98+
window.dispatchEvent(new Event("resize"));
99+
100+
// Fast-forward only 100ms - should not update yet
101+
jest.advanceTimersByTime(100);
102+
});
103+
104+
// Should still have initial dimensions
105+
expect(result.current).toEqual({ height: 768, width: 1024 });
106+
107+
act(() => {
108+
// Fast-forward remaining 100ms
109+
jest.advanceTimersByTime(100);
110+
});
111+
112+
// Now should have updated dimensions
113+
expect(result.current).toEqual({ height: 1080, width: 1920 });
114+
});
115+
116+
test("cleans up event listener on unmount", () => {
117+
const removeEventListenerSpy = jest.spyOn(window, "removeEventListener");
118+
119+
const { unmount } = renderHook(() => useWindowResize());
120+
121+
unmount();
122+
123+
expect(removeEventListenerSpy).toHaveBeenCalledWith(
124+
"resize",
125+
expect.any(Function),
126+
);
127+
128+
removeEventListenerSpy.mockRestore();
129+
});
130+
});

0 commit comments

Comments
 (0)