test(backend): fix all typescript compiler type errors in test suites

This commit is contained in:
2026-05-21 21:51:52 +07:00
parent 91e9c714df
commit a2952a32a4
6 changed files with 50 additions and 19 deletions
@@ -1,5 +1,6 @@
// File: src/modules/ai/intent-classifier/controllers/intent-admin.controller.spec.ts // File: src/modules/ai/intent-classifier/controllers/intent-admin.controller.spec.ts
// Change Log // Change Log
// - 2026-05-21: แก้ไขไทป์ให้ตรงกับ Enum ล่าสุด
// - 2026-05-19: สร้าง Integration test สำหรับ Admin API (T016, US1). // - 2026-05-19: สร้าง Integration test สำหรับ Admin API (T016, US1).
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
@@ -10,7 +11,10 @@ import {
} from './intent-admin.controller'; } from './intent-admin.controller';
import { IntentDefinitionService } from '../services/intent-definition.service'; import { IntentDefinitionService } from '../services/intent-definition.service';
import { IntentPatternService } from '../services/intent-pattern.service'; import { IntentPatternService } from '../services/intent-pattern.service';
import { IntentCategory } from '../interfaces/intent-category.enum'; import {
IntentCategory,
PatternType,
} from '../interfaces/intent-category.enum';
import { JwtAuthGuard } from '../../../../common/guards/jwt-auth.guard'; import { JwtAuthGuard } from '../../../../common/guards/jwt-auth.guard';
import { RbacGuard } from '../../../../common/guards/rbac.guard'; import { RbacGuard } from '../../../../common/guards/rbac.guard';
@@ -60,7 +64,7 @@ describe('IntentAdminController', () => {
describe('findAll', () => { describe('findAll', () => {
it('ควรเรียก service.findAll พร้อม filter', async () => { it('ควรเรียก service.findAll พร้อม filter', async () => {
await controller.findAll('read', 'true'); await controller.findAll(IntentCategory.READ, 'true');
expect(definitionService.findAll).toHaveBeenCalledWith({ expect(definitionService.findAll).toHaveBeenCalledWith({
category: 'read', category: 'read',
@@ -135,7 +139,7 @@ describe('IntentAdminController', () => {
describe('createPattern', () => { describe('createPattern', () => {
it('ควร merge intentCode กับ dto', async () => { it('ควร merge intentCode กับ dto', async () => {
const dto = { patternType: 'keyword' as const, patternValue: 'rfa' }; const dto = { patternType: PatternType.KEYWORD, patternValue: 'rfa' };
patternService.create.mockResolvedValue({ publicId: 'p-1' } as never); patternService.create.mockResolvedValue({ publicId: 'p-1' } as never);
await controller.createPattern('GET_RFA', dto); await controller.createPattern('GET_RFA', dto);
@@ -1,5 +1,6 @@
// File: src/modules/ai/intent-classifier/services/intent-analytics.service.spec.ts // File: src/modules/ai/intent-classifier/services/intent-analytics.service.spec.ts
// Change Log // Change Log
// - 2026-05-21: แก้ไขการทำ Type Casting ของ AiAuditLog ใน Mock ให้สมบูรณ์ขึ้นด้วย unknown
// - 2026-05-19: สร้าง Unit tests สำหรับ IntentAnalyticsService (T033, US3). // - 2026-05-19: สร้าง Unit tests สำหรับ IntentAnalyticsService (T033, US3).
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
@@ -21,6 +22,7 @@ function mockLog(
const intentCode = overrides.intentCode ?? 'GET_RFA'; const intentCode = overrides.intentCode ?? 'GET_RFA';
return { return {
id: Math.floor(Math.random() * 1000), id: Math.floor(Math.random() * 1000),
publicId: 'mock-public-id',
aiModel: 'intent-classifier', aiModel: 'intent-classifier',
modelName: method === 'llm_fallback' ? 'gemma4:e4b' : 'pattern-match', modelName: method === 'llm_fallback' ? 'gemma4:e4b' : 'pattern-match',
aiSuggestionJson: { aiSuggestionJson: {
@@ -33,7 +35,7 @@ function mockLog(
confidenceScore: overrides.confidence ?? 1.0, confidenceScore: overrides.confidence ?? 1.0,
status: overrides.status ?? AiAuditStatus.SUCCESS, status: overrides.status ?? AiAuditStatus.SUCCESS,
createdAt: new Date(), createdAt: new Date(),
} as AiAuditLog; } as unknown as AiAuditLog;
} }
describe('IntentAnalyticsService', () => { describe('IntentAnalyticsService', () => {
@@ -1,5 +1,6 @@
// File: backend/tests/e2e/rfa-workflow.e2e-spec.ts // File: backend/tests/e2e/rfa-workflow.e2e-spec.ts
// Change Log // Change Log
// - 2026-05-21: แก้ไขไทป์ Record ให้ครอบคลุม ReviewTaskStatus ทั้งหมด (EXPIRED, CANCELLED)
// - 2026-05-15: Initial E2E test scaffolding // - 2026-05-15: Initial E2E test scaffolding
// - 2026-05-16: Simplified to use unit test approach - full E2E requires database // - 2026-05-16: Simplified to use unit test approach - full E2E requires database
// - Note: Full E2E tests require running database and full infrastructure setup // - Note: Full E2E tests require running database and full infrastructure setup
@@ -37,6 +38,8 @@ describe('RFA Approval Workflow (E2E)', () => {
], ],
[ReviewTaskStatus.COMPLETED]: [], [ReviewTaskStatus.COMPLETED]: [],
[ReviewTaskStatus.DELEGATED]: [ReviewTaskStatus.IN_PROGRESS], [ReviewTaskStatus.DELEGATED]: [ReviewTaskStatus.IN_PROGRESS],
[ReviewTaskStatus.EXPIRED]: [],
[ReviewTaskStatus.CANCELLED]: [],
}; };
// Verify status enum values exist // Verify status enum values exist
@@ -1,5 +1,6 @@
// File: backend/tests/integration/cross-spec/qdrant-isolation.spec.ts // File: backend/tests/integration/cross-spec/qdrant-isolation.spec.ts
// Change Log: // Change Log:
// - 2026-05-21: แก้ไข Type Casting ของ AiQdrantService ด้วย unknown
// - 2026-05-16: Cross-spec integration test for QdrantService projectPublicId isolation // - 2026-05-16: Cross-spec integration test for QdrantService projectPublicId isolation
// - 2026-05-16: Fixed mocking strategy to use factory pattern with proper method exposure // - 2026-05-16: Fixed mocking strategy to use factory pattern with proper method exposure
@@ -132,7 +133,9 @@ describe('Cross-Spec: QdrantService Isolation', () => {
it('should verify no rawSearch method exists (security)', () => { it('should verify no rawSearch method exists (security)', () => {
// Assert: No rawSearch method that bypasses projectPublicId filtering // Assert: No rawSearch method that bypasses projectPublicId filtering
expect((service as Record<string, unknown>).rawSearch).toBeUndefined(); expect(
(service as unknown as Record<string, unknown>).rawSearch
).toBeUndefined();
}); });
it('should handle RFA cross-spec usage correctly', async () => { it('should handle RFA cross-spec usage correctly', async () => {
@@ -1,5 +1,6 @@
// File: backend/tests/performance/approval-matrix.perf-spec.ts // File: backend/tests/performance/approval-matrix.perf-spec.ts
// Change Log: // Change Log:
// - 2026-05-21: แก้ไขการจำลองข้อมูลและการคอมไพล์ไทป์ใน ResponseCodeRule
// - 2026-05-16: Performance test for Approval Matrix Service with 1000+ rules // - 2026-05-16: Performance test for Approval Matrix Service with 1000+ rules
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
@@ -46,20 +47,25 @@ describe('ApprovalMatrixService Performance', () => {
(_, i) => ({ (_, i) => ({
id: i + 1, id: i + 1,
responseCodeId: (i % 10) + 1, responseCodeId: (i % 10) + 1,
documentTypeId: (i % 5) + 1, documentTypeId: 1,
isRequired: i % 3 === 0, isRequired: i % 3 === 0,
priority: (i % 5) + 1, priority: (i % 5) + 1,
responseCode: {
id: (i % 10) + 1,
code: `CODE-${i % 10}`,
isActive: true,
} as unknown as ResponseCode,
}) })
); );
jest.spyOn(responseCodeRepo, 'find').mockResolvedValue([]);
jest jest
.spyOn(responseCodeRepo, 'find') .spyOn(responseCodeRuleRepo, 'find')
.mockResolvedValue(mockRules as ResponseCodeRule[]); .mockResolvedValue(mockRules as ResponseCodeRule[]);
jest.spyOn(responseCodeRuleRepo, 'find').mockResolvedValue([]);
// Act: Measure lookup time // Act: Measure lookup time
const startTime = Date.now(); const startTime = Date.now();
const _result = await service.findByDocumentType(1, 'SHOP_DRAWING'); const _result = await service.findByDocumentType(1, 100);
const endTime = Date.now(); const endTime = Date.now();
// Assert: Must complete within 100ms // Assert: Must complete within 100ms
@@ -81,19 +87,26 @@ describe('ApprovalMatrixService Performance', () => {
category: ( category: (
['ENGINEERING', 'CONTRACT', 'QUALITY'] as ResponseCodeCategory[] ['ENGINEERING', 'CONTRACT', 'QUALITY'] as ResponseCodeCategory[]
)[i % 3], )[i % 3],
description: `Description for code ${i}`, descriptionTh: `Description for code ${i}`,
}) })
); );
const mockRules: Partial<ResponseCodeRule>[] = mockCodes.map((code, i) => ({
id: i + 1,
responseCodeId: code.id,
documentTypeId: 1,
responseCode: code as ResponseCode,
}));
jest.spyOn(responseCodeRepo, 'find').mockResolvedValue([]);
jest jest
.spyOn(responseCodeRepo, 'find') .spyOn(responseCodeRuleRepo, 'find')
.mockResolvedValue(mockCodes as ResponseCode[]); .mockResolvedValue(mockRules as ResponseCodeRule[]);
jest.spyOn(responseCodeRuleRepo, 'find').mockResolvedValue([]);
// Act: Run 10 concurrent lookups // Act: Run 10 concurrent lookups
const startTime = Date.now(); const startTime = Date.now();
const promises = Array.from({ length: 10 }, () => const promises = Array.from({ length: 10 }, () =>
service.findByDocumentType(1, 'SHOP_DRAWING') service.findByDocumentType(1, 100)
); );
await Promise.all(promises); await Promise.all(promises);
const endTime = Date.now(); const endTime = Date.now();
@@ -1,11 +1,13 @@
// File: backend/tests/performance/review-tasks.perf-spec.ts // File: backend/tests/performance/review-tasks.perf-spec.ts
// Change Log: // Change Log:
// - 2026-05-21: แก้ไขไทป์ ReviewTaskStatus ในข้อมูลจำลองและสเปก
// - 2026-05-16: Performance test for Review Tasks Query with 10,000+ tasks // - 2026-05-16: Performance test for Review Tasks Query with 10,000+ tasks
import { ReviewTask } from '../../src/modules/review-team/entities/review-task.entity'; import { ReviewTask } from '../../src/modules/review-team/entities/review-task.entity';
import { ReviewTaskStatus } from '../../src/modules/common/enums/review.enums';
interface FindAllOptions { interface FindAllOptions {
status?: string; status?: ReviewTaskStatus;
assignedToUserId?: number; assignedToUserId?: number;
disciplineId?: number; disciplineId?: number;
page?: number; page?: number;
@@ -69,7 +71,11 @@ describe('ReviewTaskService Query Performance', () => {
(_, i) => ({ (_, i) => ({
id: i + 1, id: i + 1,
uuid: `task-${i}`, uuid: `task-${i}`,
status: ['PENDING', 'IN_PROGRESS', 'COMPLETED'][i % 3], status: [
ReviewTaskStatus.PENDING,
ReviewTaskStatus.IN_PROGRESS,
ReviewTaskStatus.COMPLETED,
][i % 3],
assignedToUserId: (i % 100) + 1, assignedToUserId: (i % 100) + 1,
rfaRevisionId: (i % 500) + 1, rfaRevisionId: (i % 500) + 1,
disciplineId: (i % 20) + 1, disciplineId: (i % 20) + 1,
@@ -81,7 +87,7 @@ describe('ReviewTaskService Query Performance', () => {
const startTime = Date.now(); const startTime = Date.now();
const result = service.findAll({ const result = service.findAll({
status: 'PENDING', status: ReviewTaskStatus.PENDING,
page: 1, page: 1,
limit: 20, limit: 20,
}); });
@@ -99,7 +105,7 @@ describe('ReviewTaskService Query Performance', () => {
(_, i) => ({ (_, i) => ({
id: i + 1, id: i + 1,
uuid: `task-${i}`, uuid: `task-${i}`,
status: 'PENDING', status: ReviewTaskStatus.PENDING,
assignedToUserId: 42, assignedToUserId: 42,
disciplineId: 5, disciplineId: 5,
}) })
@@ -109,7 +115,7 @@ describe('ReviewTaskService Query Performance', () => {
const startTime = Date.now(); const startTime = Date.now();
const result = service.findAll({ const result = service.findAll({
status: 'PENDING', status: ReviewTaskStatus.PENDING,
assignedToUserId: 42, assignedToUserId: 42,
disciplineId: 5, disciplineId: 5,
page: 1, page: 1,