Skip to content

Commit 38ff25b

Browse files
authored
[CLNP-6003] test: Add tests for hooks in src/hooks (#1283)
### Changelog * Added tests for hooks in `src/hooks` #### before <img width="1186" alt="스크린샷 2024-12-10 오후 4 09 19" src="https://github.com/user-attachments/assets/b22b914a-1280-4d22-b4f1-3e735fdd409e"> #### after <img width="1099" alt="스크린샷 2024-12-10 오후 4 08 14" src="https://github.com/user-attachments/assets/3431656d-ff7a-4bfd-9df6-ee255d022dee">
1 parent 9c9f520 commit 38ff25b

File tree

8 files changed

+268
-67
lines changed

8 files changed

+268
-67
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { renderHook } from '@testing-library/react-hooks';
2+
import { useAsyncRequest } from '../useAsyncRequest';
3+
4+
describe('useAsyncRequest', () => {
5+
beforeEach(() => {
6+
jest.clearAllMocks();
7+
});
8+
9+
it('handle request with no response correctly', async () => {
10+
const mockPromise = Promise.resolve();
11+
const mockRequest = jest.fn().mockReturnValue(mockPromise);
12+
13+
const { result } = renderHook(() => useAsyncRequest(mockRequest));
14+
15+
await mockPromise;
16+
17+
expect(result.current.loading).toBe(false);
18+
});
19+
20+
it('handle request with response correctly', async () => {
21+
const mockResponse = { code: 'ok' };
22+
const mockPromise = Promise.resolve(mockResponse);
23+
const mockRequest = jest.fn().mockReturnValue(mockPromise);
24+
25+
const { result } = renderHook(() => useAsyncRequest(mockRequest));
26+
27+
await mockPromise;
28+
29+
expect(result.current.response).toBe(mockResponse);
30+
expect(result.current.loading).toBe(false);
31+
});
32+
33+
it('cancel request correctly', async () => {
34+
const mockCancel = jest.fn();
35+
const mockRequest = { cancel: mockCancel };
36+
37+
const { unmount } = renderHook(() => useAsyncRequest(mockRequest));
38+
39+
unmount();
40+
41+
expect(mockCancel).toBeCalled();
42+
});
43+
44+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { renderHook } from '@testing-library/react-hooks';
2+
import { useDebounce } from '../useDebounce';
3+
4+
describe('useAsyncRequest', () => {
5+
beforeEach(() => {
6+
jest.clearAllMocks();
7+
});
8+
9+
it('handle useDebounce correctly', async () => {
10+
const mockFunction = jest.fn();
11+
const { result } = renderHook(() => useDebounce(mockFunction, 1000));
12+
13+
const debounceFunction = result.current;
14+
15+
debounceFunction();
16+
debounceFunction();
17+
debounceFunction();
18+
debounceFunction();
19+
debounceFunction();
20+
21+
await new Promise(resolve => {
22+
setTimeout(resolve, 1000);
23+
});
24+
25+
expect(mockFunction).toBeCalledTimes(1);
26+
});
27+
28+
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React from 'react';
2+
import { renderHook } from '@testing-library/react-hooks';
3+
import useLongPress from '../useLongPress';
4+
import { screen, fireEvent, render, waitFor } from '@testing-library/react';
5+
6+
describe('useLongPress', () => {
7+
8+
beforeEach(() => {
9+
jest.clearAllMocks();
10+
});
11+
12+
it('handle long press correctly', async () => {
13+
const mockOnLongPress = jest.fn();
14+
const mockOnClick = jest.fn();
15+
16+
const { result } = renderHook(() => useLongPress({
17+
onLongPress: mockOnLongPress,
18+
onClick: mockOnClick,
19+
}));
20+
const { onTouchStart, onTouchEnd } = result.current;
21+
22+
const targetComponent = <div id="target" onTouchStart={onTouchStart} onTouchEnd={onTouchEnd}>touch this</div>;
23+
render(targetComponent);
24+
25+
const element = screen.getByText('touch this');
26+
fireEvent.touchStart(element);
27+
await new Promise(resolve => {
28+
setTimeout(resolve, 1000);
29+
});
30+
fireEvent.touchEnd(element);
31+
32+
await waitFor(() => {
33+
expect(mockOnLongPress).toHaveBeenCalled();
34+
});
35+
});
36+
37+
it('cancel long press if touch is too short', async () => {
38+
const mockOnLongPress = jest.fn();
39+
const mockOnClick = jest.fn();
40+
41+
const { result } = renderHook(() => useLongPress({
42+
onLongPress: mockOnLongPress,
43+
onClick: mockOnClick,
44+
}));
45+
const { onTouchStart, onTouchEnd } = result.current;
46+
47+
const targetComponent = <div id="target" onTouchStart={onTouchStart} onTouchEnd={onTouchEnd}>touch this</div>;
48+
render(targetComponent);
49+
50+
const element = screen.getByText('touch this');
51+
fireEvent.touchStart(element);
52+
await new Promise(resolve => {
53+
setTimeout(resolve, 100);
54+
});
55+
fireEvent.touchEnd(element);
56+
57+
await waitFor(() => {
58+
expect(mockOnClick).toHaveBeenCalled();
59+
expect(mockOnLongPress).not.toHaveBeenCalled();
60+
});
61+
});
62+
63+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from 'react';
2+
import { renderHook } from '@testing-library/react-hooks';
3+
import { screen, fireEvent, render, waitFor } from '@testing-library/react';
4+
import useMouseHover from '../useMouseHover';
5+
6+
describe('useMouseHover', () => {
7+
8+
beforeEach(() => {
9+
jest.clearAllMocks();
10+
});
11+
12+
it('handle mouse over and out correctly', async () => {
13+
const mockSetHover = jest.fn();
14+
15+
const targetComponent = <div id="target">hover</div>;
16+
render(targetComponent);
17+
18+
const hoverElement = screen.getByText('hover');
19+
const ref = {
20+
current: hoverElement,
21+
};
22+
23+
renderHook(() => useMouseHover({
24+
ref,
25+
setHover: mockSetHover,
26+
}));
27+
28+
fireEvent.mouseEnter(hoverElement);
29+
fireEvent.mouseLeave(hoverElement);
30+
31+
await waitFor(() => {
32+
expect(mockSetHover).toHaveBeenCalledTimes(2);
33+
expect(mockSetHover).toHaveBeenCalledWith(true);
34+
expect(mockSetHover).toHaveBeenCalledWith(false);
35+
});
36+
});
37+
38+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from 'react';
2+
import { renderHook } from '@testing-library/react-hooks';
3+
import { screen, fireEvent, render, waitFor } from '@testing-library/react';
4+
import useOutsideAlerter from '../useOutsideAlerter';
5+
6+
describe('useOutsideAlerter', () => {
7+
8+
beforeEach(() => {
9+
jest.clearAllMocks();
10+
});
11+
12+
it('handle click outside correctly', async () => {
13+
const mockClickOutside = jest.fn();
14+
15+
const targetComponent = <div id="target">inside</div>;
16+
render(targetComponent);
17+
18+
const insideElement = screen.getByText('inside');
19+
const ref = {
20+
current: insideElement,
21+
};
22+
23+
renderHook(() => useOutsideAlerter({
24+
ref,
25+
callback: mockClickOutside,
26+
}));
27+
28+
fireEvent.mouseDown(insideElement);
29+
30+
await waitFor(() => {
31+
expect(mockClickOutside).toHaveBeenCalledTimes(1);
32+
});
33+
});
34+
35+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { renderHook } from '@testing-library/react-hooks';
2+
import { useThrottleCallback } from '../useThrottleCallback';
3+
4+
describe('useThrottleCallback', () => {
5+
6+
beforeEach(() => {
7+
jest.clearAllMocks();
8+
});
9+
10+
it('handle throttle callback correctly when leading is true', async () => {
11+
const mockCallback = jest.fn();
12+
13+
const { result: { current: throttleCallback } } = renderHook(() => useThrottleCallback(mockCallback, 1000, { leading: true }));
14+
15+
throttleCallback();
16+
throttleCallback();
17+
throttleCallback();
18+
throttleCallback();
19+
throttleCallback();
20+
21+
await new Promise(resolve => {
22+
setTimeout(resolve, 100);
23+
});
24+
expect(mockCallback).toHaveBeenCalledTimes(1);
25+
26+
await new Promise(resolve => {
27+
setTimeout(resolve, 1000);
28+
});
29+
expect(mockCallback).toHaveBeenCalledTimes(1);
30+
31+
});
32+
33+
it('handle throttle callback correctly when trailing is true', async () => {
34+
const mockCallback = jest.fn();
35+
36+
const { result: { current: throttleCallback } } = renderHook(() => useThrottleCallback(mockCallback, 1000, { trailing: true }));
37+
38+
throttleCallback();
39+
throttleCallback();
40+
throttleCallback();
41+
throttleCallback();
42+
throttleCallback();
43+
44+
await new Promise(resolve => {
45+
setTimeout(resolve, 100);
46+
});
47+
expect(mockCallback).toHaveBeenCalledTimes(0);
48+
49+
await new Promise(resolve => {
50+
setTimeout(resolve, 1000);
51+
});
52+
expect(mockCallback).toHaveBeenCalledTimes(1);
53+
54+
await new Promise(resolve => {
55+
setTimeout(resolve, 1000);
56+
});
57+
expect(mockCallback).toHaveBeenCalledTimes(1);
58+
});
59+
60+
});

src/hooks/useAppendDomNode.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/hooks/useThrottleCallback.ts

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -46,43 +46,3 @@ export function useThrottleCallback<T extends(...args: any[]) => void>(
4646
timer.current = setTimeout(invoke, delay);
4747
}) as T;
4848
}
49-
50-
/**
51-
* Note: `leading` has higher priority rather than `trailing`
52-
* */
53-
export function throttle<T extends(...args: any[]) => void>(
54-
callback: T,
55-
delay: number,
56-
options: { leading?: boolean; trailing?: boolean } = {
57-
leading: true,
58-
trailing: false,
59-
},
60-
) {
61-
let timer: ReturnType<typeof setTimeout> | null = null;
62-
let trailingArgs: null | any[] = null;
63-
64-
return ((...args: any[]) => {
65-
if (timer) {
66-
trailingArgs = args;
67-
return;
68-
}
69-
70-
if (options.leading) {
71-
callback(...args);
72-
} else {
73-
trailingArgs = args;
74-
}
75-
76-
const invoke = () => {
77-
if (options.trailing && trailingArgs) {
78-
callback(...trailingArgs);
79-
trailingArgs = null;
80-
timer = setTimeout(invoke, delay);
81-
} else {
82-
timer = null;
83-
}
84-
};
85-
86-
timer = setTimeout(invoke, delay);
87-
}) as T;
88-
}

0 commit comments

Comments
 (0)