Skip to content

Commit

Permalink
feat : Test 스크립트 작성
Browse files Browse the repository at this point in the history
  • Loading branch information
Lee-Dongwook committed Oct 28, 2024
1 parent 82857cc commit 80c9393
Show file tree
Hide file tree
Showing 7 changed files with 497 additions and 0 deletions.
66 changes: 66 additions & 0 deletions src/hooks/test/useDeleteChat.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { renderHook, act, waitFor } from '@testing-library/react';
import { useDeleteChat } from '@/hooks/useDeleteChat';
import { deleteDoc } from 'firebase/firestore';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

jest.mock('firebase/firestore', () => ({
deleteDoc: jest.fn(),
doc: jest.fn(),
}));

const createTestQueryClient = () => {
return new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
};

const wrapper = ({ children }: { children: React.ReactNode }) => {
return (
<QueryClientProvider client={createTestQueryClient()}>
{children}
</QueryClientProvider>
);
};

describe('useDeleteChat 테스트', () => {
const mockUserId = 'user123';
const mockSessionId = 'session123';

it('성공적으로 채팅 세션을 삭제해야 한다.', async () => {
(deleteDoc as jest.Mock).mockResolvedValueOnce(undefined);

const { result } = renderHook(() => useDeleteChat(mockUserId), {
wrapper,
});

await act(async () => {
result.current.mutate(mockSessionId);
});

await waitFor(() => expect(result.current.isSuccess).toBe(true));

expect(deleteDoc).toHaveBeenCalledWith(expect.anything());

expect(result.current.status).toBe('success');
});

it('채팅 세션 삭제 실패 시 에러를 반환해야 한다.', async () => {
const errorMessage = 'Failed to delete chat session';
(deleteDoc as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));

const { result } = renderHook(() => useDeleteChat(mockUserId), {
wrapper,
});

await act(async () => {
result.current.mutate(mockSessionId);
});

await waitFor(() => expect(result.current.isError).toBe(true));
expect(result.current.error).toEqual(new Error(errorMessage));
});
});
73 changes: 73 additions & 0 deletions src/hooks/test/useFirestoreQuery.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { renderHook, waitFor } from '@testing-library/react';
import { useFirestoreQuery } from '@/hooks/useFirestoreQuery';
import { getDocs, Query } from 'firebase/firestore';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

jest.mock('firebase/firestore', () => ({
getDocs: jest.fn(),
Query: jest.fn(),
}));

const createTestQueryClient = () => {
return new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
};

const wrapper = ({ children }: { children: React.ReactNode }) => {
return (
<QueryClientProvider client={createTestQueryClient()}>
{children}
</QueryClientProvider>
);
};

describe('useFirestoreQuery 테스트', () => {
const mockQueryKey = 'testQuery';
const mockFirestoreQuery = {} as Query;

it('성공적으로 Firestore 데이터를 가져와야 한다', async () => {
const mockData = [
{ id: '1', name: 'Document 1' },
{ id: '2', name: 'Document 2' },
];

(getDocs as jest.Mock).mockResolvedValueOnce({
docs: mockData.map((doc) => ({
id: doc.id,
data: () => ({ name: doc.name }),
})),
});

const { result } = renderHook(
() =>
useFirestoreQuery<(typeof mockData)[0]>(
mockQueryKey,
mockFirestoreQuery
),
{ wrapper }
);

await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(mockData);
});

it('Firestore 호출 실패 시 에러를 반환해야 한다', async () => {
const errorMessage = 'Failed to fetch data';

(getDocs as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));

const { result } = renderHook(
() => useFirestoreQuery<any>(mockQueryKey, mockFirestoreQuery),
{ wrapper }
);

await waitFor(() => expect(result.current.isError).toBe(true));
expect(result.current.error).toEqual(new Error(errorMessage));
});
});
80 changes: 80 additions & 0 deletions src/hooks/test/useLocalstorage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { renderHook, act } from '@testing-library/react';
import { useLocalStorage } from '@/hooks/useLocalStorage';

