如何测试这个自定义钩子(useRef)
How to test this custom hook (useRef)
我正在尝试测试这个自定义挂钩,但我不知道如何将 useRef 作为参数发送
ElementRef 正在使用 useRef
import { MutableRefObject, useEffect, useState } from "react";
export default function useNearScreen(elementRef: MutableRefObject<HTMLDivElement>, margin = 80) {
const [show, setShow] = useState(false);
useEffect(() => {
const onChange = (entries: IntersectionObserverEntry[]) => {
const el: IntersectionObserverEntry = entries[0];
if (el.isIntersecting) {
setShow(true)
observer.disconnect();
}
}
const observer = new IntersectionObserver(onChange, {
rootMargin: `${margin}px`
})
observer.observe(elementRef.current as Element);
return () => observer.disconnect();
})
return show;
}
首先jest默认使用jsdom作为测试环境。 jsdom 不支持 IntersectionObserver
,请参阅 issue#2032。所以我们需要模拟它并手动触发回调。
我将使用 @testing-library/react-hooks
包来测试 React 自定义挂钩。
例如
useNearScreen.ts
:
import { MutableRefObject, useEffect, useState } from 'react';
export default function useNearScreen(elementRef: MutableRefObject<HTMLDivElement>, margin = 80) {
const [show, setShow] = useState(false);
useEffect(() => {
const onChange = (entries: IntersectionObserverEntry[], observer: IntersectionObserver) => {
const el: IntersectionObserverEntry = entries[0];
if (el.isIntersecting) {
setShow(true);
observer.disconnect();
}
};
const observer = new IntersectionObserver(onChange, {
rootMargin: `${margin}px`,
});
observer.observe(elementRef.current as Element);
return () => observer.disconnect();
});
return show;
}
useNearScreen.test.ts
:
import { renderHook } from '@testing-library/react-hooks';
import { MutableRefObject } from 'react';
import { useRef } from 'react';
import useNearScreen from './useNearScreen';
describe('useNearScreen', () => {
test('should pass', () => {
const mObserver = {
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
};
const mIntersectionObserver = jest.fn();
mIntersectionObserver.mockImplementation((callback, options) => {
callback([{ isIntersecting: true }], mObserver);
return mObserver;
});
window.IntersectionObserver = mIntersectionObserver;
const mHTMLDivElement = document.createElement('div');
const { result } = renderHook(() => {
const elementRef = useRef<HTMLDivElement>(mHTMLDivElement);
return useNearScreen(elementRef as MutableRefObject<HTMLDivElement>);
});
expect(result.current).toBe(true);
expect(mIntersectionObserver).toBeCalledWith(expect.any(Function), { rootMargin: '80px' });
expect(mObserver.observe).toBeCalledWith(mHTMLDivElement);
expect(mObserver.disconnect).toBeCalled();
});
});
测试结果:
PASS Whosebug/71118856/useNearScreen.test.ts (9.656 s)
useNearScreen
✓ should pass (16 ms)
------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------|---------|----------|---------|---------|-------------------
All files | 100 | 66.67 | 100 | 100 |
useNearScreen.ts | 100 | 66.67 | 100 | 100 | 9
------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.581 s
我正在尝试测试这个自定义挂钩,但我不知道如何将 useRef 作为参数发送 ElementRef 正在使用 useRef
import { MutableRefObject, useEffect, useState } from "react";
export default function useNearScreen(elementRef: MutableRefObject<HTMLDivElement>, margin = 80) {
const [show, setShow] = useState(false);
useEffect(() => {
const onChange = (entries: IntersectionObserverEntry[]) => {
const el: IntersectionObserverEntry = entries[0];
if (el.isIntersecting) {
setShow(true)
observer.disconnect();
}
}
const observer = new IntersectionObserver(onChange, {
rootMargin: `${margin}px`
})
observer.observe(elementRef.current as Element);
return () => observer.disconnect();
})
return show;
}
首先jest默认使用jsdom作为测试环境。 jsdom 不支持 IntersectionObserver
,请参阅 issue#2032。所以我们需要模拟它并手动触发回调。
我将使用 @testing-library/react-hooks
包来测试 React 自定义挂钩。
例如
useNearScreen.ts
:
import { MutableRefObject, useEffect, useState } from 'react';
export default function useNearScreen(elementRef: MutableRefObject<HTMLDivElement>, margin = 80) {
const [show, setShow] = useState(false);
useEffect(() => {
const onChange = (entries: IntersectionObserverEntry[], observer: IntersectionObserver) => {
const el: IntersectionObserverEntry = entries[0];
if (el.isIntersecting) {
setShow(true);
observer.disconnect();
}
};
const observer = new IntersectionObserver(onChange, {
rootMargin: `${margin}px`,
});
observer.observe(elementRef.current as Element);
return () => observer.disconnect();
});
return show;
}
useNearScreen.test.ts
:
import { renderHook } from '@testing-library/react-hooks';
import { MutableRefObject } from 'react';
import { useRef } from 'react';
import useNearScreen from './useNearScreen';
describe('useNearScreen', () => {
test('should pass', () => {
const mObserver = {
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
};
const mIntersectionObserver = jest.fn();
mIntersectionObserver.mockImplementation((callback, options) => {
callback([{ isIntersecting: true }], mObserver);
return mObserver;
});
window.IntersectionObserver = mIntersectionObserver;
const mHTMLDivElement = document.createElement('div');
const { result } = renderHook(() => {
const elementRef = useRef<HTMLDivElement>(mHTMLDivElement);
return useNearScreen(elementRef as MutableRefObject<HTMLDivElement>);
});
expect(result.current).toBe(true);
expect(mIntersectionObserver).toBeCalledWith(expect.any(Function), { rootMargin: '80px' });
expect(mObserver.observe).toBeCalledWith(mHTMLDivElement);
expect(mObserver.disconnect).toBeCalled();
});
});
测试结果:
PASS Whosebug/71118856/useNearScreen.test.ts (9.656 s)
useNearScreen
✓ should pass (16 ms)
------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------|---------|----------|---------|---------|-------------------
All files | 100 | 66.67 | 100 | 100 |
useNearScreen.ts | 100 | 66.67 | 100 | 100 | 9
------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.581 s