Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: modern-kit refactoring & test coverage 증가 #112

Merged
merged 1 commit into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/heavy-rivers-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/react': patch
---

refac: modern-kit refactoring & test coverage 증가
32 changes: 24 additions & 8 deletions packages/react/src/hooks/useImageStatus/useImageStatus.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,41 @@ describe('useImageStatus', () => {

it('should change status to "complete" when an image loads successfully', async () => {
const { result } = renderHook(() => useImageStatus());
const loadEvent = new Event('load');

const img = document.createElement('img');
img.setAttribute('src', 'imgUrl');

await waitFor(() => result.current.ref(img));
await waitFor(() => {
result.current.ref(img);
img.dispatchEvent(loadEvent);
});

img.onload = () => {
expect(result.current.imageStatus).toBe('complete');
};
expect(result.current.imageStatus).toBe('complete');
});

it('should change status to "error" when an image fails to load', async () => {
const { result } = renderHook(() => useImageStatus());
const errorEvent = new Event('error');

const img = document.createElement('img');
img.setAttribute('src', 'imgUrl');

await waitFor(() => result.current.ref(img));
await waitFor(() => {
result.current.ref(img);
img.dispatchEvent(errorEvent);
});

expect(result.current.imageStatus).toBe('error');
});

it('should not change state if a nullish value is passed to ref', async () => {
const { result } = renderHook(() => useImageStatus());

await waitFor(() => {
result.current.ref(null as any);
});

img.onerror = () => {
expect(result.current.imageStatus).toBe('error');
};
expect(result.current.imageStatus).toBe('pending');
});
});
6 changes: 2 additions & 4 deletions packages/react/src/hooks/useIntersectionObserver/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useRef } from 'react';
import { usePreservedCallback } from '../usePreservedCallback';
import { noop } from '@modern-kit/utils';
import { Nullable } from '@modern-kit/types';
import { noop } from '@modern-kit/utils';

export interface UseIntersectionObserverProps extends IntersectionObserverInit {
action: (entry: IntersectionObserverEntry) => void;
Expand All @@ -24,9 +24,7 @@ export const useIntersectionObserver = <T extends HTMLElement>({
if (entry && entry.isIntersecting) {
const targetElement = entry.target as T;

if (callbackAction) {
callbackAction(entry);
}
callbackAction(entry);

if (calledOnce) {
observer.unobserve(targetElement);
Expand Down
44 changes: 44 additions & 0 deletions packages/react/src/hooks/useMediaQuery/useMediaQuery.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { MockInstance } from 'vitest';
import { useMediaQuery } from '.';
import { renderHook } from '@testing-library/react';
import * as ModernKitUtils from '@modern-kit/utils';

let windowMatchMediaSpy: MockInstance;

beforeEach(() => {
windowMatchMediaSpy = vi.spyOn(window, 'matchMedia');

windowMatchMediaSpy.mockImplementation((query) => {
return {
matches: query === '(min-width: 600px)',
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
};
});
});

afterEach(() => {
vi.clearAllMocks();
});

describe('useMediaQuery', () => {
it('should return true for matches when query matches', () => {
const { result } = renderHook(() => useMediaQuery('(min-width: 600px)'));

expect(result.current.isMatch).toBe(true);
});

it('should return false when query does not match', () => {
const { result } = renderHook(() => useMediaQuery('(min-width: 599px)'));

expect(result.current.isMatch).toBe(false);
});

it('should return false for isMatch when not in a client environment', () => {
vi.spyOn(ModernKitUtils, 'isClient').mockReturnValue(false);

const { result } = renderHook(() => useMediaQuery('(min-width: 600px)'));

expect(result.current.isMatch).toBe(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { screen } from '@testing-library/react';
import { useOnClickOutside } from '.';
import { renderSetup } from '../../utils/test/renderSetup';

afterEach(() => {
vi.clearAllMocks();
});

const TestComponent = ({ onAction }: { onAction: () => void }) => {
const { ref } = useOnClickOutside<HTMLDivElement>(onAction);

Expand Down
43 changes: 14 additions & 29 deletions packages/react/src/hooks/useToggle/useToggle.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,25 @@
import { screen, waitFor } from '@testing-library/react';
import { renderHook, waitFor } from '@testing-library/react';
import { useToggle } from '.';
import { renderSetup } from '../../utils/test/renderSetup';

const TestComponent = () => {
const [bool, toggle] = useToggle(false);
describe('useToggle', () => {
it('should default to false if no arguments are passed.', async () => {
const { result } = renderHook(() => useToggle());

return (
<div>
<p role={'paragraph'}>{`${bool}`}</p>
<button onClick={toggle}>button</button>
</div>
);
};
expect(result.current[0]).toBeFalsy();
});

describe('useToggle', () => {
it('When toggle is executed, the value of bool changes from true to false, or from false to true.', async () => {
const { user } = renderSetup(<TestComponent />);
it('should toggle the boolean value from true to false or from false to true when executed.', async () => {
const { result } = renderHook(() => useToggle(false));
const toggle = result.current[1];

const button = screen.getByRole('button');
const paragraph = screen.getByRole('paragraph');
expect(result.current[0]).toBeFalsy();

expect(paragraph).toHaveTextContent('false');
await waitFor(() => toggle());

await waitFor(() => {
user.click(button);
expect(paragraph).toHaveTextContent('true');
});
expect(result.current[0]).toBeTruthy();

await waitFor(() => {
user.click(button);
expect(paragraph).toHaveTextContent('false');
});
await waitFor(() => toggle());

await waitFor(() => {
user.click(button);
expect(paragraph).toHaveTextContent('true');
});
expect(result.current[0]).toBeFalsy();
});
});
2 changes: 1 addition & 1 deletion packages/react/src/hooks/useVisibilityChange/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface UseVisibilityChangeProps {
export const useVisibilityChange = ({
onShow = noop,
onHide = noop,
}: UseVisibilityChangeProps) => {
}: UseVisibilityChangeProps = {}) => {
const handleVisibilityChange = usePreservedCallback((event: Event) => {
const isVisible = document.visibilityState === 'visible';
const callbackAction = isVisible ? onShow : onHide;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
import { renderHook } from '@testing-library/react';
import { useVisibilityChange } from '.';
import * as ModernKitUtils from '@modern-kit/utils';

// Mocking the noop function in @modern-kit/utils
vi.mock('@modern-kit/utils', () => {
return {
noop: vi.fn(),
};
});

const visibilityStateSpyOn = vi.spyOn(document, 'visibilityState', 'get');
const event = new Event('visibilitychange');

afterEach(() => {
vi.clearAllMocks();
});

describe('useVisibilityChange', () => {
const visibilityStateSpyOn = vi.spyOn(document, 'visibilityState', 'get');
const event = new Event('visibilitychange');
it('should call the onShow callback when the page becomes visible', () => {
const { noop } = ModernKitUtils;

renderHook(() => useVisibilityChange());

visibilityStateSpyOn.mockReturnValue('visible');
document.dispatchEvent(event);

expect(noop).toBeCalledTimes(1);

visibilityStateSpyOn.mockReturnValue('hidden');
document.dispatchEvent(event);

afterAll(() => {
visibilityStateSpyOn.mockRestore();
expect(noop).toBeCalledTimes(2);
});

it('should call the onShow callback when the page becomes visible', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/react/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default defineConfig({
'src/global.d.ts',
'src/components/index.ts',
'src/hooks/index.ts',
'src/utils/test/**',
],
},
},
Expand Down