240 lines
7.0 KiB
TypeScript
240 lines
7.0 KiB
TypeScript
// File: hooks/ai/__tests__/use-intent-classification.test.ts
|
|
// Change Log
|
|
// - 2026-05-19: สร้าง Unit tests สำหรับ Intent Classification hooks (T038).
|
|
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { renderHook, waitFor } from '@testing-library/react';
|
|
import { createTestQueryClient } from '@/lib/test-utils';
|
|
import {
|
|
useIntentDefinitions,
|
|
useIntentDefinition,
|
|
useIntentPatterns,
|
|
useCreateIntentDefinition,
|
|
useClassifyIntent,
|
|
} from '../use-intent-classification';
|
|
import { aiIntentService } from '@/lib/services/ai-intent.service';
|
|
|
|
// Mock service
|
|
vi.mock('@/lib/services/ai-intent.service', () => ({
|
|
aiIntentService: {
|
|
getDefinitions: vi.fn(),
|
|
getDefinition: vi.fn(),
|
|
getPatterns: vi.fn(),
|
|
createDefinition: vi.fn(),
|
|
updateDefinition: vi.fn(),
|
|
createPattern: vi.fn(),
|
|
updatePattern: vi.fn(),
|
|
deletePattern: vi.fn(),
|
|
classify: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
describe('use-intent-classification hooks', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('useIntentDefinitions', () => {
|
|
it('ควรดึง definitions สำเร็จ', async () => {
|
|
const mockData = [
|
|
{ publicId: 'uuid-1', intentCode: 'GET_RFA', category: 'read' },
|
|
{ publicId: 'uuid-2', intentCode: 'SUMMARIZE_DOCUMENT', category: 'read' },
|
|
];
|
|
|
|
vi.mocked(aiIntentService.getDefinitions).mockResolvedValue(mockData);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useIntentDefinitions(), { wrapper });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isSuccess).toBe(true);
|
|
});
|
|
|
|
expect(result.current.data).toEqual(mockData);
|
|
expect(aiIntentService.getDefinitions).toHaveBeenCalledWith(undefined);
|
|
});
|
|
|
|
it('ควรส่ง filter params ไปด้วย', async () => {
|
|
vi.mocked(aiIntentService.getDefinitions).mockResolvedValue([]);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
renderHook(
|
|
() => useIntentDefinitions({ category: 'read', isActive: true }),
|
|
{ wrapper },
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(aiIntentService.getDefinitions).toHaveBeenCalledWith({
|
|
category: 'read',
|
|
isActive: true,
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('useIntentDefinition', () => {
|
|
it('ควรดึง definition ตาม intentCode', async () => {
|
|
const mockDef = {
|
|
publicId: 'uuid-1',
|
|
intentCode: 'GET_RFA',
|
|
descriptionTh: 'ดึง RFA',
|
|
descriptionEn: 'Get RFA',
|
|
category: 'read',
|
|
isActive: true,
|
|
};
|
|
|
|
vi.mocked(aiIntentService.getDefinition).mockResolvedValue(mockDef);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(
|
|
() => useIntentDefinition('GET_RFA'),
|
|
{ wrapper },
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isSuccess).toBe(true);
|
|
});
|
|
|
|
expect(result.current.data).toEqual(mockDef);
|
|
expect(aiIntentService.getDefinition).toHaveBeenCalledWith('GET_RFA');
|
|
});
|
|
|
|
it('ควรไม่ fetch เมื่อ intentCode เป็นค่าว่าง', () => {
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(
|
|
() => useIntentDefinition(''),
|
|
{ wrapper },
|
|
);
|
|
|
|
// enabled: !!intentCode → false → ไม่ fetch
|
|
expect(result.current.fetchStatus).toBe('idle');
|
|
expect(aiIntentService.getDefinition).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('useIntentPatterns', () => {
|
|
it('ควรดึง patterns ตาม intentCode', async () => {
|
|
const mockPatterns = [
|
|
{ publicId: 'p-1', intentCode: 'GET_RFA', patternType: 'keyword', patternValue: 'rfa' },
|
|
];
|
|
|
|
vi.mocked(aiIntentService.getPatterns).mockResolvedValue(mockPatterns);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(
|
|
() => useIntentPatterns('GET_RFA'),
|
|
{ wrapper },
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isSuccess).toBe(true);
|
|
});
|
|
|
|
expect(result.current.data).toEqual(mockPatterns);
|
|
});
|
|
});
|
|
|
|
describe('useCreateIntentDefinition', () => {
|
|
it('ควรเรียก createDefinition สำเร็จ', async () => {
|
|
const newDef = {
|
|
intentCode: 'TEST_INTENT',
|
|
descriptionTh: 'ทดสอบ',
|
|
descriptionEn: 'Test',
|
|
category: 'utility' as const,
|
|
};
|
|
|
|
vi.mocked(aiIntentService.createDefinition).mockResolvedValue({
|
|
publicId: 'new-uuid',
|
|
...newDef,
|
|
isActive: true,
|
|
});
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(
|
|
() => useCreateIntentDefinition(),
|
|
{ wrapper },
|
|
);
|
|
|
|
result.current.mutate(newDef);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isSuccess).toBe(true);
|
|
});
|
|
|
|
expect(aiIntentService.createDefinition).toHaveBeenCalledWith(newDef);
|
|
});
|
|
});
|
|
|
|
describe('useClassifyIntent', () => {
|
|
it('ควร classify query สำเร็จ', async () => {
|
|
const mockResult = {
|
|
intentCode: 'SUMMARIZE_DOCUMENT',
|
|
confidence: 1.0,
|
|
method: 'pattern',
|
|
latencyMs: 3,
|
|
};
|
|
|
|
vi.mocked(aiIntentService.classify).mockResolvedValue(mockResult);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(
|
|
() => useClassifyIntent(),
|
|
{ wrapper },
|
|
);
|
|
|
|
result.current.mutate({ query: 'สรุปเอกสาร' });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isSuccess).toBe(true);
|
|
});
|
|
|
|
expect(result.current.data).toEqual(mockResult);
|
|
expect(aiIntentService.classify).toHaveBeenCalledWith('สรุปเอกสาร', undefined);
|
|
});
|
|
|
|
it('ควรส่ง projectPublicId ไปด้วย (ถ้ามี)', async () => {
|
|
vi.mocked(aiIntentService.classify).mockResolvedValue({
|
|
intentCode: 'GET_RFA',
|
|
confidence: 0.9,
|
|
method: 'llm_fallback',
|
|
latencyMs: 500,
|
|
});
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(
|
|
() => useClassifyIntent(),
|
|
{ wrapper },
|
|
);
|
|
|
|
result.current.mutate({
|
|
query: 'show rfa',
|
|
projectPublicId: 'proj-uuid-123',
|
|
});
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isSuccess).toBe(true);
|
|
});
|
|
|
|
expect(aiIntentService.classify).toHaveBeenCalledWith('show rfa', 'proj-uuid-123');
|
|
});
|
|
|
|
it('ควร handle error state', async () => {
|
|
vi.mocked(aiIntentService.classify).mockRejectedValue(new Error('Network error'));
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(
|
|
() => useClassifyIntent(),
|
|
{ wrapper },
|
|
);
|
|
|
|
result.current.mutate({ query: 'test' });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isError).toBe(true);
|
|
});
|
|
|
|
expect(result.current.error).toBeInstanceOf(Error);
|
|
});
|
|
});
|
|
});
|