import { describe, it, expect } from 'vitest' import { waitFor, act } from '@testing-library/react' import { http, HttpResponse } from 'msw' import { server } from '@/test/mocks/server' import { renderHookWithProviders } from '@/test/utils' import { mockUserResponse } from '@/test/mocks/data' import { useUsers, useCreateUser, useUpdateUser } from '@/hooks/useUsers' // --------------------------------------------------------------------------- // useUsers // --------------------------------------------------------------------------- describe('useUsers', () => { it('fetches user list (success)', async () => { const { result } = renderHookWithProviders(() => useUsers()) await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect(result.current.data).toEqual([mockUserResponse]) expect(result.current.data).toHaveLength(1) expect(result.current.data![0].username).toBe('admin_user') expect(result.current.data![0].role).toBe('admin') }) it('handles empty list', async () => { server.use( http.get('/api/admin/users', () => { return HttpResponse.json([]) }), ) const { result } = renderHookWithProviders(() => useUsers()) await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect(result.current.data).toEqual([]) expect(result.current.data).toHaveLength(0) }) }) // --------------------------------------------------------------------------- // useCreateUser // --------------------------------------------------------------------------- describe('useCreateUser', () => { it('creates user (success)', async () => { const newUser = { ...mockUserResponse, id: 3, username: 'new_user', email: 'new@dak.de', role: 'dak_mitarbeiter' as const, } server.use( http.post('/api/admin/users', () => { return HttpResponse.json(newUser) }), ) const { result } = renderHookWithProviders(() => useCreateUser()) let response: unknown await act(async () => { response = await result.current.mutateAsync({ username: 'new_user', email: 'new@dak.de', password: 'SecurePass123!', role: 'dak_mitarbeiter', }) }) await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect((response as { id: number }).id).toBe(3) expect((response as { username: string }).username).toBe('new_user') expect((response as { role: string }).role).toBe('dak_mitarbeiter') }) it('handles validation error (422)', async () => { server.use( http.post('/api/admin/users', () => { return HttpResponse.json( { detail: 'Username already exists' }, { status: 422 }, ) }), ) const { result } = renderHookWithProviders(() => useCreateUser()) await act(async () => { try { await result.current.mutateAsync({ username: 'admin_user', email: 'duplicate@dak.de', password: 'SecurePass123!', role: 'admin', }) } catch { // expected } }) await waitFor(() => expect(result.current.isError).toBe(true)) }) }) // --------------------------------------------------------------------------- // useUpdateUser // --------------------------------------------------------------------------- describe('useUpdateUser', () => { it('updates user (success)', async () => { const updatedUser = { ...mockUserResponse, role: 'dak_mitarbeiter' as const, is_active: false, } server.use( http.put('/api/admin/users/:id', () => { return HttpResponse.json(updatedUser) }), ) const { result } = renderHookWithProviders(() => useUpdateUser()) let response: unknown await act(async () => { response = await result.current.mutateAsync({ id: 1, payload: { role: 'dak_mitarbeiter', is_active: false }, }) }) await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect((response as { role: string }).role).toBe('dak_mitarbeiter') expect((response as { is_active: boolean }).is_active).toBe(false) }) it('handles error (404 Not Found)', async () => { server.use( http.put('/api/admin/users/:id', () => { return HttpResponse.json( { detail: 'User not found' }, { status: 404 }, ) }), ) const { result } = renderHookWithProviders(() => useUpdateUser()) await act(async () => { try { await result.current.mutateAsync({ id: 999, payload: { is_active: false }, }) } catch { // expected } }) await waitFor(() => expect(result.current.isError).toBe(true)) }) })