describe('useLocalStorage 테스트', () => {
const mockKey = 'testKey';

beforeEach(() => {
localStorage.clear();
jest.clearAllMocks();
});

it('초기 값이 localStorage에 없을 때 기본 값을 반환해야 한다', () => {
const { result } = renderHook(() => useLocalStorage(mockKey, 'initial'));

const [storedValue] = result.current;

expect(storedValue).toBe('initial');
expect(localStorage.getItem(mockKey)).toBe(JSON.stringify('initial'));
});

it('localStorage에 값이 있을 때 해당 값을 반환해야 한다', () => {
localStorage.setItem(mockKey, JSON.stringify('storedValue'));

const { result } = renderHook(() => useLocalStorage(mockKey, 'initial'));

const [storedValue] = result.current;

expect(storedValue).toBe('storedValue');
});

it('값을 업데이트하면 localStorage에 저장되어야 한다', () => {
const { result } = renderHook(() => useLocalStorage(mockKey, 'initial'));

const [, setValue] = result.current;

act(() => {
setValue('newValue');
});

const [updatedValue] = result.current;

expect(updatedValue).toBe('newValue');
expect(localStorage.getItem(mockKey)).toBe(JSON.stringify('newValue'));
});

it('localStorage에서 데이터를 가져오거나 설정할 때 오류가 발생하면 기본 값을 반환해야 한다', () => {
jest.spyOn(Storage.prototype, 'getItem').mockImplementation(() => {
throw new Error('Failed to get item');
});

const { result } = renderHook(() => useLocalStorage(mockKey, 'initial'));

const [storedValue] = result.current;

expect(storedValue).toBe('initial');
});

it('setItem에서 오류가 발생하면 콘솔에 에러를 출력해야 한다', () => {
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();

jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
throw new Error('Failed to set item');
});

const { result } = renderHook(() => useLocalStorage(mockKey, 'initial'));

const [, setValue] = result.current;

act(() => {
setValue('newValue');
});

expect(consoleErrorSpy).toHaveBeenCalledWith(
'Failed to set localStorage item:',
expect.any(Error)
);

consoleErrorSpy.mockRestore();
});
});
73 changes: 73 additions & 0 deletions src/hooks/test/useOnlineStatus.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { renderHook, act } from '@testing-library/react';
import { useOnlineStatus } from '@/hooks/useOnlineStatus';

describe('useOnlineStatus', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('초기 온라인 상태를 설정해야 한다', () => {
Object.defineProperty(navigator, 'onLine', {
value: true,
writable: true,
});

const { result } = renderHook(() => useOnlineStatus());
expect(result.current).toBe(true);

Object.defineProperty(navigator, 'onLine', {
value: false,
writable: true,
});

const { result: offlineResult } = renderHook(() => useOnlineStatus());
expect(offlineResult.current).toBe(false);
});

it('online 이벤트 발생 시 상태가 true로 변경되어야 한다', () => {
const { result } = renderHook(() => useOnlineStatus());

act(() => {
window.dispatchEvent(new Event('online'));
});

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

it('offline 이벤트 발생 시 상태가 false로 변경되어야 한다', () => {
const { result } = renderHook(() => useOnlineStatus());

act(() => {
window.dispatchEvent(new Event('offline'));
});

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

it('컴포넌트 언마운트 시 이벤트 리스너가 제거되어야 한다', () => {
const addEventListenerSpy = jest.spyOn(window, 'addEventListener');
const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');

const { unmount } = renderHook(() => useOnlineStatus());

expect(addEventListenerSpy).toHaveBeenCalledWith(
'online',
expect.any(Function)
);
expect(addEventListenerSpy).toHaveBeenCalledWith(
'offline',
expect.any(Function)
);

unmount();

expect(removeEventListenerSpy).toHaveBeenCalledWith(
'online',
expect.any(Function)
);
expect(removeEventListenerSpy).toHaveBeenCalledWith(
'offline',
expect.any(Function)
);
});
});
Loading

0 comments on commit 80c9393

Please sign in to comment.