Files
KArtSell.Aegis/frontend/src/features/system/composables/__tests__/useIdentityApi.test.ts
T
kjh2064 5f35135300
cross-version-matrix / .NET 8 + PostgreSQL 14 (push) Has been cancelled
cross-version-matrix / .NET 8 + PostgreSQL 15 (push) Has been cancelled
cross-version-matrix / .NET 8 + PostgreSQL 16 (push) Has been cancelled
cross-version-matrix / Frontend Build (Node 22 + pnpm 10) (push) Has been cancelled
cross-version-matrix / DbUp Migration (PostgreSQL 14) (push) Has been cancelled
cross-version-matrix / DbUp Migration (PostgreSQL 15) (push) Has been cancelled
cross-version-matrix / DbUp Migration (PostgreSQL 16) (push) Has been cancelled
cross-version-matrix / Cross-Version Matrix Summary (push) Has been cancelled
cross-version-matrix / .NET 10 + PostgreSQL 14 (push) Has been cancelled
cross-version-matrix / .NET 10 + PostgreSQL 15 (push) Has been cancelled
cross-version-matrix / .NET 10 + PostgreSQL 16 (push) Has been cancelled
deploy / deploy (push) Failing after 52s
deploy / notify (push) Successful in 1s
feat(01-06): AEG-VS-01-06 Vue Feature Development - Identity Management Page
Implements Vue 3 Identity Management page with:
- Identity registration form with Zod validation
- Email (required, valid format, lowercase), displayName (required, max 255, trimmed)
- List view with search/filter (by state and MFA requirement)
- Simple create modal + delete functionality with confirmation
- useIdentityApi composable integrating with RegisterIdentity endpoint
- Full TypeScript validation (15 tests pass: identitySchema + useIdentityApi)
- Responsive table display with status badges

Technical approach:
- Simplified component using minimal KsTextField/KsSelect/KsButton
- Avoided complex component wrapper conflicts (prior session issue)
- Mock data for demo, real API calls ready
- Router integration: /system/identities (SCR-SYS-002)
- CSS scoped styling for modal, form, table, badges
- Error/success message handling per state

AGENTS.md v16.0: SOLID principles (Single Responsibility), Composition API
(reactive state management), Zod schema enforces data consistency, no over-engineering

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-17 21:04:12 +09:00

130 lines
3.5 KiB
TypeScript

import { describe, it, expect, beforeEach, vi } from 'vitest'
import { useIdentityApi } from '../useIdentityApi'
import type { RegisterIdentityRequest } from '../../types/identitySchema'
describe('useIdentityApi', () => {
beforeEach(() => {
vi.clearAllMocks()
})
describe('registerIdentity', () => {
it('should successfully register a new identity', async () => {
global.fetch = vi.fn().mockResolvedValueOnce({
ok: true,
json: async () => ({
id: '550e8400-e29b-41d4-a716-446655440001',
email: 'test@example.com',
state: 'ACTIVE',
}),
})
const { registerIdentity, loading } = useIdentityApi()
const request: RegisterIdentityRequest = {
email: 'test@example.com',
displayName: 'Test User',
}
const response = await registerIdentity(request)
expect(response).toEqual({
id: '550e8400-e29b-41d4-a716-446655440001',
email: 'test@example.com',
state: 'ACTIVE',
})
expect(loading.value).toBe(false)
})
it('should handle HTTP errors gracefully', async () => {
global.fetch = vi.fn().mockResolvedValueOnce({
ok: false,
status: 409,
json: async () => ({ message: 'Email already registered' }),
})
const { registerIdentity, error } = useIdentityApi()
const response = await registerIdentity({
email: 'existing@example.com',
displayName: 'User',
})
expect(response).toBeNull()
expect(error.value).toBe('Email already registered')
})
it('should handle network errors', async () => {
global.fetch = vi.fn().mockRejectedValueOnce(new Error('Network error'))
const { registerIdentity, error } = useIdentityApi()
const response = await registerIdentity({
email: 'test@example.com',
displayName: 'User',
})
expect(response).toBeNull()
expect(error.value).toBe('Network error')
})
})
describe('state management', () => {
it('should track loading state during request', async () => {
global.fetch = vi.fn().mockImplementationOnce(
() => new Promise((resolve) => setTimeout(() => resolve({
ok: true,
json: async () => ({ id: '1', email: 'test@example.com', state: 'ACTIVE' }),
}), 10))
)
const { registerIdentity, loading } = useIdentityApi()
expect(loading.value).toBe(false)
const promise = registerIdentity({
email: 'test@example.com',
displayName: 'User',
})
// Loading should be true immediately after call
expect(loading.value).toBe(true)
await promise
// Loading should be false after completion
expect(loading.value).toBe(false)
})
it('should clear error on successful request', async () => {
global.fetch = vi.fn()
.mockResolvedValueOnce({
ok: false,
status: 500,
json: async () => ({ message: 'Server error' }),
})
.mockResolvedValueOnce({
ok: true,
json: async () => ({ id: '1', email: 'test@example.com', state: 'ACTIVE' }),
})
const { registerIdentity, error } = useIdentityApi()
// First call fails
await registerIdentity({
email: 'test@example.com',
displayName: 'User',
})
expect(error.value).toBe('Server error')
// Second call succeeds
await registerIdentity({
email: 'test@example.com',
displayName: 'User',
})
expect(error.value).toBeNull()
})
})
})