MeshiTrack/packages/web/tests/lib/useApi.test.ts

150 lines
4 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook } from '@testing-library/react';
const { mockUseSession, mockUseSWR, mockApiClient } = vi.hoisted(() => ({
mockUseSession: vi.fn(),
mockUseSWR: vi.fn(),
mockApiClient: {
_accessToken: null as string | null,
2026-04-26 18:44:59 +09:00
set accessToken(token: string) {
this._accessToken = token;
},
get hasToken() {
return this._accessToken !== null;
},
2026-05-19 14:09:03 +09:00
get: vi.fn(),
},
}));
vi.mock('next-auth/react', () => ({
useSession: mockUseSession,
}));
vi.mock('swr', () => ({
2026-05-19 14:09:03 +09:00
default: vi.fn((key, fetcher) => {
if (typeof fetcher === 'function') {
try {
fetcher();
} catch (e) {}
}
return mockUseSWR(key, fetcher);
}),
}));
vi.mock('@/services/api-client', () => ({
apiClient: mockApiClient,
}));
2026-05-19 11:06:03 +09:00
import { useApi } from '../../src/lib/useApi';
beforeEach(() => {
vi.clearAllMocks();
mockApiClient._accessToken = null;
});
describe('useApi', () => {
it('returns loading state when session is loading', () => {
mockUseSession.mockReturnValue({ data: null, status: 'loading' });
mockUseSWR.mockReturnValue({ data: undefined, mutate: vi.fn(), isLoading: false });
const { result } = renderHook(() => useApi());
expect(result.current.isLoading).toBe(true);
expect(result.current.isAuthenticated).toBe(false);
expect(result.current.householdId).toBeNull();
});
it('returns unauthenticated state', () => {
mockUseSession.mockReturnValue({ data: null, status: 'unauthenticated' });
mockUseSWR.mockReturnValue({ data: undefined, mutate: vi.fn(), isLoading: false });
const { result } = renderHook(() => useApi());
expect(result.current.isAuthenticated).toBe(false);
expect(result.current.isLoading).toBe(false);
});
it('sets token on apiClient when session has accessToken', () => {
mockUseSession.mockReturnValue({
data: { accessToken: 'test-jwt' },
status: 'authenticated',
});
mockUseSWR.mockReturnValue({
data: { householdIds: ['hh1'], displayName: 'Test' },
mutate: vi.fn(),
isLoading: false,
});
renderHook(() => useApi());
expect(mockApiClient._accessToken).toBe('test-jwt');
});
it('returns householdId from profile', () => {
mockUseSession.mockReturnValue({
data: { accessToken: 'test-jwt' },
status: 'authenticated',
});
mockUseSWR.mockReturnValue({
data: { householdIds: ['hh1', 'hh2'], displayName: 'Test' },
mutate: vi.fn(),
isLoading: false,
});
const { result } = renderHook(() => useApi());
expect(result.current.householdId).toBe('hh1');
expect(result.current.householdIds).toEqual(['hh1', 'hh2']);
expect(result.current.isAuthenticated).toBe(true);
});
it('returns null householdId when profile has no households', () => {
mockUseSession.mockReturnValue({
data: { accessToken: 'test-jwt' },
status: 'authenticated',
});
mockUseSWR.mockReturnValue({
data: { householdIds: [] },
mutate: vi.fn(),
isLoading: false,
});
const { result } = renderHook(() => useApi());
expect(result.current.householdId).toBeNull();
});
it('returns loading when authenticated but profile is still loading', () => {
mockUseSession.mockReturnValue({
data: { accessToken: 'test-jwt' },
status: 'authenticated',
});
mockUseSWR.mockReturnValue({
data: undefined,
mutate: vi.fn(),
isLoading: true,
});
const { result } = renderHook(() => useApi());
expect(result.current.isLoading).toBe(true);
});
it('provides refreshProfile function from SWR mutate', () => {
const mutateFn = vi.fn();
mockUseSession.mockReturnValue({
data: { accessToken: 'test-jwt' },
status: 'authenticated',
});
mockUseSWR.mockReturnValue({
data: { householdIds: ['hh1'] },
mutate: mutateFn,
isLoading: false,
});
const { result } = renderHook(() => useApi());
expect(result.current.refreshProfile).toBe(mutateFn);
});
});