Skip to content

Commit

Permalink
chore: first pass at trying to mock ResizeObserver for tests (#604)
Browse files Browse the repository at this point in the history
### **PR Type**
Tests, Enhancement


___

### **Description**
- Added a mock implementation of `ResizeObserver` for testing purposes.
- Created comprehensive tests for the `useResizeObserver` hook using the
mock `ResizeObserver`.
- Refactored `useResizeObserver` to handle cases where `ResizeObserver`
is undefined, improving robustness.



___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>useResizeObserver.test.tsx</strong><dd><code>Add tests
for `useResizeObserver` with `ResizeObserver` mock</code></dd></summary>
<hr>

packages/ui-hooks/src/hooks/__tests__/useResizeObserver.test.tsx

<li>Added a mock implementation for <code>ResizeObserver</code>.<br>
<li> Created tests for <code>useResizeObserver</code> hook.<br> <li>
Simulated resize events in tests.<br>


</details>


  </td>
<td><a
href="https://github.com/aversini/ui-components/pull/604/files#diff-817c498322b1d9ec6ea8df205b7893101d4b89f74fb9e6ef998d09c64931389d">+111/-0</a>&nbsp;
</td>

</tr>                    
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>useResizeObserver.ts</strong><dd><code>Refactor
`useResizeObserver` to handle undefined
`ResizeObserver`</code></dd></summary>
<hr>

packages/ui-hooks/src/hooks/useResizeObserver.ts

<li>Refactored <code>useResizeObserver</code> to handle
<code>ResizeObserver</code> undefined case.<br> <li> Removed unnecessary
comments and adjusted memoization logic.<br>


</details>


  </td>
<td><a
href="https://github.com/aversini/ui-components/pull/604/files#diff-bb3ddb329d4b3f6fd8a1e761a789d33ba9e6b3556d42068d3928b15ff426bda1">+20/-22</a>&nbsp;
</td>

</tr>                    
</table></td></tr></tr></tbody></table>

___

> 💡 **PR-Agent usage**:
>Comment `/help` on the PR to get a list of all available PR-Agent tools
and their descriptions
  • Loading branch information
aversini authored Aug 23, 2024
1 parent 6f47ede commit 0a52aba
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 22 deletions.
111 changes: 111 additions & 0 deletions packages/ui-hooks/src/hooks/__tests__/useResizeObserver.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { act, render, renderHook } from "@testing-library/react";

import { forwardRef } from "react";
import { useResizeObserver } from "../useResizeObserver";

class ResizeObserverMock {
fn: any;
static instances: ResizeObserverMock[] = [];
/**
* Simulate a resize event on all instances of ResizeObserverMock
* It can be called with no arguments or with an optional object that
* contains the contentRect property.
*
* @static
* @param {ResizeObserverEntry[]} [entries] - The entries to simulate the resize event with.
* @returns {void}
*
*/
static simulateResize({
bottom,
height,
left,
right,
top,
width,
}: {
bottom?: number;
height?: number;
left?: number;
right?: number;
top?: number;
width?: number;
} = {}) {
ResizeObserverMock.instances.forEach((target) => {
target.fn([
{
contentRect: {
bottom: bottom || 0,
height: height || 0,
left: left || 0,
right: right || 0,
top: top || 0,
width: width || 0,
},
},
]);
});
}

constructor(fn: any) {
this.fn = fn;
ResizeObserverMock.instances.push(this);
}

observe() {
this.fn([
{
contentRect: {
bottom: 0,
height: 0,
left: 0,
right: 0,
top: 0,
width: 0,
},
},
]);
}
unobserve() {
ResizeObserverMock.instances = [];
}
disconnect() {
ResizeObserverMock.instances = [];
}
}

const TestComponent = forwardRef<HTMLDivElement>((_, ref) => {
return <div ref={ref}>hello world</div>;
});

vi.spyOn(window, "requestAnimationFrame").mockImplementation(
(callback: FrameRequestCallback): number => {
callback(0);
return 0;
},
);

describe("useResizeObserver", () => {
const originalResizeObserver = global.ResizeObserver;
beforeAll(() => {
global.ResizeObserver = window.ResizeObserver = ResizeObserverMock;
});
afterAll(() => {
global.ResizeObserver = window.ResizeObserver = originalResizeObserver;
});
it("should return 0 when first initialized", () => {
global.ResizeObserver = window.ResizeObserver = ResizeObserverMock;
const { result } = renderHook(() => useResizeObserver());
expect(result.current[1].width).toBe(0);
});

it("should return 10 when width is resized to 10", () => {
global.ResizeObserver = window.ResizeObserver = ResizeObserverMock;
const { result } = renderHook(() => useResizeObserver());
render(<TestComponent ref={result.current[0]} />);
act(() => {
ResizeObserverMock.simulateResize({ width: 10 });
});
expect(result.current[1].width).toBe(10);
});
});
42 changes: 20 additions & 22 deletions packages/ui-hooks/src/hooks/useResizeObserver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* c8 ignore start */

import { useEffect, useMemo, useRef, useState } from "react";

import { useIsMounted } from "./useIsMounted";
Expand Down Expand Up @@ -40,26 +38,27 @@ export function useResizeObserver<T extends HTMLElement = any>(

const [rect, setRect] = useState<ObserverRect>(defaultState);

const observer = useMemo(
() =>
typeof window !== "undefined"
? new ResizeObserver((entries: any) => {
const entry = entries[0];

if (entry) {
cancelAnimationFrame(frameID.current);
const observer = useMemo(() => {
/* c8 ignore start */
if (typeof ResizeObserver === "undefined") {
return null;
}
/* c8 ignore end */

frameID.current = requestAnimationFrame(() => {
if (ref.current && isMounted()) {
setRect(entry.contentRect);
}
});
}
})
: null,
[isMounted],
);
return new ResizeObserver((entries: any) => {
const entry = entries[0];
if (entry) {
cancelAnimationFrame(frameID.current);
frameID.current = requestAnimationFrame(() => {
if (ref.current && isMounted()) {
setRect(entry.contentRect);
}
});
}
});
}, [isMounted]);

/* c8 ignore start */
useEffect(() => {
if (ref.current) {
observer?.observe(ref.current, options);
Expand All @@ -73,8 +72,7 @@ export function useResizeObserver<T extends HTMLElement = any>(
}
};
}, [observer, options]);
/* c8 ignore end */

return [ref, rect] as const;
}

/* c8 ignore end */

0 comments on commit 0a52aba

Please sign in to comment.