import { describe, it, expect, beforeEach, vi } from 'vitest' import axios from 'axios' import { onboardingService } from '../onboarding.service' import type { OnboardingRequest, OnboardingResponse, EmployeeStatusResponse } from '../../types/onboarding' // Mock axios vi.mock('axios', () => ({ default: { post: vi.fn(), get: vi.fn(), }, })) const mockedAxios = axios as unknown as { post: ReturnType get: ReturnType } describe('OnboardingService', () => { beforeEach(() => { vi.clearAllMocks() }) describe('onboardEmployee', () => { it('should successfully onboard an employee', async () => { // Arrange const request: OnboardingRequest = { resume_id: 1, keycloak_user_id: '550e8400-e29b-41d4-a716-446655440000', keycloak_username: 'wang.ming', hire_date: '2026-02-21', departments: [ { department_id: 9, position: '資深工程師', membership_type: 'permanent', }, ], role_ids: [1, 2], storage_quota_gb: 20, email_quota_mb: 5120, } const mockResponse: OnboardingResponse = { message: 'Employee onboarded successfully', employee: { tenant_id: 1, seq_no: 1, tenant_emp_code: 'PWD0001', keycloak_user_id: '550e8400-e29b-41d4-a716-446655440000', keycloak_username: 'wang.ming', name: '王明', hire_date: '2026-02-21', }, summary: { departments_assigned: 1, roles_assigned: 2, services_enabled: 5, }, } mockedAxios.post.mockResolvedValueOnce({ data: mockResponse }) // Act const result = await onboardingService.onboardEmployee(request) // Assert expect(mockedAxios.post).toHaveBeenCalledWith( 'http://localhost:10181/api/v1/emp-lifecycle/onboard', request ) expect(result).toEqual(mockResponse) }) it('should throw error when API fails', async () => { // Arrange const request: OnboardingRequest = { resume_id: 999, keycloak_user_id: 'invalid-uuid', keycloak_username: 'test', hire_date: '2026-02-21', departments: [], role_ids: [], } const errorMessage = 'Resume ID 999 not found' mockedAxios.post.mockRejectedValueOnce({ response: { data: { detail: errorMessage }, status: 404, }, }) // Act & Assert await expect( onboardingService.onboardEmployee(request) ).rejects.toThrow() }) }) describe('getEmployeeStatus', () => { it('should fetch employee status successfully', async () => { // Arrange const tenantId = 1 const seqNo = 1 const mockResponse: EmployeeStatusResponse = { employee: { tenant_id: 1, seq_no: 1, tenant_emp_code: 'PWD0001', name: '王明', keycloak_user_id: '550e8400-e29b-41d4-a716-446655440000', keycloak_username: 'wang.ming', hire_date: '2026-02-21', resign_date: null, employment_status: 'active', storage_quota_gb: 20, email_quota_mb: 5120, }, departments: [ { department_id: 9, department_name: '玄鐵風能', position: '資深工程師', membership_type: 'permanent', joined_at: '2026-02-21T10:00:00', }, ], roles: [ { role_id: 1, role_name: 'HR管理員', role_code: 'HR_ADMIN', assigned_at: '2026-02-21T10:00:00', }, ], services: [ { service_id: 1, service_name: '單一簽入', service_code: 'SSO', quota_gb: null, quota_mb: null, enabled_at: '2026-02-21T10:00:00', }, ], } mockedAxios.get.mockResolvedValueOnce({ data: mockResponse }) // Act const result = await onboardingService.getEmployeeStatus(tenantId, seqNo) // Assert expect(mockedAxios.get).toHaveBeenCalledWith( `http://localhost:10181/api/v1/emp-lifecycle/${tenantId}/${seqNo}/status` ) expect(result).toEqual(mockResponse) }) it('should throw error when employee not found', async () => { // Arrange const tenantId = 1 const seqNo = 999 mockedAxios.get.mockRejectedValueOnce({ response: { data: { detail: 'Employee not found' }, status: 404, }, }) // Act & Assert await expect( onboardingService.getEmployeeStatus(tenantId, seqNo) ).rejects.toThrow() }) }) describe('offboardEmployee', () => { it('should successfully offboard an employee', async () => { // Arrange const tenantId = 1 const seqNo = 1 const mockResponse = { message: 'Employee offboarded successfully', employee: { tenant_emp_code: 'PWD0001', resign_date: '2026-02-21', }, summary: { departments_removed: 1, roles_revoked: 2, services_disabled: 5, }, } mockedAxios.post.mockResolvedValueOnce({ data: mockResponse }) // Act const result = await onboardingService.offboardEmployee(tenantId, seqNo) // Assert expect(mockedAxios.post).toHaveBeenCalledWith( `http://localhost:10181/api/v1/emp-lifecycle/${tenantId}/${seqNo}/offboard` ) expect(result).toEqual(mockResponse) }) }) })