Skip to content

Commit

Permalink
fix: slightly better tests for useResizeObserver (#608)
Browse files Browse the repository at this point in the history
### **PR Type**
tests, enhancement


___

### **Description**
- Added a new mock implementation for `ResizeObserver` to facilitate
testing.
- Improved test coverage for the `useResizeObserver` hook, including
testing observer disconnection.
- Simplified conditional checks in `useResizeObserver` using `c8 ignore
next` for better code coverage handling.



___



### **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>ResizeObserver.ts</strong><dd><code>Add mock
implementation for ResizeObserver</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

packages/ui-hooks/src/hooks/__tests__/__mocks__/ResizeObserver.ts

<li>Added a mock implementation for <code>ResizeObserver</code>.<br>
<li> Implemented methods to simulate resize events.<br> <li> Utilized
<code>vitest</code> for mocking functions.<br>


</details>


  </td>
<td><a
href="https://github.com/aversini/ui-components/pull/608/files#diff-cd7fcfea89952737da719c2e7c1e5503ac41f7ca30268423d53384e84846fd9b">+69/-0</a>&nbsp;
&nbsp; </td>

</tr>                    

<tr>
  <td>
    <details>
<summary><strong>useResizeObserver.test.tsx</strong><dd><code>Improve
and expand tests for useResizeObserver</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

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

<li>Replaced inline <code>ResizeObserverMock</code> with imported
mock.<br> <li> Enhanced test cases for
<code>useResizeObserver</code>.<br> <li> Added test for observer
disconnection on unmount.<br>


</details>


  </td>
<td><a
href="https://github.com/aversini/ui-components/pull/608/files#diff-817c498322b1d9ec6ea8df205b7893101d4b89f74fb9e6ef998d09c64931389d">+31/-87</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>Simplify
conditional checks and ensure cleanup</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

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

<li>Simplified conditional checks using <code>c8 ignore next</code>.<br>
<li> Ensured observer disconnects on component unmount.<br>


</details>


  </td>
<td><a
href="https://github.com/aversini/ui-components/pull/608/files#diff-bb3ddb329d4b3f6fd8a1e761a789d33ba9e6b3556d42068d3928b15ff426bda1">+3/-4</a>&nbsp;
&nbsp; &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 30, 2024
1 parent bc3cb58 commit 3619c92
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 91 deletions.
69 changes: 69 additions & 0 deletions packages/ui-hooks/src/hooks/__tests__/__mocks__/ResizeObserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { vi } from "vitest";

export class ResizeObserverMock {
private static _instances: ResizeObserverMock[] = [];

private callback: any;
private _observe: any;
private _unobserve: any;
private _disconnect: any;

constructor(callback: ResizeObserverCallback) {
this.callback = callback;
this.observe = vi.fn();
this.unobserve = vi.fn();
this.disconnect = vi.fn();
ResizeObserverMock._instances.push(this);
}

public static get instances(): ResizeObserverMock[] {
return ResizeObserverMock._instances;
}

public observe(element: Element): void {
this._observe.mock.calls.push([element]);
}

public unobserve(element: Element): void {
this._unobserve.mock.calls.push([element]);
}

public disconnect(): void {
this._disconnect.mock.calls.push([]);
}

public mockTrigger(entries: ResizeObserverEntry[]): void {
this.callback(entries, this);
}

public simulateResize({
bottom,
height,
left,
right,
top,
width,
}: {
bottom?: number;
height?: number;
left?: number;
right?: number;
top?: number;
width?: number;
} = {}) {
ResizeObserverMock._instances.forEach((target) => {
target.callback([
{
contentRect: {
bottom: bottom || 0,
height: height || 0,
left: left || 0,
right: right || 0,
top: top || 0,
width: width || 0,
},
},
]);
});
}
}
118 changes: 31 additions & 87 deletions packages/ui-hooks/src/hooks/__tests__/useResizeObserver.test.tsx
Original file line number Diff line number Diff line change
@@ -1,111 +1,55 @@
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>;
});
import { ResizeObserverMock } from "./__mocks__/ResizeObserver";

vi.spyOn(window, "requestAnimationFrame").mockImplementation(
(callback: FrameRequestCallback): number => {
callback(0);
return 0;
},
);
const TestComponent = forwardRef<HTMLDivElement>((_, ref) => {
return <div ref={ref}>hello world</div>;
});

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);
expect(result.current[0]).toBeInstanceOf(Object);
expect(result.current[1]).toEqual({
x: 0,
y: 0,
width: 0,
height: 0,
top: 0,
left: 0,
bottom: 0,
right: 0,
});
});

it("should return 10 when width is resized to 10", () => {
it("should update the sizes when the observed element changes size", async () => {
global.ResizeObserver = window.ResizeObserver = ResizeObserverMock;
const { result } = renderHook(() => useResizeObserver());
render(<TestComponent ref={result.current[0]} />);
const observer = ResizeObserverMock.instances[0];

act(() => {
ResizeObserverMock.simulateResize({ width: 10 });
observer.simulateResize({ width: 100, height: 200 });
});
expect(result.current[1].width).toBe(10);

expect(result.current[1].width).toBe(100);
expect(result.current[1].height).toBe(200);
});

it("disconnects the observer when the component unmounts", () => {
global.ResizeObserver = window.ResizeObserver = ResizeObserverMock;
const { result, unmount } = renderHook(() => useResizeObserver());
render(<TestComponent ref={result.current[0]} />);
const observer = ResizeObserverMock.instances[0];
unmount();
expect(observer.disconnect).toHaveBeenCalledTimes(1);
});
});
7 changes: 3 additions & 4 deletions packages/ui-hooks/src/hooks/useResizeObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ export function useResizeObserver<T extends HTMLElement = any>(
const [rect, setRect] = useState<ObserverRect>(defaultState);

const observer = useMemo(() => {
/* c8 ignore start */
/* c8 ignore next 3 */
if (typeof ResizeObserver === "undefined") {
return null;
}
/* c8 ignore end */

return new ResizeObserver((entries: any) => {
const entry = entries[0];
Expand All @@ -58,21 +57,21 @@ export function useResizeObserver<T extends HTMLElement = any>(
});
}, [isMounted]);

/* c8 ignore start */
useEffect(() => {
/* c8 ignore next 3 */
if (ref.current) {
observer?.observe(ref.current, options);
}

return () => {
observer?.disconnect();

/* c8 ignore next 3 */
if (frameID.current) {
cancelAnimationFrame(frameID.current);
}
};
}, [observer, options]);
/* c8 ignore end */

return [ref, rect] as const;
}

0 comments on commit 3619c92

Please sign in to comment.