690615:1449 237 #01
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@
|
||||
.yarn/install-state.gz
|
||||
|
||||
# testing
|
||||
# /coverage
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
|
||||
@@ -20,16 +20,18 @@ import { Brain, Sliders, Play, Settings } from 'lucide-react';
|
||||
|
||||
export default function UnifiedPromptManagementPage() {
|
||||
const queryClient = useQueryClient();
|
||||
const [selectedType, setSelectedType] = useState<PromptType>('ocr_extraction');
|
||||
const [selectedType, setSelectedType] = useState<PromptType | 'all'>('ocr_extraction');
|
||||
const [selectedVersion, setSelectedVersion] = useState<PromptVersion | null>(null);
|
||||
|
||||
// ดึงข้อมูลประวัติเวอร์ชันทั้งหมดของ prompt_type ที่เลือก
|
||||
const { data: versions = [], isLoading } = useQuery<PromptVersion[]>({
|
||||
queryKey: ['admin-ai-prompts', selectedType],
|
||||
queryFn: async () => {
|
||||
if (selectedType === 'all') return [];
|
||||
const res = await adminAiService.listPrompts(selectedType);
|
||||
return res || [];
|
||||
},
|
||||
enabled: selectedType !== 'all',
|
||||
});
|
||||
|
||||
// อัปเดต selectedVersion เมื่อเปลี่ยนประเภทหรือข้อมูลรีเฟรช
|
||||
@@ -45,6 +47,7 @@ export default function UnifiedPromptManagementPage() {
|
||||
// สร้างเวอร์ชันใหม่
|
||||
const createMutation = useMutation({
|
||||
mutationFn: async (payload: { template: string; manualNote: string }) => {
|
||||
if (selectedType === 'all') throw new Error('Cannot create prompt for "All Types"');
|
||||
return await adminAiService.createPrompt(selectedType, {
|
||||
template: payload.template,
|
||||
manualNote: payload.manualNote,
|
||||
@@ -54,28 +57,52 @@ export default function UnifiedPromptManagementPage() {
|
||||
toast.success('สร้าง Prompt Version ใหม่สำเร็จ');
|
||||
queryClient.invalidateQueries({ queryKey: ['admin-ai-prompts', selectedType] });
|
||||
},
|
||||
onError: () => {
|
||||
toast.error('ไม่สามารถสร้าง Prompt Version ใหม่ได้');
|
||||
onError: (err: unknown) => {
|
||||
const errorMsg = (err as { response?: { data?: { message?: string; userMessage?: string; recoveryAction?: string } } })?.response?.data?.message;
|
||||
const userMessage = (err as { response?: { data?: { userMessage?: string } } })?.response?.data?.userMessage;
|
||||
const recoveryAction = (err as { response?: { data?: { recoveryAction?: string } } })?.response?.data?.recoveryAction;
|
||||
|
||||
// ADR-007 layered error handling (T073)
|
||||
if (userMessage) {
|
||||
toast.error(userMessage, {
|
||||
description: recoveryAction || 'กรุณาตรวจสอบข้อมูลและลองใหม่',
|
||||
});
|
||||
} else {
|
||||
toast.error(errorMsg || 'ไม่สามารถสร้าง Prompt Version ใหม่ได้');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// เปิดใช้งานเวอร์ชัน
|
||||
const activateMutation = useMutation({
|
||||
mutationFn: async (versionNumber: number) => {
|
||||
if (selectedType === 'all') throw new Error('Cannot activate prompt for "All Types"');
|
||||
return await adminAiService.activatePrompt(selectedType, versionNumber);
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('เปิดใช้งาน Prompt Version สำเร็จ');
|
||||
queryClient.invalidateQueries({ queryKey: ['admin-ai-prompts', selectedType] });
|
||||
},
|
||||
onError: () => {
|
||||
toast.error('ไม่สามารถเปิดใช้งาน Prompt Version ได้');
|
||||
onError: (err: unknown) => {
|
||||
const errorMsg = (err as { response?: { data?: { message?: string; userMessage?: string; recoveryAction?: string } } })?.response?.data?.message;
|
||||
const userMessage = (err as { response?: { data?: { userMessage?: string } } })?.response?.data?.userMessage;
|
||||
const recoveryAction = (err as { response?: { data?: { recoveryAction?: string } } })?.response?.data?.recoveryAction;
|
||||
|
||||
// ADR-007 layered error handling (T073)
|
||||
if (userMessage) {
|
||||
toast.error(userMessage, {
|
||||
description: recoveryAction || 'กรุณาตรวจสอบข้อมูลและลองใหม่',
|
||||
});
|
||||
} else {
|
||||
toast.error(errorMsg || 'ไม่สามารถเปิดใช้งาน Prompt Version ได้');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// ลบเวอร์ชัน
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: async (versionNumber: number) => {
|
||||
if (selectedType === 'all') throw new Error('Cannot delete prompt for "All Types"');
|
||||
return await adminAiService.deletePrompt(selectedType, versionNumber);
|
||||
},
|
||||
onSuccess: () => {
|
||||
@@ -83,14 +110,25 @@ export default function UnifiedPromptManagementPage() {
|
||||
queryClient.invalidateQueries({ queryKey: ['admin-ai-prompts', selectedType] });
|
||||
},
|
||||
onError: (err: unknown) => {
|
||||
const errorMsg = (err as { response?: { data?: { message?: string } } })?.response?.data?.message;
|
||||
toast.error(errorMsg || 'ไม่สามารถลบ Prompt Version ได้');
|
||||
const errorMsg = (err as { response?: { data?: { message?: string; userMessage?: string; recoveryAction?: string } } })?.response?.data?.message;
|
||||
const userMessage = (err as { response?: { data?: { userMessage?: string } } })?.response?.data?.userMessage;
|
||||
const recoveryAction = (err as { response?: { data?: { recoveryAction?: string } } })?.response?.data?.recoveryAction;
|
||||
|
||||
// ADR-007 layered error handling (T073)
|
||||
if (userMessage) {
|
||||
toast.error(userMessage, {
|
||||
description: recoveryAction || 'กรุณาตรวจสอบข้อมูลและลองใหม่',
|
||||
});
|
||||
} else {
|
||||
toast.error(errorMsg || 'ไม่สามารถลบ Prompt Version ได้');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// อัปเดตบริบทข้อมูล (Context Config)
|
||||
const updateConfigMutation = useMutation({
|
||||
mutationFn: async (payload: { versionNumber: number; config: ContextConfig }) => {
|
||||
if (selectedType === 'all') throw new Error('Cannot update config for "All Types"');
|
||||
return await adminAiService.updateContextConfig(
|
||||
selectedType,
|
||||
payload.versionNumber,
|
||||
@@ -102,31 +140,42 @@ export default function UnifiedPromptManagementPage() {
|
||||
queryClient.invalidateQueries({ queryKey: ['admin-ai-prompts', selectedType] });
|
||||
},
|
||||
onError: (err: unknown) => {
|
||||
const errorMsg = (err as { response?: { data?: { message?: string } } })?.response?.data?.message;
|
||||
toast.error(errorMsg || 'ไม่สามารถอัปเดตบริบทได้');
|
||||
const errorMsg = (err as { response?: { data?: { message?: string; userMessage?: string; recoveryAction?: string } } })?.response?.data?.message;
|
||||
const userMessage = (err as { response?: { data?: { userMessage?: string } } })?.response?.data?.userMessage;
|
||||
const recoveryAction = (err as { response?: { data?: { recoveryAction?: string } } })?.response?.data?.recoveryAction;
|
||||
|
||||
// ADR-007 layered error handling (T073)
|
||||
if (userMessage) {
|
||||
toast.error(userMessage, {
|
||||
description: recoveryAction || 'กรุณาตรวจสอบข้อมูลและลองใหม่',
|
||||
});
|
||||
} else {
|
||||
toast.error(errorMsg || 'ไม่สามารถอัปเดตบริบทได้');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-6 p-6">
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 border-b border-border/10 pb-5">
|
||||
<div className="space-y-4 sm:space-y-6 p-4 sm:p-6">
|
||||
<div className="flex flex-col sm:flex-row md:flex-row sm:items-center md:items-center justify-between gap-3 sm:gap-4 border-b border-border/10 pb-4 sm:pb-5">
|
||||
<div className="space-y-1">
|
||||
<h1 className="text-2xl font-bold tracking-tight text-foreground flex items-center gap-2">
|
||||
<Brain className="h-6 w-6 text-primary" />
|
||||
ระบบจัดการ Prompt และบริบท (Prompt & Context Manager)
|
||||
<h1 className="text-xl sm:text-2xl font-bold tracking-tight text-foreground flex items-center gap-2">
|
||||
<Brain className="h-5 w-5 sm:h-6 sm:w-6 text-primary" />
|
||||
<span className="hidden sm:inline">ระบบจัดการ Prompt และบริบท (Prompt & Context Manager)</span>
|
||||
<span className="sm:hidden">Prompt Manager</span>
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
<p className="text-xs sm:text-sm text-muted-foreground hidden sm:block">
|
||||
จัดการเทมเพลตพรอมต์และตัวกรองข้อมูล Master Data เพื่อส่งให้ระบบ AI ประมวลผลอย่างแม่นยำ
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full md:w-[320px] bg-background/40 p-2.5 rounded-lg border border-border/50">
|
||||
<div className="w-full sm:w-[280px] md:w-[320px] bg-background/40 p-2 sm:p-2.5 rounded-lg border border-border/50">
|
||||
<PromptTypeDropdown value={selectedType} onChange={setSelectedType} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 xl:grid-cols-12 gap-6 items-start">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-4 sm:gap-6 items-start">
|
||||
{/* Sidebar: รายการประวัติเวอร์ชัน */}
|
||||
<div className="xl:col-span-4 space-y-4">
|
||||
<div className="lg:col-span-4 xl:col-span-4 space-y-4">
|
||||
<VersionHistory
|
||||
versions={versions}
|
||||
isLoading={isLoading}
|
||||
@@ -139,43 +188,55 @@ export default function UnifiedPromptManagementPage() {
|
||||
</div>
|
||||
|
||||
{/* Main Panel: แผงแก้ไขและทดสอบ Sandbox */}
|
||||
<div className="xl:col-span-8">
|
||||
<div className="lg:col-span-8 xl:col-span-8">
|
||||
<Tabs defaultValue="editor" className="w-full space-y-4">
|
||||
<TabsList className="bg-background/40 border border-border/50 p-1">
|
||||
<TabsTrigger value="editor" className="text-xs font-semibold flex items-center gap-1.5">
|
||||
<TabsList className="bg-background/40 border border-border/50 p-1 w-full overflow-x-auto">
|
||||
<TabsTrigger value="editor" className="text-xs font-semibold flex items-center gap-1.5 whitespace-nowrap">
|
||||
<Settings className="h-3.5 w-3.5 text-primary" />
|
||||
ตัวแก้ไขและบริบท (Editor & Context)
|
||||
<span className="hidden sm:inline">ตัวแก้ไขและบริบท (Editor & Context)</span>
|
||||
<span className="sm:hidden">Editor</span>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="sandbox" className="text-xs font-semibold flex items-center gap-1.5">
|
||||
<TabsTrigger value="sandbox" className="text-xs font-semibold flex items-center gap-1.5 whitespace-nowrap">
|
||||
<Play className="h-3.5 w-3.5 text-primary" />
|
||||
บอร์ดทดลอง (3-Step Sandbox)
|
||||
<span className="hidden sm:inline">บอร์ดทดลอง (3-Step Sandbox)</span>
|
||||
<span className="sm:hidden">Sandbox</span>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="parameters" className="text-xs font-semibold flex items-center gap-1.5">
|
||||
<TabsTrigger value="parameters" className="text-xs font-semibold flex items-center gap-1.5 whitespace-nowrap">
|
||||
<Sliders className="h-3.5 w-3.5 text-primary" />
|
||||
พารามิเตอร์รันไทม์ (Runtime Params)
|
||||
<span className="hidden sm:inline">พารามิเตอร์รันไทม์ (Runtime Params)</span>
|
||||
<span className="sm:hidden">Params</span>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="editor" className="space-y-4 mt-0 focus-visible:outline-none">
|
||||
<PromptEditor
|
||||
promptType={selectedType}
|
||||
initialTemplate={selectedVersion?.template || ''}
|
||||
onSave={async (tmpl, note) => {
|
||||
await createMutation.mutateAsync({ template: tmpl, manualNote: note });
|
||||
}}
|
||||
isSaving={createMutation.isPending}
|
||||
/>
|
||||
{selectedVersion && (
|
||||
<ContextConfigEditor
|
||||
initialConfig={selectedVersion.contextConfig}
|
||||
onSave={async (config) => {
|
||||
await updateConfigMutation.mutateAsync({
|
||||
versionNumber: selectedVersion.versionNumber,
|
||||
config,
|
||||
});
|
||||
}}
|
||||
isSaving={updateConfigMutation.isPending}
|
||||
/>
|
||||
{selectedType !== 'all' && (
|
||||
<>
|
||||
<PromptEditor
|
||||
promptType={selectedType}
|
||||
initialTemplate={selectedVersion?.template || ''}
|
||||
onSave={async (tmpl, note) => {
|
||||
await createMutation.mutateAsync({ template: tmpl, manualNote: note });
|
||||
}}
|
||||
isSaving={createMutation.isPending}
|
||||
/>
|
||||
{selectedVersion && (
|
||||
<ContextConfigEditor
|
||||
initialConfig={selectedVersion.contextConfig}
|
||||
onSave={async (config) => {
|
||||
await updateConfigMutation.mutateAsync({
|
||||
versionNumber: selectedVersion.versionNumber,
|
||||
config,
|
||||
});
|
||||
}}
|
||||
isSaving={updateConfigMutation.isPending}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{selectedType === 'all' && (
|
||||
<div className="text-center text-sm text-muted-foreground py-10">
|
||||
กรุณาเลือกประเภท Prompt เพื่อแก้ไข
|
||||
</div>
|
||||
)}
|
||||
</TabsContent>
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
// File: frontend/components/admin/ai/ContextConfigEditor.tsx
|
||||
// Change Log:
|
||||
// - 2026-06-14: Created ContextConfigEditor component with project/contract loaders and selectors (conforming to task T028)
|
||||
// - 2026-06-15: Added field validation UI with error messages (T069)
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { CheckCircle2, Settings } from 'lucide-react';
|
||||
import { CheckCircle2, Settings, AlertCircle } from 'lucide-react';
|
||||
import { ContextConfig } from '@/lib/types/ai-prompts';
|
||||
import { projectService } from '@/lib/services/project.service';
|
||||
import { contractService } from '@/lib/services/contract.service';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface ContextConfigEditorProps {
|
||||
initialConfig: ContextConfig | null;
|
||||
@@ -40,6 +43,7 @@ export default function ContextConfigEditor({
|
||||
onSave,
|
||||
isSaving,
|
||||
}: ContextConfigEditorProps) {
|
||||
const { t } = useTranslation('ai');
|
||||
const [projects, setProjects] = useState<ProjectOption[]>([]);
|
||||
const [contracts, setContracts] = useState<ContractOption[]>([]);
|
||||
const [filteredContracts, setFilteredContracts] = useState<ContractOption[]>([]);
|
||||
@@ -51,6 +55,31 @@ export default function ContextConfigEditor({
|
||||
const [language, setLanguage] = useState<string>('th');
|
||||
const [outputLanguage, setOutputLanguage] = useState<string>('th');
|
||||
|
||||
// Validation errors (T069)
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
|
||||
const validate = (): boolean => {
|
||||
const newErrors: Record<string, string> = {};
|
||||
|
||||
// Validate pageSize
|
||||
if (pageSize < 1 || pageSize > 1000) {
|
||||
newErrors.pageSize = t('prompt_management.pageSize_invalid');
|
||||
}
|
||||
|
||||
// Validate language
|
||||
if (!language || language.trim().length === 0) {
|
||||
newErrors.language = t('prompt_management.language_required');
|
||||
}
|
||||
|
||||
// Validate outputLanguage
|
||||
if (!outputLanguage || outputLanguage.trim().length === 0) {
|
||||
newErrors.outputLanguage = t('prompt_management.output_language_required');
|
||||
}
|
||||
|
||||
setErrors(newErrors);
|
||||
return Object.keys(newErrors).length === 0;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
@@ -117,6 +146,9 @@ export default function ContextConfigEditor({
|
||||
}, [projectId, contracts, contractId]);
|
||||
|
||||
const handleSave = () => {
|
||||
if (!validate()) {
|
||||
return;
|
||||
}
|
||||
const config: ContextConfig = {
|
||||
filter: {
|
||||
projectId: projectId === 'all' ? null : projectId,
|
||||
@@ -182,24 +214,36 @@ export default function ContextConfigEditor({
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3.5">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
ประวัติอ้างอิง (Page Size)
|
||||
{t('prompt_management.page_size')}
|
||||
</label>
|
||||
<Input
|
||||
type="number"
|
||||
min={1}
|
||||
max={20}
|
||||
max={1000}
|
||||
value={pageSize}
|
||||
onChange={(e) => setPageSize(Math.max(1, Number(e.target.value)))}
|
||||
className="bg-background/50 border-border/50 text-sm focus-visible:ring-primary/30"
|
||||
onChange={(e) => {
|
||||
setPageSize(Math.max(1, Number(e.target.value)));
|
||||
setErrors((prev) => ({ ...prev, pageSize: '' }));
|
||||
}}
|
||||
className={cn(
|
||||
'bg-background/50 border-border/50 text-sm focus-visible:ring-primary/30',
|
||||
errors.pageSize && 'border-destructive'
|
||||
)}
|
||||
/>
|
||||
{errors.pageSize && (
|
||||
<div className="flex items-center gap-1 text-[10px] text-destructive">
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
{errors.pageSize}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
ภาษาต้นทาง (Language)
|
||||
{t('prompt_management.language')}
|
||||
</label>
|
||||
<Select value={language} onValueChange={setLanguage}>
|
||||
<SelectTrigger className="bg-background/50 border-border/50 backdrop-blur-sm">
|
||||
<Select value={language} onValueChange={(val) => { setLanguage(val); setErrors((prev) => ({ ...prev, language: '' })); }}>
|
||||
<SelectTrigger className={cn('bg-background/50 border-border/50 backdrop-blur-sm', errors.language && 'border-destructive')}>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -207,14 +251,20 @@ export default function ContextConfigEditor({
|
||||
<SelectItem value="en">English (EN)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{errors.language && (
|
||||
<div className="flex items-center gap-1 text-[10px] text-destructive">
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
{errors.language}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
ภาษาปลายทาง (Output)
|
||||
{t('prompt_management.output_language')}
|
||||
</label>
|
||||
<Select value={outputLanguage} onValueChange={setOutputLanguage}>
|
||||
<SelectTrigger className="bg-background/50 border-border/50 backdrop-blur-sm">
|
||||
<Select value={outputLanguage} onValueChange={(val) => { setOutputLanguage(val); setErrors((prev) => ({ ...prev, outputLanguage: '' })); }}>
|
||||
<SelectTrigger className={cn('bg-background/50 border-border/50 backdrop-blur-sm', errors.outputLanguage && 'border-destructive')}>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -222,6 +272,12 @@ export default function ContextConfigEditor({
|
||||
<SelectItem value="en">English (EN)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{errors.outputLanguage && (
|
||||
<div className="flex items-center gap-1 text-[10px] text-destructive">
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
{errors.outputLanguage}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@@ -1,40 +1,52 @@
|
||||
// File: frontend/components/admin/ai/PromptTypeDropdown.tsx
|
||||
// Change Log:
|
||||
// - 2026-06-14: Created PromptTypeDropdown component (conforming to task T016)
|
||||
// - 2026-06-15: Added "All Types" option (T064)
|
||||
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { PromptType } from '@/lib/types/ai-prompts';
|
||||
|
||||
interface PromptTypeDropdownProps {
|
||||
value: PromptType;
|
||||
onChange: (value: PromptType) => void;
|
||||
value: PromptType | 'all';
|
||||
onChange: (value: PromptType | 'all') => void;
|
||||
disabled?: boolean;
|
||||
showAllOption?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* คอมโพเนนต์ Dropdown สำหรับเลือกประเภทของ AI Prompt
|
||||
* รองรับ: OCR Extraction, RAG Query, RAG Prep, และ Document Classification
|
||||
* และ "All Types" สำหรับดูทุกประเภท (T064)
|
||||
*/
|
||||
export default function PromptTypeDropdown({
|
||||
value,
|
||||
onChange,
|
||||
disabled = false,
|
||||
showAllOption = false,
|
||||
}: PromptTypeDropdownProps) {
|
||||
const { t } = useTranslation('ai');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-1.5 w-full">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
ประเภทของพรอมต์ (Prompt Type)
|
||||
{t('prompt_management.prompt_type')}
|
||||
</label>
|
||||
<Select
|
||||
value={value}
|
||||
onValueChange={(val) => onChange(val as PromptType)}
|
||||
onValueChange={(val) => onChange(val as PromptType | 'all')}
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectTrigger className="w-full bg-background/50 border-border/50 backdrop-blur-sm">
|
||||
<SelectValue placeholder="เลือกประเภทพรอมต์..." />
|
||||
<SelectValue placeholder={t('prompt_management.prompt_type')} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{showAllOption && (
|
||||
<SelectItem value="all">
|
||||
{t('prompt_management.all_types')}
|
||||
</SelectItem>
|
||||
)}
|
||||
<SelectItem value="ocr_extraction">
|
||||
สกัดข้อความ OCR (OCR Extraction)
|
||||
</SelectItem>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// File: frontend/components/admin/ai/RuntimeParametersPanel.tsx
|
||||
// Change Log:
|
||||
// - 2026-06-14: Created RuntimeParametersPanel component for managing sandbox parameters (conforming to task T048)
|
||||
// - 2026-06-15: Added i18n support for Runtime Parameters label (T072)
|
||||
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
@@ -26,6 +28,7 @@ const PROFILE_OPTIONS = [
|
||||
];
|
||||
|
||||
export default function RuntimeParametersPanel({ onProfileChange }: RuntimeParametersPanelProps) {
|
||||
const { t } = useTranslation('ai');
|
||||
const [selectedProfile, setSelectedProfile] = useState<string>('standard');
|
||||
const [params, setParams] = useState<SandboxProfileParams | null>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
@@ -132,7 +135,7 @@ export default function RuntimeParametersPanel({ onProfileChange }: RuntimeParam
|
||||
<div className="space-y-1">
|
||||
<CardTitle className="flex items-center gap-2 text-sm font-semibold tracking-wide text-foreground">
|
||||
<Sliders className="h-4 w-4 text-primary" />
|
||||
จัดการพารามิเตอร์รันไทม์ (Runtime Parameters)
|
||||
{t('sandbox_test.runtime_parameters')}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-xs">
|
||||
ปรับเปลี่ยนพารามิเตอร์การทำงานของโมเดล AI ในระบบทดสอบ Sandbox
|
||||
|
||||
@@ -0,0 +1,478 @@
|
||||
// File: frontend/components/admin/ai/SandboxTestArea.tsx
|
||||
// Change Log:
|
||||
// - 2026-06-15: Created SandboxTestArea component with UI elements for 3-step sandbox testing (T038)
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { adminAiService } from '@/lib/services/admin-ai.service';
|
||||
import { useProjects, useContracts } from '@/hooks/use-master-data';
|
||||
import { toast } from 'sonner';
|
||||
import {
|
||||
Upload,
|
||||
Play,
|
||||
FileText,
|
||||
FileJson,
|
||||
Database,
|
||||
ArrowRight,
|
||||
Loader2,
|
||||
CheckCircle,
|
||||
} from 'lucide-react';
|
||||
|
||||
interface SandboxTestAreaProps {
|
||||
promptType: string;
|
||||
selectedVersionNumber?: number;
|
||||
onActivateVersion?: (versionNumber: number) => void;
|
||||
}
|
||||
|
||||
interface ProjectOption {
|
||||
publicId: string;
|
||||
projectCode: string;
|
||||
projectName: string;
|
||||
}
|
||||
|
||||
interface ContractOption {
|
||||
publicId: string;
|
||||
contractCode: string;
|
||||
contractName: string;
|
||||
}
|
||||
|
||||
interface SandboxJobResult {
|
||||
ocrText?: string;
|
||||
answer?: string;
|
||||
status?: string;
|
||||
errorMessage?: string;
|
||||
ragChunks?: Array<{ text: string; summary: string }>;
|
||||
ragVectors?: unknown[];
|
||||
}
|
||||
|
||||
export default function SandboxTestArea({
|
||||
promptType: _promptType,
|
||||
selectedVersionNumber,
|
||||
onActivateVersion,
|
||||
}: SandboxTestAreaProps) {
|
||||
// Master data state
|
||||
const [selectedProject, setSelectedProject] = useState<string>('');
|
||||
const [selectedContract, setSelectedContract] = useState<string>('');
|
||||
const { data: projectsData } = useProjects();
|
||||
const projects = Array.isArray(projectsData) ? (projectsData as ProjectOption[]) : [];
|
||||
const { data: contractsData } = useContracts(selectedProject);
|
||||
const contracts = Array.isArray(contractsData) ? (contractsData as ContractOption[]) : [];
|
||||
|
||||
// Sandbox states
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [ocrEngine, setOcrEngine] = useState<string>('auto');
|
||||
const [currentStep, setCurrentStep] = useState<number>(1);
|
||||
const [jobStatus, setJobStatus] = useState<'idle' | 'running' | 'completed' | 'failed'>('idle');
|
||||
const [progress, setProgress] = useState<number>(0);
|
||||
const [statusText, setStatusText] = useState<string>('');
|
||||
|
||||
// Results cache
|
||||
const [requestPublicId, setRequestPublicId] = useState<string | null>(null);
|
||||
const [ocrText, setOcrText] = useState<string>('');
|
||||
const [extractedMetadata, setExtractedMetadata] = useState<Record<string, unknown> | null>(null);
|
||||
const [ragChunks, setRagChunks] = useState<Array<{ text: string; summary: string }> | null>(null);
|
||||
const [ragVectorsCount, setRagVectorsCount] = useState<number>(0);
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files && e.target.files[0]) {
|
||||
setFile(e.target.files[0]);
|
||||
setOcrText('');
|
||||
setExtractedMetadata(null);
|
||||
setRagChunks(null);
|
||||
setRequestPublicId(null);
|
||||
setCurrentStep(1);
|
||||
setJobStatus('idle');
|
||||
setProgress(0);
|
||||
}
|
||||
};
|
||||
|
||||
const pollJobStatus = (id: string, step: number, onSuccess: (result: SandboxJobResult) => void) => {
|
||||
let interval = setInterval(async () => {
|
||||
try {
|
||||
const res = await adminAiService.getSandboxJobStatus(id);
|
||||
if (res.status === 'completed') {
|
||||
clearInterval(interval);
|
||||
setJobStatus('completed');
|
||||
setProgress(100);
|
||||
onSuccess(res as SandboxJobResult);
|
||||
} else if (res.status === 'failed') {
|
||||
clearInterval(interval);
|
||||
setJobStatus('failed');
|
||||
setProgress(0);
|
||||
toast.error(res.errorMessage || 'การประมวลผลล้มเหลว');
|
||||
} else if (res.status === 'processing') {
|
||||
setProgress(step === 1 ? 50 : 60);
|
||||
setStatusText('กำลังประมวลผล...');
|
||||
}
|
||||
} catch (_err) {
|
||||
clearInterval(interval);
|
||||
setJobStatus('failed');
|
||||
setProgress(0);
|
||||
toast.error('ไม่สามารถดึงสถานะงานได้');
|
||||
}
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const handleRunOcr = async () => {
|
||||
if (!file) {
|
||||
toast.error('กรุณาเลือกไฟล์ PDF สำหรับทดสอบ');
|
||||
return;
|
||||
}
|
||||
setJobStatus('running');
|
||||
setProgress(15);
|
||||
setStatusText('กำลังอัปโหลดและส่งเอกสารเข้าคิว OCR...');
|
||||
try {
|
||||
const res = await adminAiService.submitSandboxOcr(file, ocrEngine);
|
||||
setRequestPublicId(res.requestPublicId);
|
||||
pollJobStatus(res.requestPublicId, 1, (result) => {
|
||||
setOcrText(result.ocrText || '');
|
||||
setCurrentStep(2);
|
||||
toast.success('ทำ OCR สำเร็จแล้ว สามารถทำการสกัดข้อมูลต่อได้');
|
||||
});
|
||||
} catch (_err) {
|
||||
setJobStatus('failed');
|
||||
toast.error('เกิดข้อผิดพลาดในการรัน OCR');
|
||||
}
|
||||
};
|
||||
|
||||
const handleRunExtract = async () => {
|
||||
if (!requestPublicId) {
|
||||
toast.error('กรุณาทำ OCR ก่อน');
|
||||
return;
|
||||
}
|
||||
if (!selectedProject) {
|
||||
toast.error('กรุณาเลือกโครงการสำหรับทดสอบ');
|
||||
return;
|
||||
}
|
||||
setJobStatus('running');
|
||||
setProgress(20);
|
||||
setStatusText('กำลังประมวลผลการสกัดข้อมูลเมตาดาต้า...');
|
||||
try {
|
||||
const res = await adminAiService.submitSandboxAiExtract(
|
||||
requestPublicId,
|
||||
selectedVersionNumber,
|
||||
selectedProject,
|
||||
selectedContract || undefined
|
||||
);
|
||||
pollJobStatus(res.requestPublicId, 2, (result) => {
|
||||
let parsed = null;
|
||||
try {
|
||||
parsed = result.answer ? JSON.parse(result.answer) : null;
|
||||
} catch {
|
||||
parsed = { error: 'ผลลัพธ์ไม่ใช่ JSON ที่ถูกต้อง', raw: result.answer };
|
||||
}
|
||||
setExtractedMetadata(parsed);
|
||||
setCurrentStep(3);
|
||||
toast.success('สกัดข้อมูลเมตาดาต้าสำเร็จ สามารถทดสอบ RAG Prep ต่อได้');
|
||||
});
|
||||
} catch (_err) {
|
||||
setJobStatus('failed');
|
||||
toast.error('เกิดข้อผิดพลาดในการสกัดข้อมูล');
|
||||
}
|
||||
};
|
||||
|
||||
const handleRunRagPrep = async () => {
|
||||
if (!ocrText) {
|
||||
toast.error('ไม่มีข้อความ OCR สำหรับทดสอบ');
|
||||
return;
|
||||
}
|
||||
setJobStatus('running');
|
||||
setProgress(30);
|
||||
setStatusText('กำลังประมวลผลการทำ Semantic Chunking และสร้างเวกเตอร์ RAG...');
|
||||
try {
|
||||
const res = await adminAiService.submitSandboxRagPrep(ocrText);
|
||||
pollJobStatus(res.jobId, 3, (result) => {
|
||||
setRagChunks(result.ragChunks || []);
|
||||
setRagVectorsCount(result.ragVectors ? result.ragVectors.length : 0);
|
||||
toast.success('วิเคราะห์การเตรียมข้อมูล RAG สำเร็จ');
|
||||
});
|
||||
} catch (_err) {
|
||||
setJobStatus('failed');
|
||||
toast.error('เกิดข้อผิดพลาดในการทำ RAG Prep');
|
||||
}
|
||||
};
|
||||
|
||||
const handleActivate = () => {
|
||||
if (selectedVersionNumber && onActivateVersion) {
|
||||
onActivateVersion(selectedVersionNumber);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="border border-border/50 bg-background/30 backdrop-blur-md transition-all duration-300 hover:shadow-md">
|
||||
<CardHeader className="pb-3 border-b border-border/10">
|
||||
<CardTitle className="flex items-center gap-2 text-sm font-semibold tracking-wide text-foreground">
|
||||
<Play className="h-4 w-4 text-primary" />
|
||||
รันบอร์ดทดลองการทำงาน (3-Step Sandbox Testing)
|
||||
</CardTitle>
|
||||
<CardDescription className="text-xs">
|
||||
ทดสอบความถูกต้องของเวอร์ชันพรอมต์จำลองกระบวนการจริง (OCR → AI Extract → RAG Prep)
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-5 space-y-6">
|
||||
<div className="flex flex-wrap items-center gap-4 border-b border-border/10 pb-4">
|
||||
<div className="flex-1 min-w-[200px] space-y-1">
|
||||
<Label className="text-[11px] font-semibold text-muted-foreground">โครงการสำหรับสกัดบริบท</Label>
|
||||
<Select value={selectedProject} onValueChange={setSelectedProject}>
|
||||
<SelectTrigger className="h-8 text-xs bg-background/50 border-border/50">
|
||||
<SelectValue placeholder="เลือกโครงการ..." />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{projects.map((p) => (
|
||||
<SelectItem key={p.publicId} value={p.publicId} className="text-xs">
|
||||
{p.projectName}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex-1 min-w-[200px] space-y-1">
|
||||
<Label className="text-[11px] font-semibold text-muted-foreground">สัญญา (ถ้ามี)</Label>
|
||||
<Select value={selectedContract} onValueChange={setSelectedContract} disabled={!selectedProject}>
|
||||
<SelectTrigger className="h-8 text-xs bg-background/50 border-border/50">
|
||||
<SelectValue placeholder="เลือกสัญญา..." />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{contracts.map((c) => (
|
||||
<SelectItem key={c.publicId} value={c.publicId} className="text-xs">
|
||||
{c.contractName}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="w-[150px] space-y-1">
|
||||
<Label className="text-[11px] font-semibold text-muted-foreground">OCR Engine</Label>
|
||||
<Select value={ocrEngine} onValueChange={setOcrEngine}>
|
||||
<SelectTrigger className="h-8 text-xs bg-background/50 border-border/50">
|
||||
<SelectValue placeholder="เลือกเอนจิน..." />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="auto" className="text-xs">Auto (Baseline)</SelectItem>
|
||||
<SelectItem value="tesseract" className="text-xs">Tesseract (CPU)</SelectItem>
|
||||
<SelectItem value="np-dms-ocr" className="text-xs">Typhoon OCR (GPU)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row items-center gap-4 bg-background/40 p-4 border border-border/30 rounded-lg">
|
||||
<div className="flex items-center gap-3 flex-1">
|
||||
<div className="p-2 bg-primary/10 rounded">
|
||||
<Upload className="h-5 w-5 text-primary" />
|
||||
</div>
|
||||
<div className="space-y-0.5">
|
||||
<Label className="text-xs font-bold text-foreground">อัปโหลดไฟล์สำหรับทดสอบ Sandbox</Label>
|
||||
<p className="text-[10px] text-muted-foreground">เลือกไฟล์ PDF วิศวกรรม/ก่อสร้าง ขนาดไม่เกิน 50MB</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative overflow-hidden cursor-pointer bg-primary/90 hover:bg-primary/95 text-primary-foreground font-semibold px-4 py-2 rounded text-xs select-none flex items-center gap-2">
|
||||
<span>เลือกไฟล์เอกสาร...</span>
|
||||
<input
|
||||
type="file"
|
||||
accept=".pdf"
|
||||
onChange={handleFileChange}
|
||||
className="absolute inset-0 opacity-0 cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{file && (
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground font-mono bg-secondary/20 border border-border/50 px-3 py-1.5 rounded">
|
||||
<FileText className="h-4 w-4 text-primary shrink-0" />
|
||||
<span className="truncate flex-1">{file.name}</span>
|
||||
<span>({(file.size / (1024 * 1024)).toFixed(2)} MB)</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Status indicator */}
|
||||
{jobStatus === 'running' && (
|
||||
<div className="space-y-2.5 p-4 border border-primary/20 bg-primary/[0.02] rounded-lg">
|
||||
<div className="flex justify-between items-center text-xs">
|
||||
<span className="flex items-center font-semibold text-primary">
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
|
||||
{statusText}
|
||||
</span>
|
||||
<span className="font-mono font-bold text-primary">{progress}%</span>
|
||||
</div>
|
||||
<Progress value={progress} className="h-1.5" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Steps navigation and panels */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 pt-2">
|
||||
{/* Step buttons */}
|
||||
<div className="lg:col-span-3 flex lg:flex-col gap-2.5">
|
||||
<Button
|
||||
variant={currentStep === 1 ? 'default' : 'outline'}
|
||||
disabled={jobStatus === 'running' || !file}
|
||||
onClick={() => setCurrentStep(1)}
|
||||
className="w-full h-9 justify-start text-xs font-semibold"
|
||||
>
|
||||
<Badge className="mr-2 h-4 min-w-4 px-1 flex items-center justify-center text-[9px] bg-secondary text-secondary-foreground select-none">1</Badge>
|
||||
Step 1: Run OCR
|
||||
</Button>
|
||||
<Button
|
||||
variant={currentStep === 2 ? 'default' : 'outline'}
|
||||
disabled={jobStatus === 'running' || !ocrText}
|
||||
onClick={() => setCurrentStep(2)}
|
||||
className="w-full h-9 justify-start text-xs font-semibold"
|
||||
>
|
||||
<Badge className="mr-2 h-4 min-w-4 px-1 flex items-center justify-center text-[9px] bg-secondary text-secondary-foreground select-none">2</Badge>
|
||||
Step 2: AI Extract
|
||||
</Button>
|
||||
<Button
|
||||
variant={currentStep === 3 ? 'default' : 'outline'}
|
||||
disabled={jobStatus === 'running' || !extractedMetadata}
|
||||
onClick={() => setCurrentStep(3)}
|
||||
className="w-full h-9 justify-start text-xs font-semibold"
|
||||
>
|
||||
<Badge className="mr-2 h-4 min-w-4 px-1 flex items-center justify-center text-[9px] bg-secondary text-secondary-foreground select-none">3</Badge>
|
||||
Step 3: RAG Prep
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Step detail views */}
|
||||
<div className="lg:col-span-9 border border-border/30 rounded-lg p-4 bg-background/50 min-h-[300px] flex flex-col justify-between">
|
||||
{currentStep === 1 && (
|
||||
<div className="space-y-4 flex-1 flex flex-col justify-between">
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-xs font-bold text-foreground flex items-center gap-1.5">
|
||||
<FileText className="h-4 w-4 text-primary" />
|
||||
Step 1: สกัดข้อความ OCR (OCR Extraction)
|
||||
</h4>
|
||||
<p className="text-[11px] text-muted-foreground leading-normal">
|
||||
รันเอนจินสกัดข้อความเพื่อดึงตัวหนังสือดิบออกมาจากหน้าไฟล์ PDF ที่ส่งขึ้นไป สามารถดูผลลัพธ์ข้อความดิบเพื่อประเมินความคมชัดของ OCR
|
||||
</p>
|
||||
</div>
|
||||
{ocrText ? (
|
||||
<div className="flex-1 min-h-[150px] max-h-[250px] overflow-y-auto rounded bg-secondary/30 border border-border/50 p-3 font-mono text-[10px] whitespace-pre-wrap select-text leading-relaxed mt-3">
|
||||
{ocrText}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex-1 min-h-[150px] flex items-center justify-center border border-dashed border-border/70 rounded mt-3 text-xs text-muted-foreground italic">
|
||||
ยังไม่มีข้อมูล OCR คลิก "เริ่มรัน OCR" ด้านล่าง
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-end pt-4 border-t border-border/10 mt-4">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleRunOcr}
|
||||
disabled={jobStatus === 'running' || !file}
|
||||
className="h-8 text-xs"
|
||||
>
|
||||
เริ่มรัน OCR (Run OCR)
|
||||
<ArrowRight className="ml-1.5 h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentStep === 2 && (
|
||||
<div className="space-y-4 flex-1 flex flex-col justify-between">
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-xs font-bold text-foreground flex items-center gap-1.5">
|
||||
<FileJson className="h-4 w-4 text-primary" />
|
||||
Step 2: สกัดข้อมูลอัจฉริยะ (AI Metadata Extraction)
|
||||
</h4>
|
||||
<p className="text-[11px] text-muted-foreground leading-normal">
|
||||
ส่งข้อความ OCR พร้อมบริบท Master data (โครงการ/สัญญา) เข้าไปประมวลผลร่วมกับโมเดลหลักและเวอร์ชันพรอมต์ที่เลือก เพื่อแปลงเป็นโครงสร้างข้อมูล JSON อัจฉริยะ
|
||||
</p>
|
||||
</div>
|
||||
{extractedMetadata ? (
|
||||
<div className="flex-1 min-h-[150px] max-h-[250px] overflow-y-auto rounded bg-secondary/30 border border-border/50 p-3 font-mono text-[10px] text-emerald-400 select-text leading-relaxed mt-3">
|
||||
<pre>{JSON.stringify(extractedMetadata, null, 2)}</pre>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex-1 min-h-[150px] flex items-center justify-center border border-dashed border-border/70 rounded mt-3 text-xs text-muted-foreground italic">
|
||||
ยังไม่มีผลลัพธ์การสกัดข้อมูล คลิก "เริ่มรันสกัดข้อมูล" ด้านล่าง
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-between items-center pt-4 border-t border-border/10 mt-4">
|
||||
{selectedVersionNumber && onActivateVersion && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleActivate}
|
||||
className="h-8 text-xs border-emerald-500/30 text-emerald-500 hover:bg-emerald-500/10"
|
||||
>
|
||||
<CheckCircle className="mr-1.5 h-3.5 w-3.5" />
|
||||
เปิดใช้งานเวอร์ชัน v{selectedVersionNumber} ทันที
|
||||
</Button>
|
||||
)}
|
||||
<div className="flex-1 text-right">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleRunExtract}
|
||||
disabled={jobStatus === 'running' || !ocrText}
|
||||
className="h-8 text-xs bg-primary hover:bg-primary/95 text-primary-foreground"
|
||||
>
|
||||
เริ่มรันสกัดข้อมูล (Run AI Extract)
|
||||
<ArrowRight className="ml-1.5 h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentStep === 3 && (
|
||||
<div className="space-y-4 flex-1 flex flex-col justify-between">
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-xs font-bold text-foreground flex items-center gap-1.5">
|
||||
<Database className="h-4 w-4 text-primary" />
|
||||
Step 3: เตรียมฐานข้อมูลค้นหา (RAG Prep Sandbox)
|
||||
</h4>
|
||||
<p className="text-[11px] text-muted-foreground leading-normal">
|
||||
จำลองกระบวนการแบ่งข้อความออกเป็นส่วนๆ (Semantic Chunking) ตามความเหมาะสมทางภาษาและความหมายของเอกสาร พร้อมแสดงขนาดเวกเตอร์ Dense/Sparse ที่สกัดสำหรับใช้ใน Qdrant
|
||||
</p>
|
||||
</div>
|
||||
{ragChunks ? (
|
||||
<div className="flex-1 flex flex-col gap-3 mt-3 overflow-hidden">
|
||||
<div className="flex justify-between items-center bg-secondary/40 border border-border/50 px-3 py-2 rounded text-xs select-none">
|
||||
<span className="font-semibold text-foreground flex items-center gap-1">
|
||||
<CheckCircle className="h-4 w-4 text-emerald-500" />
|
||||
ทำเวกเตอร์สำเร็จ: {ragVectorsCount} เวกเตอร์
|
||||
</span>
|
||||
<Badge variant="outline" className="text-[10px] border-border/50"> chunks: {ragChunks.length}</Badge>
|
||||
</div>
|
||||
<div className="flex-1 min-h-[120px] max-h-[200px] overflow-y-auto space-y-2 mt-1">
|
||||
{ragChunks.map((chunk, idx) => (
|
||||
<div key={idx} className="bg-background/80 border border-border/30 rounded p-2.5 text-[10px] space-y-1 hover:border-primary/20 transition-all select-text">
|
||||
<div className="flex justify-between items-center text-primary font-bold">
|
||||
<span>#Chunk {idx + 1}</span>
|
||||
<Badge className="text-[8px] py-0 px-1 select-none">{chunk.summary || 'หัวข้อหลัก'}</Badge>
|
||||
</div>
|
||||
<p className="leading-relaxed text-muted-foreground">{chunk.text}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex-1 min-h-[150px] flex items-center justify-center border border-dashed border-border/70 rounded mt-3 text-xs text-muted-foreground italic">
|
||||
ยังไม่มีผลลัพธ์ RAG Prep คลิก "เริ่มทดสอบ RAG Prep" ด้านล่าง
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-end pt-4 border-t border-border/10 mt-4">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleRunRagPrep}
|
||||
disabled={jobStatus === 'running' || !ocrText}
|
||||
className="h-8 text-xs bg-emerald-500 hover:bg-emerald-600 text-white"
|
||||
>
|
||||
เริ่มทดสอบ RAG Prep (Test RAG Prep)
|
||||
<CheckCircle className="ml-1.5 h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
// File: frontend/components/admin/ai/VersionHistory.tsx
|
||||
// Change Log:
|
||||
// - 2026-06-14: Created VersionHistory component with type filtering and nice badges (conforming to task T017)
|
||||
// - 2026-06-15: Added All Types view grouped by prompt type (T065)
|
||||
// - 2026-06-15: Added pagination (20 versions/page) (T075)
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { CheckCircle2, Trash2, BookOpen, Clock, StickyNote } from 'lucide-react';
|
||||
import { CheckCircle2, Trash2, BookOpen, Clock, StickyNote, Folder, ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
import { PromptVersion } from '@/lib/types/ai-prompts';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
@@ -18,10 +21,12 @@ interface VersionHistoryProps {
|
||||
onDeleteVersion: (versionNumber: number) => void;
|
||||
isActivating: boolean;
|
||||
isDeleting: boolean;
|
||||
showAllTypes?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* คอมโพเนนต์แสดงประวัติเวอร์ชันของพรอมต์ตามประเภทที่กรองไว้
|
||||
* หรือแสดงทุกประเภทแบบจัดกลุ่ม (T065)
|
||||
* แสดงรายการเวอร์ชันพร้อมปุ่มพรีโหลด เปิดใช้งาน และลบเวอร์ชันที่ไม่ต้องการ
|
||||
*/
|
||||
export default function VersionHistory({
|
||||
@@ -32,31 +37,162 @@ export default function VersionHistory({
|
||||
onDeleteVersion,
|
||||
isActivating,
|
||||
isDeleting,
|
||||
showAllTypes = false,
|
||||
}: VersionHistoryProps) {
|
||||
const { t } = useTranslation('ai');
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const PAGE_SIZE = 20; // T075: 20 versions per page
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex h-[300px] items-center justify-center text-sm text-muted-foreground">
|
||||
<Clock className="mr-2 h-4 w-4 animate-spin text-primary" />
|
||||
กำลังโหลดประวัติเวอร์ชัน...
|
||||
{t('prompt_management.version_history')}...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Group versions by prompt type when showing all types
|
||||
const groupedVersions = showAllTypes
|
||||
? versions.reduce((acc, version) => {
|
||||
const type = version.promptType;
|
||||
if (!acc[type]) {
|
||||
acc[type] = [];
|
||||
}
|
||||
acc[type].push(version);
|
||||
return acc;
|
||||
}, {} as Record<string, PromptVersion[]>)
|
||||
: null;
|
||||
|
||||
const getPromptTypeLabel = (type: string): string => {
|
||||
const labels: Record<string, string> = {
|
||||
ocr_extraction: 'สกัดข้อความ OCR (OCR Extraction)',
|
||||
rag_query_prompt: 'ค้นหาข้อมูล RAG (RAG Query)',
|
||||
rag_prep_prompt: 'เตรียมข้อมูล RAG (RAG Prep)',
|
||||
classification_prompt: 'จำแนกประเภทเอกสาร (Classification)',
|
||||
};
|
||||
return labels[type] || type;
|
||||
};
|
||||
|
||||
// Pagination logic (T075)
|
||||
const totalPages = Math.ceil(versions.length / PAGE_SIZE);
|
||||
const startIndex = (currentPage - 1) * PAGE_SIZE;
|
||||
const endIndex = startIndex + PAGE_SIZE;
|
||||
const paginatedVersions = versions.slice(startIndex, endIndex);
|
||||
|
||||
const handlePreviousPage = () => {
|
||||
setCurrentPage((prev) => Math.max(1, prev - 1));
|
||||
};
|
||||
|
||||
const handleNextPage = () => {
|
||||
setCurrentPage((prev) => Math.min(totalPages, prev + 1));
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="border border-border/50 bg-background/30 backdrop-blur-md transition-all duration-300 hover:shadow-md">
|
||||
<CardHeader className="pb-3 border-b border-border/10">
|
||||
<CardTitle className="flex items-center gap-2 text-sm font-semibold tracking-wide text-foreground">
|
||||
<BookOpen className="h-4 w-4 text-primary" />
|
||||
ประวัติเวอร์ชัน (Version History)
|
||||
{showAllTypes ? `${t('prompt_management.version_history')} (${t('prompt_management.all_types')})` : t('prompt_management.version_history')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-4 px-3 sm:px-4 max-h-[500px] overflow-y-auto space-y-3">
|
||||
{versions.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center py-10 text-center text-xs text-muted-foreground italic">
|
||||
ไม่พบเวอร์ชันอื่นในระบบสำหรับประเภทนี้
|
||||
{t('prompt_management.no_versions')}
|
||||
</div>
|
||||
) : showAllTypes && groupedVersions ? (
|
||||
// Grouped view by prompt type (with pagination applied to each group)
|
||||
Object.entries(groupedVersions).map(([promptType, typeVersions]) => {
|
||||
const paginatedGroupVersions = typeVersions.slice(startIndex, endIndex);
|
||||
return (
|
||||
<div key={promptType} className="space-y-2">
|
||||
<div className="flex items-center gap-2 text-xs font-semibold text-foreground/80 bg-muted/30 px-2 py-1.5 rounded">
|
||||
<Folder className="h-3.5 w-3.5 text-primary" />
|
||||
{getPromptTypeLabel(promptType)}
|
||||
</div>
|
||||
{paginatedGroupVersions.map((version) => {
|
||||
const isActive = version.isActive === true;
|
||||
return (
|
||||
<div
|
||||
key={version.versionNumber}
|
||||
className={cn(
|
||||
'group relative rounded-lg border border-border/30 bg-background/50 p-3.5 transition-all duration-200 hover:border-primary/30 hover:bg-background/80',
|
||||
isActive && 'border-emerald-500/20 bg-emerald-500/[0.02]'
|
||||
)}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-mono text-sm font-bold text-foreground">
|
||||
v{version.versionNumber}
|
||||
</span>
|
||||
{isActive ? (
|
||||
<Badge className="border-emerald-500/20 bg-emerald-500/10 text-emerald-500 hover:bg-emerald-500/20 text-[10px] py-0 px-1.5 flex items-center gap-1 select-none">
|
||||
<CheckCircle2 className="h-3 w-3" />
|
||||
{t('prompt_management.is_active')}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="outline" className="text-[10px] text-muted-foreground border-border/50 bg-background/40 select-none">
|
||||
ร่าง (Inactive)
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 text-[11px] text-muted-foreground">
|
||||
<span className="flex items-center gap-1">
|
||||
<Clock className="h-3 w-3" />
|
||||
สร้าง: {new Date(version.createdAt).toLocaleString('th-TH')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 opacity-90 sm:opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 text-[10px] text-muted-foreground hover:bg-secondary"
|
||||
onClick={() => onLoadTemplate(version)}
|
||||
>
|
||||
โหลด (Load)
|
||||
</Button>
|
||||
{!isActive && (
|
||||
<>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
disabled={isActivating}
|
||||
className="h-7 text-[10px] text-emerald-500 hover:text-emerald-600 hover:bg-emerald-500/10"
|
||||
onClick={() => onActivateVersion(version.versionNumber)}
|
||||
>
|
||||
{t('prompt_management.activate_version')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
disabled={isDeleting}
|
||||
className="h-7 w-7 text-destructive hover:bg-destructive/10"
|
||||
onClick={() => onDeleteVersion(version.versionNumber)}
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{version.manualNote && (
|
||||
<div className="mt-2.5 rounded bg-muted/30 p-2 border border-border/10 flex gap-1.5 items-start text-[11px] text-muted-foreground select-text">
|
||||
<StickyNote className="h-3.5 w-3.5 text-amber-500 shrink-0 mt-0.5" />
|
||||
<p className="leading-relaxed whitespace-pre-wrap">{version.manualNote}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
versions.map((version) => {
|
||||
// Single type view with pagination (T075)
|
||||
paginatedVersions.map((version) => {
|
||||
const isActive = version.isActive === true;
|
||||
return (
|
||||
<div
|
||||
@@ -75,7 +211,7 @@ export default function VersionHistory({
|
||||
{isActive ? (
|
||||
<Badge className="border-emerald-500/20 bg-emerald-500/10 text-emerald-500 hover:bg-emerald-500/20 text-[10px] py-0 px-1.5 flex items-center gap-1 select-none">
|
||||
<CheckCircle2 className="h-3 w-3" />
|
||||
ใช้งานจริง (Active)
|
||||
{t('prompt_management.is_active')}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="outline" className="text-[10px] text-muted-foreground border-border/50 bg-background/40 select-none">
|
||||
@@ -108,7 +244,7 @@ export default function VersionHistory({
|
||||
className="h-7 text-[10px] text-emerald-500 hover:text-emerald-600 hover:bg-emerald-500/10"
|
||||
onClick={() => onActivateVersion(version.versionNumber)}
|
||||
>
|
||||
ใช้งาน (Activate)
|
||||
{t('prompt_management.activate_version')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -133,6 +269,34 @@ export default function VersionHistory({
|
||||
);
|
||||
})
|
||||
)}
|
||||
{/* Pagination controls (T075) */}
|
||||
{totalPages > 1 && (
|
||||
<div className="flex items-center justify-between pt-3 border-t border-border/10 mt-3">
|
||||
<div className="text-[10px] text-muted-foreground">
|
||||
หน้า {currentPage} จาก {totalPages} ({versions.length} เวอร์ชัน)
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handlePreviousPage}
|
||||
disabled={currentPage === 1}
|
||||
className="h-7 px-2 text-[10px] border-border/50 bg-background/50"
|
||||
>
|
||||
<ChevronLeft className="h-3 w-3" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleNextPage}
|
||||
disabled={currentPage === totalPages}
|
||||
className="h-7 px-2 text-[10px] border-border/50 bg-background/50"
|
||||
>
|
||||
<ChevronRight className="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// File: components/search/__tests__/filters.test.tsx
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { SearchFilters } from '../filters';
|
||||
|
||||
describe('SearchFilters', () => {
|
||||
const mockOnFilterChange = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('ควร render filters card', () => {
|
||||
const filters = { types: [], statuses: [] };
|
||||
render(<SearchFilters filters={filters} onFilterChange={mockOnFilterChange} />);
|
||||
|
||||
expect(screen.getByText('Filters')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรแสดง Document Type checkboxes', () => {
|
||||
const filters = { types: [], statuses: [] };
|
||||
render(<SearchFilters filters={filters} onFilterChange={mockOnFilterChange} />);
|
||||
|
||||
expect(screen.getByText('Document Type')).toBeInTheDocument();
|
||||
expect(screen.getByText('Correspondence')).toBeInTheDocument();
|
||||
expect(screen.getByText('RFA')).toBeInTheDocument();
|
||||
expect(screen.getByText('Drawing')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรแสดง Status checkboxes', () => {
|
||||
const filters = { types: [], statuses: [] };
|
||||
render(<SearchFilters filters={filters} onFilterChange={mockOnFilterChange} />);
|
||||
|
||||
expect(screen.getByText('Status')).toBeInTheDocument();
|
||||
expect(screen.getByText('Draft')).toBeInTheDocument();
|
||||
expect(screen.getByText('Submitted')).toBeInTheDocument();
|
||||
expect(screen.getByText('Approved')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรแสดง active count badge เมื่อมี filters', () => {
|
||||
const filters = { types: ['correspondence'], statuses: ['DRAFT'] };
|
||||
render(<SearchFilters filters={filters} onFilterChange={mockOnFilterChange} />);
|
||||
|
||||
expect(screen.getByText('2 active')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรไม่แสดง active count badge เมื่อไม่มี filters', () => {
|
||||
const filters = { types: [], statuses: [] };
|
||||
render(<SearchFilters filters={filters} onFilterChange={mockOnFilterChange} />);
|
||||
|
||||
expect(screen.queryByText(/active/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรแสดง Clear all filters button เมื่อมี active filters', () => {
|
||||
const filters = { types: ['correspondence'], statuses: [] };
|
||||
render(<SearchFilters filters={filters} onFilterChange={mockOnFilterChange} />);
|
||||
|
||||
expect(screen.getByText('Clear all filters')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรไม่แสดง Clear all filters button เมื่อไม่มี active filters', () => {
|
||||
const filters = { types: [], statuses: [] };
|
||||
render(<SearchFilters filters={filters} onFilterChange={mockOnFilterChange} />);
|
||||
|
||||
expect(screen.queryByText('Clear all filters')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
// File: components/search/__tests__/results.test.tsx
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { SearchResults } from '../results';
|
||||
|
||||
describe('SearchResults', () => {
|
||||
const mockResults = [
|
||||
{
|
||||
type: 'correspondence',
|
||||
publicId: '019505a1-7c3e-7000-8000-abc123def456',
|
||||
documentNumber: 'CORR-001',
|
||||
title: 'Test Correspondence',
|
||||
description: 'Test description',
|
||||
status: 'DRAFT',
|
||||
createdAt: '2026-06-14T10:00:00Z',
|
||||
highlight: null,
|
||||
},
|
||||
];
|
||||
|
||||
it('ควร render loading state เมื่อ loading=true', () => {
|
||||
render(<SearchResults results={[]} query="" loading={true} />);
|
||||
|
||||
const spinners = screen.getAllByRole('generic', { name: '' }).filter(el => el.querySelector('.animate-spin'));
|
||||
if (spinners.length > 0) {
|
||||
expect(spinners[0]).toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
it('ควร render empty state เมื่อไม่มี results และมี query', () => {
|
||||
render(<SearchResults results={[]} query="test" loading={false} />);
|
||||
|
||||
expect(screen.getByText('No results found for "test"')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควร render empty state เมื่อไม่มี results และไม่มี query', () => {
|
||||
render(<SearchResults results={[]} query="" loading={false} />);
|
||||
|
||||
expect(screen.getByText('Enter a search term to start')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควร render results list เมื่อมี results', () => {
|
||||
render(<SearchResults results={mockResults} query="" loading={false} />);
|
||||
|
||||
expect(screen.getByText('Test Correspondence')).toBeInTheDocument();
|
||||
expect(screen.getByText('CORR-001')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรแสดง document type badge', () => {
|
||||
render(<SearchResults results={mockResults} query="" loading={false} />);
|
||||
|
||||
expect(screen.getByText('Correspondence')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรแสดง status badge', () => {
|
||||
render(<SearchResults results={mockResults} query="" loading={false} />);
|
||||
|
||||
expect(screen.getByText('Draft')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรแสดง description เมื่อมี', () => {
|
||||
render(<SearchResults results={mockResults} query="" loading={false} />);
|
||||
|
||||
expect(screen.getByText('Test description')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ควรแสดง formatted date', () => {
|
||||
render(<SearchResults results={mockResults} query="" loading={false} />);
|
||||
|
||||
expect(screen.getByText(/14 Jun 2026/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -90,7 +90,6 @@ describe('WorkflowLifecycle', () => {
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/files/upload', expect.any(FormData));
|
||||
});
|
||||
expect(onAttachmentsChange).toHaveBeenCalledWith(['019505a1-7c3e-7000-8000-abc123def902']);
|
||||
expect(screen.getByText('uploaded.pdf')).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByRole('button', { name: 'workflow.timeline.removeFile' }));
|
||||
expect(onAttachmentsChange).toHaveBeenLastCalledWith([]);
|
||||
});
|
||||
|
||||
@@ -115,4 +115,79 @@ describe('DSLEditor (T054)', () => {
|
||||
});
|
||||
// ไม่ throw error
|
||||
});
|
||||
|
||||
it('calls onChange callback when editor value changes', async () => {
|
||||
const onChange = vi.fn();
|
||||
render(<DSLEditor initialValue="initial" onChange={onChange} />);
|
||||
|
||||
const editor = screen.getByTestId('monaco-editor');
|
||||
await userEvent.type(editor, ' updated');
|
||||
|
||||
// onChange ถูกเรียกแต่ละ character - check ว่าถูกเรียกและค่าสุดท้ายถูกต้อง
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
expect(onChange).toHaveBeenLastCalledWith(' updated');
|
||||
});
|
||||
|
||||
it('disables Validate and Test buttons when readOnly=true', () => {
|
||||
render(<DSLEditor initialValue="test" readOnly={true} />);
|
||||
|
||||
const validateButton = screen.getByRole('button', { name: /validate/i });
|
||||
const testButton = screen.getByRole('button', { name: /test/i });
|
||||
|
||||
expect(validateButton).toBeDisabled();
|
||||
expect(testButton).toBeDisabled();
|
||||
});
|
||||
|
||||
it('enables Validate and Test buttons when readOnly=false', () => {
|
||||
render(<DSLEditor initialValue="test" readOnly={false} />);
|
||||
|
||||
const validateButton = screen.getByRole('button', { name: /validate/i });
|
||||
const testButton = screen.getByRole('button', { name: /test/i });
|
||||
|
||||
expect(validateButton).not.toBeDisabled();
|
||||
expect(testButton).not.toBeDisabled();
|
||||
});
|
||||
|
||||
it('clears validation result when editor value changes', async () => {
|
||||
mockValidateDSL.mockResolvedValue({ valid: true });
|
||||
const onChange = vi.fn();
|
||||
|
||||
render(<DSLEditor initialValue="test" onChange={onChange} onValidationChange={onValidationChange} />);
|
||||
|
||||
// Validate first
|
||||
await userEvent.click(screen.getByRole('button', { name: /validate/i }));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/valid and ready/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Change editor value
|
||||
const editor = screen.getByTestId('monaco-editor');
|
||||
await userEvent.type(editor, ' updated');
|
||||
|
||||
// Validation result should be cleared
|
||||
expect(screen.queryByText(/valid and ready/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows Test result when Test button is clicked', async () => {
|
||||
render(<DSLEditor initialValue="test" />);
|
||||
|
||||
const testButton = screen.getByRole('button', { name: /test/i });
|
||||
await userEvent.click(testButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Workflow simulation completed successfully/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('updates internal state when initialValue prop changes', () => {
|
||||
const { rerender } = render(<DSLEditor initialValue="initial" />);
|
||||
|
||||
// Mock Monaco editor ไม่ได้ update value เมื่อ initialValue เปลี่ยน
|
||||
// แต่เราสามารถ test ได้โดย render component ใหม่ด้วย initialValue ต่างกัน
|
||||
rerender(<DSLEditor initialValue="updated" />);
|
||||
|
||||
// Component ควร render ได้โดยไม่ throw error
|
||||
const editor = screen.getByTestId('monaco-editor');
|
||||
expect(editor).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
// File: components/workflows/__tests__/visual-builder.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
// Mock ReactFlow to avoid dependency issues
|
||||
vi.mock('reactflow', () => ({
|
||||
ReactFlow: () => null,
|
||||
Controls: () => null,
|
||||
Background: () => null,
|
||||
Panel: () => null,
|
||||
useNodesState: () => [[], () => {}, () => {}],
|
||||
useEdgesState: () => [[], () => {}, () => {}],
|
||||
addEdge: (params: any, edges: any) => [...edges, params],
|
||||
useReactFlow: () => ({ fitView: () => {} }),
|
||||
MarkerType: { ArrowClosed: 'arrowclosed' },
|
||||
ReactFlowProvider: ({ children }: { children: React.ReactNode }) => children,
|
||||
}));
|
||||
|
||||
// Import helper functions after mocking
|
||||
import { createNode, createEdge, parseDSL } from '../visual-builder';
|
||||
|
||||
describe('visual-builder helper functions', () => {
|
||||
describe('createNode', () => {
|
||||
it('ควรสร้าง node ปกติ', () => {
|
||||
const node = createNode('TestNode', 100);
|
||||
|
||||
expect(node.id).toBe('TestNode');
|
||||
expect(node.type).toBe('default');
|
||||
expect(node.data.label).toBe('TestNode\n(No Role)');
|
||||
expect(node.data.name).toBe('TestNode');
|
||||
});
|
||||
|
||||
it('ควรสร้าง start node เมื่อ isStart=true', () => {
|
||||
const node = createNode('Start', 100, { isStart: true });
|
||||
|
||||
expect(node.type).toBe('input');
|
||||
expect(node.data.type).toBe('START');
|
||||
expect(node.style?.background).toBe('#10b981');
|
||||
});
|
||||
|
||||
it('ควรสร้าง end node เมื่อ isEnd=true', () => {
|
||||
const node = createNode('End', 100, { isEnd: true });
|
||||
|
||||
expect(node.type).toBe('output');
|
||||
expect(node.data.type).toBe('END');
|
||||
expect(node.style?.background).toBe('#ef4444');
|
||||
});
|
||||
|
||||
it('ควรสร้าง condition node เมื่อ isCondition=true', () => {
|
||||
const node = createNode('Condition', 100, { isCondition: true });
|
||||
|
||||
expect(node.style?.background).toBe('#fef3c7');
|
||||
expect(node.style?.borderStyle).toBe('dashed');
|
||||
});
|
||||
|
||||
it('ควรใส่ role ใน label เมื่อมี role', () => {
|
||||
const node = createNode('Task', 100, { role: 'Manager' });
|
||||
|
||||
expect(node.data.label).toBe('Task\n(Manager)');
|
||||
expect(node.data.role).toBe('Manager');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createEdge', () => {
|
||||
it('ควรสร้าง edge ระหว่าง source และ target', () => {
|
||||
const edge = createEdge('node1', 'node2', 'TRANSITION');
|
||||
|
||||
expect(edge.source).toBe('node1');
|
||||
expect(edge.target).toBe('node2');
|
||||
expect(edge.label).toBe('TRANSITION');
|
||||
expect(edge.id).toBe('e-node1-TRANSITION-node2');
|
||||
});
|
||||
|
||||
it('ควรมี markerEnd', () => {
|
||||
const edge = createEdge('node1', 'node2', 'TRANSITION');
|
||||
|
||||
expect(edge.markerEnd).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseDSL', () => {
|
||||
it('ควร return empty nodes/edges เมื่อ DSL เป็น empty string', () => {
|
||||
const result = parseDSL('');
|
||||
|
||||
expect(result.nodes).toEqual([]);
|
||||
expect(result.edges).toEqual([]);
|
||||
});
|
||||
|
||||
it('ควร return empty nodes/edges เมื่อ JSON parse fail', () => {
|
||||
const result = parseDSL('invalid json');
|
||||
|
||||
expect(result.nodes).toEqual([]);
|
||||
expect(result.edges).toEqual([]);
|
||||
});
|
||||
|
||||
it('ควร parse DSL ที่มี states array', () => {
|
||||
const dsl = JSON.stringify({
|
||||
states: [
|
||||
{ name: 'Start', type: 'START', initial: true },
|
||||
{ name: 'Review', role: 'Manager' },
|
||||
],
|
||||
});
|
||||
|
||||
const result = parseDSL(dsl);
|
||||
|
||||
expect(result.nodes.length).toBe(2);
|
||||
expect(result.nodes[0].data.name).toBe('Start');
|
||||
expect(result.nodes[1].data.name).toBe('Review');
|
||||
});
|
||||
|
||||
it('ควร parse DSL ที่มี states object', () => {
|
||||
const dsl = JSON.stringify({
|
||||
initialState: 'Start',
|
||||
states: {
|
||||
Start: { initial: true },
|
||||
End: { terminal: true },
|
||||
},
|
||||
});
|
||||
|
||||
const result = parseDSL(dsl);
|
||||
|
||||
expect(result.nodes.length).toBe(2);
|
||||
expect(result.nodes[0].data.name).toBe('Start');
|
||||
expect(result.nodes[1].data.name).toBe('End');
|
||||
});
|
||||
|
||||
it('ควรสร้าง edges จาก transitions', () => {
|
||||
const dsl = JSON.stringify({
|
||||
states: [
|
||||
{ name: 'Start', on: { SUBMIT: { to: 'Review' } } },
|
||||
{ name: 'Review' },
|
||||
],
|
||||
});
|
||||
|
||||
const result = parseDSL(dsl);
|
||||
|
||||
expect(result.edges.length).toBe(1);
|
||||
expect(result.edges[0].source).toBe('Start');
|
||||
expect(result.edges[0].target).toBe('Review');
|
||||
});
|
||||
|
||||
it('ควร handle dslDefinition field', () => {
|
||||
const dsl = JSON.stringify({
|
||||
dslDefinition: JSON.stringify({
|
||||
states: [{ name: 'Start' }],
|
||||
}),
|
||||
});
|
||||
|
||||
const result = parseDSL(dsl);
|
||||
|
||||
expect(result.nodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('ควร handle role จาก require.role', () => {
|
||||
const dsl = JSON.stringify({
|
||||
states: [
|
||||
{ name: 'Review', on: { SUBMIT: { require: { role: 'Manager' } } } },
|
||||
],
|
||||
});
|
||||
|
||||
const result = parseDSL(dsl);
|
||||
|
||||
expect(result.nodes[0].data.role).toBe('Manager');
|
||||
});
|
||||
|
||||
it('ควร handle role array จาก require.role', () => {
|
||||
const dsl = JSON.stringify({
|
||||
states: [
|
||||
{ name: 'Review', on: { SUBMIT: { require: { role: ['Manager', 'Lead'] } } } },
|
||||
],
|
||||
});
|
||||
|
||||
const result = parseDSL(dsl);
|
||||
|
||||
expect(result.nodes[0].data.role).toBe('Manager, Lead');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -106,7 +106,7 @@ interface VisualWorkflowBuilderProps {
|
||||
onDslChange?: (dsl: string) => void;
|
||||
}
|
||||
|
||||
const createNode = (
|
||||
export const createNode = (
|
||||
name: string,
|
||||
yOffset: number,
|
||||
options?: {
|
||||
@@ -148,7 +148,7 @@ const createNode = (
|
||||
};
|
||||
};
|
||||
|
||||
const createEdge = (source: string, target: string, label: string): Edge => ({
|
||||
export const createEdge = (source: string, target: string, label: string): Edge => ({
|
||||
id: `e-${source}-${label}-${target}`,
|
||||
source,
|
||||
target,
|
||||
@@ -156,7 +156,7 @@ const createEdge = (source: string, target: string, label: string): Edge => ({
|
||||
markerEnd: { type: MarkerType.ArrowClosed },
|
||||
});
|
||||
|
||||
function parseDSL(dsl: string): { nodes: Node[]; edges: Edge[] } {
|
||||
export function parseDSL(dsl: string): { nodes: Node[]; edges: Edge[] } {
|
||||
const nodes: Node[] = [];
|
||||
const edges: Edge[] = [];
|
||||
let yOffset = 50;
|
||||
|
||||
@@ -0,0 +1,965 @@
|
||||
Loaded vitest@4.1.8 and @vitest/coverage-v8@4.1.6 .
|
||||
Running mixed versions is not supported and may lead into bugs
|
||||
Update your dependencies and make sure the versions match.
|
||||
|
||||
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.8 [39m[90mE:/np-dms/lcbp3/frontend[39m
|
||||
[2mCoverage enabled with [22m[33mv8[39m
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > creates a user with required fields and selected role
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/admin/reference/__tests__/generic-crud-table.test.tsx > GenericCrudTable > creates a new item from dialog form
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/admin/reference/__tests__/generic-crud-table.test.tsx > GenericCrudTable > creates a new item from dialog form
|
||||
Checkbox is changing from controlled to uncontrolled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
[32m✓[39m components/admin/__tests__/organization-dialog.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 3073[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ Dialog เมื่อ open เป็น true [33m 523[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Cancel และ Create Organization สำหรับ New [33m 902[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Save Changes สำหรับ Edit [33m 309[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก onOpenChange(false) เมื่อคลิก Cancel [33m 323[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง validation error เมื่อ submit form ว่างเปล่า [33m 380[2mms[22m[39m
|
||||
[32m✓[39m components/admin/reference/__tests__/generic-crud-table.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 3343[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders data rows returned by fetchFn [33m 493[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m creates a new item from dialog form [33m 2652[2mms[22m[39m
|
||||
[32m✓[39m components/workflow/__tests__/integrated-banner.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 3730[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders metadata, priority, workflow state, and legacy actions [33m 1170[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m requires comment for reject action [33m 2378[2mms[22m[39m
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
[32m✓[39m components/layout/__tests__/user-nav.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 4180[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount) [33m 1370[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile [33m 906[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings [33m 829[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out [33m 762[2mms[22m[39m
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > pre-fills existing user and submits update without empty password
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > closes when cancel is clicked
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/admin/__tests__/user-dialog.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 9233[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m creates a user with required fields and selected role [33m 6406[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m pre-fills existing user and submits update without empty password [33m 2302[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m closes when cancel is clicked [33m 514[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/form.test.tsx [2m([22m[2m27 tests[22m[2m)[22m[33m 10824[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render form with all required fields [33m 891[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render optional fields [33m 547[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render submit button [33m 413[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty project [33m 566[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty contract [33m 592[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty discipline [33m 581[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty type [33m 359[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for short subject [33m 656[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty to organization [33m 489[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow subject input [33m 488[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow body input [33m 402[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow remarks input [33m 437[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render shop drawing section [33m 386[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render as-built drawing section [33m 374[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show search input for shop drawings [33m 317[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show search input for as-built drawings [33m 450[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show preview section when form is valid [33m 800[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display preview number [33m 775[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should call create mutation on valid submit [33m 370[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show loading state during submission [33m 325[2mms[22m[39m
|
||||
[32m✓[39m components/transmittal/__tests__/transmittal-form.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 15486[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders main sections and supports cancel navigation [33m 2737[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m shows validation errors when required fields are missing [33m 1994[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m submits cleaned transmittal payload and navigates to created record [33m 10741[2mms[22m[39m
|
||||
[32m✓[39m lib/api/__tests__/admin.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 5792[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return array of users [33m 526[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return users ที่มี publicId, username, email [33m 524[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร create user ใหม่และ return user object [33m 814[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร assign userId ใหม่ให้ user [33m 814[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return array of organizations [33m 511[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return organizations ที่มี publicId, orgCode, orgName [33m 513[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร create organization ใหม่และ return org object [33m 603[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร assign orgId ใหม่ให้ organization [33m 609[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return array of audit logs [33m 427[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return logs ที่มี publicId, userName, action [33m 407[2mms[22m[39m
|
||||
stderr | components/admin/__tests__/sidebar.test.tsx > AdminMobileSidebar > opens mobile navigation from trigger button
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/admin/__tests__/sidebar.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 4226[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m auto-expands the active menu and renders child links [33m 1999[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m toggles a collapsed menu on click [33m 1334[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m opens mobile navigation from trigger button [33m 874[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/form.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 6172[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m keeps edit prefilled values after mount (no reset on initial render) [33m 4307[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m keeps dependent fields intact after async effects (reset guard) [33m 1856[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/detail.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[33m 5536[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์รายละเอียดเอกสารและข้อมูลพื้นฐานได้ถูกต้อง [33m 863[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่มและส่งคำขอเมื่อกด Submit for Review ในกรณีที่เป็น DRAFT [33m 1845[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงข้อความเตือนภัยและซ่อนปุ่มการกระทำบางอย่างหากเอกสารถูกยกเลิก [33m 514[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Approve และ Reject ในกรณีที่เอกสารเป็น IN_REVIEW [33m 391[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดการกดยืนยันการอนุมัติและส่งความคิดเห็นได้ถูกต้อง [33m 590[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดส่วนยกเลิกเอกสารและส่งเหตุผลการยกเลิกได้ถูกต้อง [33m 1127[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/file-preview-modal.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 5419[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders iframe for PDF MIME type [33m 2644[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders img for image MIME type [33m 666[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m shows download link for unsupported MIME type (no iframe or img) [33m 666[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onClose when close button is clicked [33m 1008[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onUnavailable when API returns 404 [33m 418[2mms[22m[39m
|
||||
[32m✓[39m components/admin/security/__tests__/rbac-matrix.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 4363[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders roles and permissions from API data [33m 2235[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m saves pending permission changes [33m 1917[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/manual-override-form.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m 4516[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render form with all required fields [33m 647[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render with default projectId from props [33m 402[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty project [33m 520[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty originator [33m 367[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should submit form with valid data [33m 523[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show error toast on submission failure [33m 484[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should disable submit button while loading [33m 382[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should reset form after successful submission [33m 350[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/tag-manager.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 2694[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก remove mutation เมื่อคลิกปุ่มลบ tag และมีสิทธิ์แก้ไข [33m 1532[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดส่วนเลือก tag และแสดง tag ที่พร้อมให้เพิ่มเมื่อคลิก Add Tag [33m 667[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/pagination.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 3627[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ข้อมูลหน้าปัจจุบัน หน้าทั้งหมด และรายการทั้งหมดสำเร็จ [33m 1951[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disable ปุ่ม Previous เมื่ออยู่หน้าแรก [33m 354[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disable ปุ่ม Next เมื่ออยู่หน้าสุดท้าย [33m 354[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนหน้าเมื่อคลิกปุ่ม Next [33m 370[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนหน้าเมื่อคลิกหมายเลขหน้าโดยตรง [33m 329[2mms[22m[39m
|
||||
[32m✓[39m components/search/__tests__/filters.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[33m 4864[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render filters card [33m 492[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง Document Type checkboxes [33m 542[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง Status checkboxes [33m 523[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง active count badge เมื่อมี filters [33m 2162[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง Clear all filters button เมื่อมี active filters [33m 703[2mms[22m[39m
|
||||
[32m✓[39m components/workflows/__tests__/dsl-editor.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 3884[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls workflowApi.validateDSL when Validate button is clicked [33m 2326[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(true) when validation returns errors [33m 416[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(false) when validation returns valid [33m 475[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(true) on server error [33m 409[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-version-history.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 3074[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders loading and empty states [33m 617[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders versions and triggers version actions [33m 2427[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/navbar.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 4531[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ header ได้ถูกต้อง [33m 3224[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก toggleSidebar เมื่อคลิกปุ่ม menu [33m 726[2mms[22m[39m
|
||||
stderr | components/layout/__tests__/layout-widgets.test.tsx > layout widgets > ProjectSwitcher ควรเลือก project และ global ได้
|
||||
In HTML, <div> cannot be a child of <select>.
|
||||
This will cause a hydration error.
|
||||
|
||||
<ProjectSwitcher>
|
||||
<Select value="global" onValueChange={function onValueChange}>
|
||||
> <select data-testid="project-select" value="global" onChange={function onChange}>
|
||||
<SelectTrigger className="w-[200px] ...">
|
||||
> <div className="flex items-center gap-2 truncate">
|
||||
...
|
||||
|
||||
<select> cannot contain a nested <div>.
|
||||
See this log for the ancestor stack trace.
|
||||
|
||||
[32m✓[39m components/layout/__tests__/layout-widgets.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 7030[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m Sidebar ควรแสดงเมนู admin และ collapse label ได้ [33m 3877[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m MobileSidebar ควร render navigation และซ่อน admin เมื่อ role ไม่ใช่ admin [33m 553[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m GlobalSearch ควร submit query และเปิด suggestion route ได้ [33m 1832[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/header.test.tsx [2m([22m[2m1 test[22m[2m)[22m[33m 2606[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders application title and composed controls [33m 2597[2mms[22m[39m
|
||||
[32m✓[39m components/ai/__tests__/ai-suggestion-button.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 2378[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disable และแสดงข้อความ fallback เมื่อ AI ถูกปิด [33m 2081[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/ocr-engine-selector.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 4121[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders OCR engine data from admin service [33m 686[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m selects a non-active OCR engine and refreshes list [33m 3227[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-type-dropdown.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 3288[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render dropdown สำหรับเลือกประเภทพรอมต์ [33m 2953[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disabled dropdown เมื่อ disabled=true [33m 325[2mms[22m[39m
|
||||
[32m✓[39m components/search/__tests__/results.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 1917[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render loading state เมื่อ loading=true [33m 1337[2mms[22m[39m
|
||||
[32m✓[39m components/ui/__tests__/button.test.tsx [2m([22m[2m17 tests[22m[2m)[22m[33m 3590[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render with default variant and size [33m 981[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render destructive variant [33m 326[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render outline variant [33m 419[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/sequence-viewer.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 1698[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render loading state initially [33m 384[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/sidebar.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 1322[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render mobile sidebar พร้อม navigation items [33m 714[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/confirm-dialog.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 2357[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์เนื้อหาและปุ่มต่างๆ ได้อย่างถูกต้องเมื่อเปิดใช้งาน [33m 1795[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก onConfirm เมื่อกดปุ่มยืนยันสำเร็จ [33m 554[2mms[22m[39m
|
||||
[32m✓[39m components/response-code/ResponseCodeSelector.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 1335[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders the trigger with placeholder text [33m 1160[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/detail.test.tsx [2m([22m[2m19 tests[22m[2m)[22m[33m 2057[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render RFA detail with data [33m 543[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/global-search.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 1087[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง loading spinner เมื่อกำลังโหลด [33m 737[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/project-switcher.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 834[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render skeleton เมื่อกำลังโหลด [33m 782[2mms[22m[39m
|
||||
[32m✓[39m components/ai/__tests__/ai-chat-panel.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 898[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์คอมโพเนนต์อย่างถูกต้อง [33m 485[2mms[22m[39m
|
||||
[32m✓[39m components/workflow/__tests__/workflow-lifecycle.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 1965[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders history steps and opens available attachments [33m 1083[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m uploads and removes pending workflow step attachments [33m 517[2mms[22m[39m
|
||||
[32m✓[39m components/drawings/__tests__/card.test.tsx [2m([22m[2m19 tests[22m[2m)[22m[33m 1123[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/sandbox-tabs.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 1067[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render 3-step sandbox testing interface [33m 810[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/list.test.tsx [2m([22m[2m11 tests[22m[2m)[22m[33m 1290[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render RFA list with data [33m 500[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/ocr-sandbox-prompt-manager.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 1032[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render sandbox tab พร้อม project, contract, engine และ history [33m 571[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/notifications-dropdown.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 1253[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render notification bell icon [33m 1102[2mms[22m[39m
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร render form สำหรับตั้งค่าบริบทข้อมูล
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร render form สำหรับตั้งค่าบริบทข้อมูล
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร disabled ปุ่มบันทึกเมื่อ isSaving=true
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร disabled ปุ่มบันทึกเมื่อ isSaving=true
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
[32m✓[39m components/admin/ai/__tests__/context-config-editor.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 1028[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render form สำหรับตั้งค่าบริบทข้อมูล [33m 677[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disabled ปุ่มบันทึกเมื่อ isSaving=true [33m 316[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/metrics-dashboard.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[33m 690[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/list.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 709[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์รายชื่อเอกสารและหัวตารางได้ถูกต้อง [33m 401[2mms[22m[39m
|
||||
[32m✓[39m hooks/ai/__tests__/use-intent-classification.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 693[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-users.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 452[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-master-data.test.ts [2m([22m[2m15 tests[22m[2m)[22m[33m 893[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/user-menu.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 782[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render user menu เมื่อมี user [33m 679[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-drawing.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 603[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflow-action.test.ts [2m([22m[2m8 tests[22m[2m)[22m[33m 705[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-editor.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 439[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflow-history.test.ts [2m([22m[2m8 tests[22m[2m)[22m[33m 566[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflows.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 371[2mms[22m[39m
|
||||
[32m✓[39m components/circulation/__tests__/circulation-list.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 546[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-rfa.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 408[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/circulation-status-card.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 476[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-dashboard.test.ts [2m([22m[2m4 tests[22m[2m)[22m[33m 457[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-review-teams.test.ts [2m([22m[2m11 tests[22m[2m)[22m[33m 793[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-ai-chat.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 175[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-projects.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 546[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-transmittal.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 276[2mms[22m[39m
|
||||
[32m✓[39m components/transmittal/__tests__/transmittal-list.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 190[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/version-history.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 360[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-ai-prompts.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 299[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-numbering.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 422[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/draft-store.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 147[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/status-badge.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 207[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/error-display.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 399[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/workflow-error-boundary.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 137[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-correspondence.test.ts [2m([22m[2m12 tests[22m[2m)[22m[33m 444[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/can.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 174[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-circulation.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 276[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/theme-toggle.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 266[2mms[22m[39m
|
||||
stderr | components/admin/ai/__tests__/runtime-parameters-panel.test.tsx > RuntimeParametersPanel > ควร render panel พารามิเตอร์เมื่อโหลดสำเร็จ
|
||||
An update to RuntimeParametersPanel inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
An update to RuntimeParametersPanel inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
[32m✓[39m components/admin/ai/__tests__/runtime-parameters-panel.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 194[2mms[22m[39m
|
||||
[32m✓[39m components/auth/__tests__/auth-sync.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[32m 130[2mms[22m[39m
|
||||
[32m✓[39m components/drawings/__tests__/list.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[32m 258[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/ui-store.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 133[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/dashboard-shell.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 170[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-delegation.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 264[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/auth-store.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 173[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/project-store.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 87[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/master-data.service.test.ts [2m([22m[2m26 tests[22m[2m)[22m[32m 57[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/shop-drawing.service.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/workflow-engine.service.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 59[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/drawing-master-data.service.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 40[2mms[22m[39m
|
||||
[32m✓[39m lib/api/__tests__/client.test.ts [2m([22m[2m14 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/correspondence.service.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/user.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/migration.service.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/session.service.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/organization.service.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 27[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/ai.service.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/transmittal.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/dashboard.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/document-numbering.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/review-team.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/circulation.service.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/contract-drawing.service.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/search.service.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/contract.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/rfa.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/project.service.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/asbuilt-drawing.service.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
||||
[32m✓[39m lib/api/__tests__/ai.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 16[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/audit-log.service.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 20[2mms[22m[39m
|
||||
[32m✓[39m lib/utils/__tests__/uuid-guard.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
||||
[32m✓[39m lib/__tests__/auth.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
||||
[32m✓[39m lib/i18n/__tests__/index.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
||||
|
||||
[2m Test Files [22m [1m[32m108 passed[39m[22m[90m (108)[39m
|
||||
[2m Tests [22m [1m[32m761 passed[39m[22m[90m (761)[39m
|
||||
[2m Start at [22m 21:24:34
|
||||
[2m Duration [22m 159.63s[2m (transform 37.26s, setup 66.12s, import 222.37s, tests 169.90s, environment 459.70s)[22m
|
||||
|
||||
[34m % [39m[2mCoverage report from [22m[33mv8[39m
|
||||
-------------------|---------|----------|---------|---------|-------------------
|
||||
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
||||
-------------------|---------|----------|---------|---------|-------------------
|
||||
All files | 52.55 | 42.12 | 50.83 | 53.22 |
|
||||
components/admin | 77.23 | 72.34 | 63.46 | 80.73 |
|
||||
...on-dialog.tsx | 71.42 | 72.22 | 66.66 | 75 | 81-90
|
||||
sidebar.tsx | 76.59 | 77.77 | 60 | 79.48 | ...47-275,298-321
|
||||
user-dialog.tsx | 80 | 70.11 | 66.66 | 84 | ...62-283,313-315
|
||||
...nents/admin/ai | 41.66 | 34.21 | 34.84 | 42.8 |
|
||||
...figEditor.tsx | 63.82 | 33.33 | 53.84 | 66.66 | ...20-129,153-192
|
||||
...eSelector.tsx | 96.15 | 95.45 | 100 | 96.15 | 44
|
||||
...ptManager.tsx | 36.88 | 22.36 | 25 | 38.36 | ...86-673,691-964
|
||||
PromptEditor.tsx | 69.23 | 63.63 | 66.66 | 70.83 | ...9,57-61,87,121
|
||||
...eDropdown.tsx | 50 | 100 | 50 | 50 | 31
|
||||
...onHistory.tsx | 100 | 100 | 100 | 100 |
|
||||
...tersPanel.tsx | 35.29 | 25.8 | 20 | 36.92 | ...07-115,128-265
|
||||
SandboxTabs.tsx | 21.62 | 25.31 | 5.88 | 21.62 | ...01-202,227-445
|
||||
...onHistory.tsx | 62.5 | 83.33 | 40 | 62.5 | 98-118
|
||||
...dmin/reference | 54.09 | 54.54 | 40.74 | 53.33 |
|
||||
...rud-table.tsx | 54.09 | 54.54 | 40.74 | 53.33 | ...76,181,259-323
|
||||
...admin/security | 93.87 | 77.41 | 88.23 | 93.61 |
|
||||
rbac-matrix.tsx | 93.87 | 77.41 | 88.23 | 93.61 | 46,98,104
|
||||
components/ai | 23.7 | 17.75 | 25.8 | 25 |
|
||||
...tusBanner.tsx | 0 | 0 | 0 | 0 | 18-40
|
||||
...hatWidget.tsx | 0 | 0 | 0 | 0 | 40-286
|
||||
...hat-input.tsx | 52.94 | 21.42 | 40 | 52.94 | 21-24,28-30,45
|
||||
...-messages.tsx | 54.38 | 56.66 | 100 | 57.4 | ...80,83-88,91-92
|
||||
...hat-panel.tsx | 75 | 33.33 | 80 | 72.72 | 32-34
|
||||
...at-toggle.tsx | 0 | 0 | 0 | 0 | 16
|
||||
...nner-host.tsx | 0 | 0 | 0 | 0 | 13-23
|
||||
...on-button.tsx | 100 | 100 | 100 | 100 |
|
||||
...ion-field.tsx | 0 | 0 | 0 | 0 | 14-147
|
||||
...ison-view.tsx | 0 | 0 | 0 | 0 | 12-133
|
||||
...indicator.tsx | 0 | 100 | 0 | 0 | 8
|
||||
...classification | 0 | 0 | 0 | 0 |
|
||||
...sult-card.tsx | 0 | 0 | 0 | 0 | 17-42
|
||||
intent-form.tsx | 0 | 0 | 0 | 0 | 54-123
|
||||
pattern-form.tsx | 0 | 0 | 0 | 0 | 55-164
|
||||
...ole-panel.tsx | 0 | 0 | 0 | 0 | 20-89
|
||||
...tion/analytics | 0 | 0 | 0 | 0 |
|
||||
...ary-cards.tsx | 0 | 0 | 0 | 0 | 19-49
|
||||
...own-table.tsx | 0 | 0 | 0 | 0 | 26-46
|
||||
...own-table.tsx | 0 | 0 | 0 | 0 | 24-61
|
||||
...ion-panel.tsx | 0 | 0 | 0 | 0 | 28-61
|
||||
components/auth | 100 | 92.85 | 100 | 100 |
|
||||
auth-sync.tsx | 100 | 92.85 | 100 | 100 | 43-45
|
||||
...ts/circulation | 100 | 95.45 | 100 | 100 |
|
||||
...tion-list.tsx | 100 | 95.45 | 100 | 100 | 120
|
||||
components/common | 91.11 | 88.88 | 96.96 | 92 |
|
||||
can.tsx | 100 | 100 | 100 | 100 |
|
||||
...rm-dialog.tsx | 100 | 100 | 100 | 100 |
|
||||
data-table.tsx | 100 | 66.66 | 100 | 100 | 41,50
|
||||
...r-display.tsx | 93.33 | 93.61 | 100 | 92.85 | 69,94
|
||||
...iew-modal.tsx | 87.8 | 84.61 | 88.88 | 90.9 | 35,76,92
|
||||
pagination.tsx | 100 | 100 | 100 | 100 |
|
||||
status-badge.tsx | 78.26 | 77.77 | 100 | 78.26 | 37-38,48-50
|
||||
...-boundary.tsx | 100 | 100 | 100 | 100 |
|
||||
...orrespondences | 48.69 | 43.65 | 50.37 | 49.87 |
|
||||
...atus-card.tsx | 100 | 83.33 | 100 | 100 | 30-32,51-52,94
|
||||
...s-content.tsx | 0 | 0 | 0 | 0 | 17-212
|
||||
detail.tsx | 80.64 | 67.74 | 77.27 | 88.67 | ...93,151,195,238
|
||||
form.tsx | 55.55 | 43.08 | 53.33 | 56.2 | ...43,564,593-729
|
||||
list.tsx | 92.85 | 67.74 | 100 | 96.29 | 112
|
||||
...-selector.tsx | 0 | 0 | 0 | 0 | 38-203
|
||||
...n-history.tsx | 0 | 0 | 0 | 0 | 13-56
|
||||
tag-manager.tsx | 92.85 | 88.46 | 84.61 | 91.66 | 24,131
|
||||
...ow-dialog.tsx | 0 | 0 | 0 | 0 | 15-198
|
||||
components/custom | 1.35 | 0 | 0 | 1.4 |
|
||||
...load-zone.tsx | 2 | 0 | 0 | 2.12 | 35-187
|
||||
...isualizer.tsx | 0 | 0 | 0 | 0 | 30-68
|
||||
...ents/dashboard | 0 | 0 | 0 | 0 |
|
||||
...ing-tasks.tsx | 0 | 0 | 0 | 0 | 15-55
|
||||
...k-actions.tsx | 0 | 100 | 0 | 0 | 8
|
||||
...-activity.tsx | 0 | 0 | 0 | 0 | 16-51
|
||||
stats-cards.tsx | 0 | 0 | 0 | 0 | 13-58
|
||||
...nts/delegation | 0 | 0 | 0 | 0 |
|
||||
...ationForm.tsx | 0 | 0 | 0 | 0 | 29-162
|
||||
...s/distribution | 0 | 0 | 0 | 0 |
|
||||
...ionStatus.tsx | 0 | 0 | 0 | 0 | 30-54
|
||||
...cuments/common | 0 | 0 | 0 | 0 |
|
||||
...ata-table.tsx | 0 | 0 | 0 | 0 | 39-161
|
||||
...nents/drawings | 12.26 | 25.87 | 6.06 | 13.13 |
|
||||
card.tsx | 100 | 96.15 | 100 | 100 | 73
|
||||
columns.tsx | 10 | 0 | 0 | 10 | 21-66
|
||||
list.tsx | 100 | 100 | 100 | 100 |
|
||||
...n-history.tsx | 0 | 0 | 0 | 0 | 11-17
|
||||
upload-form.tsx | 0 | 0 | 0 | 0 | 29-435
|
||||
components/layout | 93.83 | 86.3 | 93.75 | 93.52 |
|
||||
...ard-shell.tsx | 100 | 100 | 100 | 100 |
|
||||
...al-search.tsx | 86.48 | 67.85 | 92.85 | 85.71 | 24,44,62-66
|
||||
header.tsx | 100 | 100 | 100 | 100 |
|
||||
navbar.tsx | 100 | 100 | 100 | 100 |
|
||||
...-dropdown.tsx | 100 | 78.94 | 100 | 100 | 24,28-31,67
|
||||
...-switcher.tsx | 100 | 100 | 100 | 100 |
|
||||
sidebar.tsx | 90.9 | 96.66 | 77.77 | 90 | 152,224,236,250
|
||||
theme-toggle.tsx | 100 | 100 | 100 | 100 |
|
||||
user-menu.tsx | 100 | 75 | 100 | 100 | 34
|
||||
user-nav.tsx | 100 | 60 | 100 | 100 | 26-38
|
||||
...ents/migration | 0 | 0 | 0 | 0 |
|
||||
...eue-table.tsx | 0 | 0 | 0 | 0 | 58-479
|
||||
...ents/numbering | 29.94 | 19.69 | 31.57 | 29.94 |
|
||||
...ogs-table.tsx | 0 | 0 | 0 | 0 | 10-52
|
||||
...port-form.tsx | 0 | 0 | 0 | 0 | 11-38
|
||||
...mber-form.tsx | 0 | 0 | 0 | 0 | 14-72
|
||||
...ride-form.tsx | 100 | 80 | 100 | 100 | 45
|
||||
...dashboard.tsx | 100 | 100 | 100 | 100 |
|
||||
...ce-viewer.tsx | 100 | 93.33 | 100 | 100 | 21
|
||||
...te-editor.tsx | 0 | 0 | 0 | 0 | 16-181
|
||||
...te-tester.tsx | 0 | 0 | 0 | 0 | 36-182
|
||||
...lace-form.tsx | 0 | 0 | 0 | 0 | 15-91
|
||||
...nents/reminder | 0 | 0 | 0 | 0 |
|
||||
...erHistory.tsx | 0 | 0 | 0 | 0 | 21-55
|
||||
...rRuleForm.tsx | 0 | 0 | 0 | 0 | 15-129
|
||||
.../response-code | 26.41 | 17.33 | 20.83 | 26.53 |
|
||||
...lications.tsx | 0 | 0 | 0 | 0 | 14-72
|
||||
MatrixEditor.tsx | 0 | 0 | 0 | 0 | 44-134
|
||||
...deManager.tsx | 0 | 0 | 0 | 0 | 53-137
|
||||
...eSelector.tsx | 100 | 72.22 | 100 | 100 | 40,74-89
|
||||
...ts/review-task | 0 | 0 | 0 | 0 |
|
||||
...eviewForm.tsx | 0 | 0 | 0 | 0 | 24-88
|
||||
...atedBadge.tsx | 0 | 0 | 0 | 0 | 22-26
|
||||
...lProgress.tsx | 0 | 0 | 0 | 0 | 27-64
|
||||
...TaskInbox.tsx | 0 | 0 | 0 | 0 | 43-159
|
||||
...ideDialog.tsx | 0 | 0 | 0 | 0 | 25-87
|
||||
...ts/review-team | 0 | 0 | 0 | 0 |
|
||||
...wTeamForm.tsx | 0 | 0 | 0 | 0 | 22-136
|
||||
...mSelector.tsx | 0 | 0 | 0 | 0 | 17-67
|
||||
...erManager.tsx | 0 | 0 | 0 | 0 | 45-172
|
||||
components/rfas | 57.14 | 55.08 | 43.58 | 57.56 |
|
||||
detail.tsx | 58.13 | 64.28 | 62.5 | 58.53 | ...,82-92,189-194
|
||||
form.tsx | 55.08 | 50.23 | 30.18 | 55.68 | ...84,496,514-778
|
||||
list.tsx | 72.72 | 70.83 | 88.88 | 71.42 | 78-89
|
||||
components/search | 66.66 | 58.33 | 46.15 | 75 |
|
||||
filters.tsx | 45 | 37.5 | 30 | 52.94 | 33-35,39-41,63,81
|
||||
results.tsx | 93.75 | 75 | 100 | 100 | 39,63-70
|
||||
...ts/transmittal | 72.72 | 55.76 | 72.22 | 74.19 |
|
||||
...ttal-form.tsx | 93.61 | 75 | 89.28 | 93.47 | 100,317,405
|
||||
...ttal-list.tsx | 21.05 | 12.5 | 12.5 | 18.75 | 24-67
|
||||
components/ui | 90.84 | 79.06 | 80 | 90.84 |
|
||||
alert-dialog.tsx | 100 | 100 | 100 | 100 |
|
||||
alert.tsx | 90 | 100 | 66.66 | 90 | 31
|
||||
avatar.tsx | 100 | 100 | 100 | 100 |
|
||||
badge.tsx | 100 | 100 | 100 | 100 |
|
||||
button.tsx | 100 | 100 | 100 | 100 |
|
||||
calendar.tsx | 0 | 0 | 0 | 0 | 13-54
|
||||
card.tsx | 100 | 100 | 100 | 100 |
|
||||
checkbox.tsx | 100 | 100 | 100 | 100 |
|
||||
command.tsx | 91.66 | 100 | 75 | 91.66 | 83,104
|
||||
dialog.tsx | 100 | 100 | 100 | 100 |
|
||||
...down-menu.tsx | 92.3 | 42.85 | 71.42 | 92.3 | 79,98
|
||||
form.tsx | 97.29 | 90 | 100 | 97.29 | 43
|
||||
hover-card.tsx | 100 | 100 | 100 | 100 |
|
||||
input.tsx | 100 | 100 | 100 | 100 |
|
||||
label.tsx | 100 | 100 | 100 | 100 |
|
||||
popover.tsx | 100 | 100 | 100 | 100 |
|
||||
progress.tsx | 100 | 100 | 100 | 100 |
|
||||
scroll-area.tsx | 100 | 80 | 100 | 100 | 30
|
||||
select.tsx | 95.83 | 100 | 85.71 | 95.83 | 128
|
||||
separator.tsx | 100 | 75 | 100 | 100 | 16
|
||||
sheet.tsx | 86.95 | 100 | 50 | 86.95 | 73,78,94
|
||||
skeleton.tsx | 100 | 100 | 100 | 100 |
|
||||
sonner.tsx | 0 | 0 | 0 | 0 | 9-11
|
||||
switch.tsx | 100 | 100 | 100 | 100 |
|
||||
table.tsx | 91.66 | 100 | 75 | 91.66 | 28,67
|
||||
tabs.tsx | 0 | 100 | 0 | 0 | 8-53
|
||||
textarea.tsx | 100 | 100 | 100 | 100 |
|
||||
...nents/workflow | 83.63 | 81.48 | 78.57 | 88.54 |
|
||||
...ed-banner.tsx | 86.36 | 74.54 | 90 | 94.59 | 45,135
|
||||
...lifecycle.tsx | 81.81 | 88.67 | 72.22 | 84.74 | 57,60,63,255-261
|
||||
...ents/workflows | 15.38 | 15.32 | 12.12 | 16 |
|
||||
dsl-editor.tsx | 63.15 | 61.76 | 50 | 64.86 | 41-46,51,79-88
|
||||
...l-builder.tsx | 0 | 0 | 0 | 0 | 70-406
|
||||
hooks | 64.06 | 43.05 | 62.76 | 64.15 |
|
||||
use-ai-chat.ts | 84.21 | 50 | 75 | 88.88 | 18-21,85
|
||||
...ai-prompts.ts | 100 | 75 | 100 | 100 | 107,117-175
|
||||
use-ai-status.ts | 18.18 | 7.14 | 9.09 | 21.42 | 17-25,41-82
|
||||
...audit-logs.ts | 0 | 100 | 0 | 0 | 5-13
|
||||
...irculation.ts | 44.44 | 0 | 50 | 44.44 | 7,16-26
|
||||
...espondence.ts | 51.28 | 10 | 49.05 | 51.28 | 81,98-117,136-224
|
||||
use-dashboard.ts | 100 | 100 | 100 | 100 |
|
||||
...delegation.ts | 100 | 100 | 100 | 100 |
|
||||
...n-matrices.ts | 0 | 0 | 0 | 0 | 47-98
|
||||
use-drawing.ts | 63.15 | 54.16 | 62.5 | 62.96 | ...05,124,141-179
|
||||
...aster-data.ts | 100 | 61.53 | 100 | 100 | 39-72,98-99
|
||||
...ion-review.ts | 0 | 0 | 0 | 0 | 20-101
|
||||
...tification.ts | 0 | 100 | 0 | 0 | 5-28
|
||||
use-numbering.ts | 100 | 100 | 100 | 100 |
|
||||
use-projects.ts | 100 | 100 | 100 | 100 |
|
||||
...rence-data.ts | 0 | 0 | 0 | 0 | 10-118
|
||||
use-reminder.ts | 0 | 100 | 0 | 0 | 45-126
|
||||
...onse-codes.ts | 0 | 0 | 0 | 0 | 6-41
|
||||
...view-teams.ts | 100 | 50 | 100 | 100 | 27
|
||||
use-rfa.ts | 78.37 | 100 | 80 | 78.37 | 41-52,87
|
||||
use-search.ts | 0 | 0 | 0 | 0 | 5-23
|
||||
...anslations.ts | 0 | 100 | 0 | 0 | 9-12
|
||||
...ransmittal.ts | 100 | 100 | 100 | 100 |
|
||||
use-users.ts | 100 | 100 | 100 | 100 |
|
||||
...low-action.ts | 90.47 | 74.19 | 100 | 90.24 | 77-80,97,107
|
||||
...ow-history.ts | 100 | 100 | 100 | 100 |
|
||||
use-workflows.ts | 100 | 100 | 100 | 100 |
|
||||
hooks/ai | 44.11 | 100 | 48.14 | 44.11 |
|
||||
...sification.ts | 44.11 | 100 | 48.14 | 44.11 | 72-122
|
||||
lib | 32 | 28.57 | 46.15 | 31.94 |
|
||||
auth.ts | 27.94 | 28.57 | 33.33 | 27.69 | 67,75-113,134-232
|
||||
test-utils.tsx | 66.66 | 100 | 66.66 | 66.66 | 33-34
|
||||
utils.ts | 100 | 100 | 100 | 100 |
|
||||
lib/api | 35.63 | 31.25 | 20.83 | 36.56 |
|
||||
admin.ts | 100 | 50 | 100 | 100 | 76-104
|
||||
ai.ts | 32.65 | 38.88 | 8.69 | 30.43 | ...13-175,200-222
|
||||
client.ts | 81.35 | 72.54 | 62.5 | 82.45 | 70-87,177
|
||||
dashboard.ts | 0 | 100 | 0 | 0 | 8-53
|
||||
drawings.ts | 0 | 100 | 0 | 0 | 4-41
|
||||
files.ts | 14.28 | 100 | 0 | 16.66 | 15-24
|
||||
notifications.ts | 0 | 0 | 0 | 0 | 4-49
|
||||
numbering.ts | 0 | 0 | 0 | 0 | 124-343
|
||||
workflows.ts | 0 | 0 | 0 | 0 | 4-86
|
||||
lib/i18n | 100 | 100 | 100 | 100 |
|
||||
index.ts | 100 | 100 | 100 | 100 |
|
||||
lib/services | 70.06 | 65.93 | 70.19 | 69.3 |
|
||||
...ai.service.ts | 6.38 | 0 | 2.77 | 6.38 | ...84-191,209-459
|
||||
...nt.service.ts | 0 | 0 | 0 | 0 | 9-229
|
||||
...ts.service.ts | 0 | 0 | 0 | 0 | 9-76
|
||||
ai.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ng.service.ts | 100 | 100 | 100 | 100 |
|
||||
...og.service.ts | 100 | 100 | 100 | 100 |
|
||||
...on.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ng.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ct.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ce.service.ts | 61.29 | 100 | 60 | 61.29 | ...2,67-68,90-115
|
||||
...rd.service.ts | 100 | 89.13 | 100 | 100 | 68,80-82
|
||||
...ng.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ta.service.ts | 100 | 82.35 | 100 | 100 | 117-149
|
||||
index.ts | 0 | 0 | 0 | 0 |
|
||||
...ma.service.ts | 0 | 100 | 0 | 0 | 5-69
|
||||
...ta.service.ts | 84.5 | 71.42 | 88.23 | 82.81 | ...46-147,226-241
|
||||
...on.service.ts | 88.23 | 59.45 | 100 | 87.87 | 29,67-77
|
||||
...ng.service.ts | 0 | 100 | 0 | 0 | 9-25
|
||||
...on.service.ts | 0 | 100 | 0 | 0 | 4-19
|
||||
...on.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ct.service.ts | 100 | 100 | 100 | 100 |
|
||||
...am.service.ts | 100 | 100 | 100 | 100 |
|
||||
rfa.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ch.service.ts | 100 | 100 | 100 | 100 |
|
||||
...on.service.ts | 94.11 | 81.81 | 100 | 93.33 | 32
|
||||
...ng.service.ts | 100 | 100 | 100 | 100 |
|
||||
...al.service.ts | 100 | 100 | 100 | 100 |
|
||||
user.service.ts | 96.15 | 80 | 100 | 96 | 27
|
||||
...ne.service.ts | 96.72 | 66.17 | 100 | 96.49 | 51,62
|
||||
lib/stores | 100 | 100 | 100 | 100 |
|
||||
auth-store.ts | 100 | 100 | 100 | 100 |
|
||||
draft-store.ts | 100 | 100 | 100 | 100 |
|
||||
project-store.ts | 100 | 100 | 100 | 100 |
|
||||
ui-store.ts | 100 | 100 | 100 | 100 |
|
||||
lib/utils | 100 | 100 | 100 | 100 |
|
||||
uuid-guard.ts | 100 | 100 | 100 | 100 |
|
||||
-------------------|---------|----------|---------|---------|-------------------
|
||||
@@ -0,0 +1,719 @@
|
||||
Loaded vitest@4.1.8 and @vitest/coverage-v8@4.1.6 .
|
||||
Running mixed versions is not supported and may lead into bugs
|
||||
Update your dependencies and make sure the versions match.
|
||||
|
||||
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.8 [39m[90mE:/np-dms/lcbp3/frontend[39m
|
||||
[2mCoverage enabled with [22m[33mv8[39m
|
||||
|
||||
[32m✓[39m lib/api/__tests__/admin.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 6025[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return array of users [33m 538[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return users ที่มี publicId, username, email [33m 602[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร create user ใหม่และ return user object [33m 903[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร assign userId ใหม่ให้ user [33m 810[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return array of organizations [33m 511[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return organizations ที่มี publicId, orgCode, orgName [33m 512[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร create organization ใหม่และ return org object [33m 609[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร assign orgId ใหม่ให้ organization [33m 603[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return array of audit logs [33m 484[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร return logs ที่มี publicId, userName, action [33m 444[2mms[22m[39m
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > creates a user with required fields and selected role
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/workflow/__tests__/integrated-banner.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 19140[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders metadata, priority, workflow state, and legacy actions [33m 5616[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m requires comment for reject action [33m 12129[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m uses workflow mutation when instanceId is provided [33m 1186[2mms[22m[39m
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > pre-fills existing user and submits update without empty password
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/correspondences/detail.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[33m 16897[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์รายละเอียดเอกสารและข้อมูลพื้นฐานได้ถูกต้อง [33m 3087[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่มและส่งคำขอเมื่อกด Submit for Review ในกรณีที่เป็น DRAFT [33m 7163[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงข้อความเตือนภัยและซ่อนปุ่มการกระทำบางอย่างหากเอกสารถูกยกเลิก [33m 1607[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Approve และ Reject ในกรณีที่เอกสารเป็น IN_REVIEW [33m 1246[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดการกดยืนยันการอนุมัติและส่งความคิดเห็นได้ถูกต้อง [33m 1858[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดส่วนยกเลิกเอกสารและส่งเหตุผลการยกเลิกได้ถูกต้อง [33m 1776[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/form.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 20803[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m keeps edit prefilled values after mount (no reset on initial render) [33m 15496[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m keeps dependent fields intact after async effects (reset guard) [33m 5297[2mms[22m[39m
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > closes when cancel is clicked
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/admin/__tests__/user-dialog.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 30378[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m creates a user with required fields and selected role [33m 21875[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m pre-fills existing user and submits update without empty password [33m 5818[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m closes when cancel is clicked [33m 2671[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/form.test.tsx [2m([22m[2m27 tests[22m[2m)[22m[33m 35172[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render form with all required fields [33m 5058[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render optional fields [33m 2348[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render submit button [33m 2899[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render AI suggestion button [33m 2001[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty project [33m 4178[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty contract [33m 1506[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty discipline [33m 2037[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty type [33m 1504[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for short subject [33m 2441[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty to organization [33m 2348[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow subject input [33m 343[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow description input [33m 926[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow body input [33m 640[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow remarks input [33m 691[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render shop drawing section [33m 1140[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render as-built drawing section [33m 584[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show search input for shop drawings [33m 478[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show search input for as-built drawings [33m 812[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show preview section when form is valid [33m 1128[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display preview number [33m 1163[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should call create mutation on valid submit [33m 570[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show loading state during submission [33m 331[2mms[22m[39m
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
[31m❯[39m components/transmittal/__tests__/transmittal-form.test.tsx [2m([22m[2m3 tests[22m[2m | [22m[31m1 failed[39m[2m)[22m[33m 48965[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders main sections and supports cancel navigation [33m 13809[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m shows validation errors when required fields are missing [33m 5018[2mms[22m[39m
|
||||
[31m [31m×[31m submits cleaned transmittal payload and navigates to created record[39m[33m 30129[2mms[22m[39m
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
[32m✓[39m components/layout/__tests__/user-nav.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 21541[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์อักษรย่อชื่อผู้ใช้ได้อย่างถูกต้อง [33m 1077[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount) [33m 8143[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile [33m 5057[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings [33m 4686[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out [33m 2491[2mms[22m[39m
|
||||
[32m✓[39m components/admin/__tests__/organization-dialog.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 18755[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ Dialog เมื่อ open เป็น true [33m 3223[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง title "New Organization" เมื่อไม่มี organization prop [33m 905[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง title "Edit Organization" เมื่อมี organization prop [33m 1902[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Cancel และ Create Organization สำหรับ New [33m 6580[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Save Changes สำหรับ Edit [33m 1732[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก onOpenChange(false) เมื่อคลิก Cancel [33m 955[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง validation error เมื่อ submit form ว่างเปล่า [33m 3236[2mms[22m[39m
|
||||
stderr | components/admin/reference/__tests__/generic-crud-table.test.tsx > GenericCrudTable > creates a new item from dialog form
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
stderr | components/admin/reference/__tests__/generic-crud-table.test.tsx > GenericCrudTable > creates a new item from dialog form
|
||||
Checkbox is changing from controlled to uncontrolled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
|
||||
|
||||
[32m✓[39m components/admin/reference/__tests__/generic-crud-table.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 12930[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders data rows returned by fetchFn [33m 1758[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders empty state for wrapped empty data [33m 328[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m creates a new item from dialog form [33m 10815[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/file-preview-modal.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 13060[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders iframe for PDF MIME type [33m 5917[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders img for image MIME type [33m 1926[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m shows download link for unsupported MIME type (no iframe or img) [33m 1416[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onClose when close button is clicked [33m 2343[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onUnavailable when API returns 404 [33m 1288[2mms[22m[39m
|
||||
stderr | components/admin/__tests__/sidebar.test.tsx > AdminMobileSidebar > opens mobile navigation from trigger button
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/admin/__tests__/sidebar.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 12514[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m auto-expands the active menu and renders child links [33m 6461[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m toggles a collapsed menu on click [33m 3158[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m opens mobile navigation from trigger button [33m 2844[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/manual-override-form.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m 13994[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render form with all required fields [33m 2276[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render with default projectId from props [33m 634[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty project [33m 1628[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty originator [33m 599[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty recipient [33m 847[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty type [33m 1086[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty new number [33m 429[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for short reason [33m 888[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should submit form with valid data [33m 2684[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show error toast on submission failure [33m 1762[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should disable submit button while loading [33m 330[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should reset form after successful submission [33m 634[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-version-history.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 4778[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders loading and empty states [33m 499[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders versions and triggers version actions [33m 4250[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/sidebar.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 4149[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render sidebar พร้อม navigation items [33m 678[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง Admin Panel เมื่อ user เป็น ADMIN [33m 606[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render mobile sidebar พร้อม navigation items [33m 2650[2mms[22m[39m
|
||||
[32m✓[39m components/admin/security/__tests__/rbac-matrix.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 5971[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders roles and permissions from API data [33m 2818[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m saves pending permission changes [33m 2860[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/ocr-engine-selector.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 5278[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders OCR engine data from admin service [33m 1398[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m selects a non-active OCR engine and refreshes list [33m 3766[2mms[22m[39m
|
||||
[32m✓[39m components/workflows/__tests__/dsl-editor.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 8361[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls workflowApi.validateDSL when Validate button is clicked [33m 5000[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(true) when validation returns errors [33m 1652[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(false) when validation returns valid [33m 551[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(true) on server error [33m 672[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m does not call onValidationChange when prop is not provided [33m 459[2mms[22m[39m
|
||||
stderr | components/layout/__tests__/layout-widgets.test.tsx > layout widgets > ProjectSwitcher ควรเลือก project และ global ได้
|
||||
In HTML, <div> cannot be a child of <select>.
|
||||
This will cause a hydration error.
|
||||
|
||||
<ProjectSwitcher>
|
||||
<Select value="global" onValueChange={function onValueChange}>
|
||||
> <select data-testid="project-select" value="global" onChange={function onChange}>
|
||||
<SelectTrigger className="w-[200px] ...">
|
||||
> <div className="flex items-center gap-2 truncate">
|
||||
...
|
||||
|
||||
<select> cannot contain a nested <div>.
|
||||
See this log for the ancestor stack trace.
|
||||
|
||||
[32m✓[39m components/layout/__tests__/layout-widgets.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 7287[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m Sidebar ควรแสดงเมนู admin และ collapse label ได้ [33m 3921[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m GlobalSearch ควร submit query และเปิด suggestion route ได้ [33m 1746[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ProjectSwitcher ควร auto-select เมื่อมี project เดียวและแสดง loading/empty state ได้ [33m 544[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m NotificationsDropdown ควรแสดง loading และ empty state ได้ [33m 424[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m UserMenu ควรแสดงข้อมูล session และ logout กลับ login [33m 386[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/pagination.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 7973[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ข้อมูลหน้าปัจจุบัน หน้าทั้งหมด และรายการทั้งหมดสำเร็จ [33m 4676[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disable ปุ่ม Previous เมื่ออยู่หน้าแรก [33m 983[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disable ปุ่ม Next เมื่ออยู่หน้าสุดท้าย [33m 346[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนหน้าเมื่อคลิกปุ่ม Previous [33m 698[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนหน้าเมื่อคลิกหมายเลขหน้าโดยตรง [33m 996[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/user-menu.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 3815[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render user menu เมื่อมี user [33m 3599[2mms[22m[39m
|
||||
[32m✓[39m components/workflow/__tests__/workflow-lifecycle.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 4447[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders loading, error, and empty states [33m 333[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders history steps and opens available attachments [33m 2651[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m uploads and removes pending workflow step attachments [33m 1264[2mms[22m[39m
|
||||
[32m✓[39m components/ui/__tests__/button.test.tsx [2m([22m[2m17 tests[22m[2m)[22m[33m 4053[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render with default variant and size [33m 1614[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render destructive variant [33m 483[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render outline variant [33m 418[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/navbar.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 3423[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ header ได้ถูกต้อง [33m 1714[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก toggleSidebar เมื่อคลิกปุ่ม menu [33m 1184[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/confirm-dialog.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 3786[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์เนื้อหาและปุ่มต่างๆ ได้อย่างถูกต้องเมื่อเปิดใช้งาน [33m 2595[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก onConfirm เมื่อกดปุ่มยืนยันสำเร็จ [33m 1182[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/global-search.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 3811[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render search input [33m 414[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง loading spinner เมื่อกำลังโหลด [33m 3025[2mms[22m[39m
|
||||
[32m✓[39m components/drawings/__tests__/card.test.tsx [2m([22m[2m19 tests[22m[2m)[22m[33m 3428[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render drawing card with data [33m 565[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display revision [33m 561[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display volume page when present [33m 389[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/sequence-viewer.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 3967[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render loading state initially [33m 1194[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render sequences after successful fetch [33m 566[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should handle wrapped response with data property [33m 349[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should filter sequences by year [33m 395[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should filter sequences by type [33m 371[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display discipline badge when disciplineId > 0 [33m 335[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/detail.test.tsx [2m([22m[2m19 tests[22m[2m)[22m[33m 4725[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render RFA detail with data [33m 867[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render RFA items table [33m 304[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show empty state when no items [33m 493[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should handle missing project name [33m 358[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should open approve dialog when Approve clicked [33m 606[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should handle missing correspondence number [33m 334[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/notifications-dropdown.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 2903[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render notification bell icon [33m 2148[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง "No new notifications" เมื่อไม่มี notification [33m 562[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/header.test.tsx [2m([22m[2m1 test[22m[2m)[22m[33m 4183[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders application title and composed controls [33m 4174[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/ocr-sandbox-prompt-manager.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 4438[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render sandbox tab พร้อม project, contract, engine และ history [33m 2876[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรสลับไป editor และบันทึก prompt version ได้ [33m 706[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร load template จาก history เข้า editor [33m 766[2mms[22m[39m
|
||||
[32m✓[39m components/ai/__tests__/ai-chat-panel.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 2184[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์คอมโพเนนต์อย่างถูกต้อง [33m 1077[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรซ่อนปุ่มล้างประวัติการสนทนาเมื่อไม่มีข้อความ [33m 301[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่มล้างประวัติการสนทนาเมื่อมีข้อความในประวัติและคลิกเพื่อล้างข้อมูลได้ [33m 338[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/sandbox-tabs.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 3324[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render 3-step sandbox testing interface [33m 2352[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disabled ปุ่ม Run OCR เมื่อไม่มีไฟล์ [33m 879[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-type-dropdown.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 4407[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render dropdown สำหรับเลือกประเภทพรอมต์ [33m 3238[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disabled dropdown เมื่อ disabled=true [33m 1161[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/project-switcher.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 3060[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render skeleton เมื่อกำลังโหลด [33m 2667[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง project name เป็น text เมื่อมี project เดียว [33m 378[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/list.test.tsx [2m([22m[2m11 tests[22m[2m)[22m[33m 3147[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render RFA list with data [33m 1161[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display formatted dates [33m 369[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display status badges [33m 458[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render action buttons for each row [33m 506[2mms[22m[39m
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร render form สำหรับตั้งค่าบริบทข้อมูล
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร render form สำหรับตั้งค่าบริบทข้อมูล
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
[32m✓[39m hooks/__tests__/use-master-data.test.ts [2m([22m[2m15 tests[22m[2m)[22m[33m 2145[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรดึงข้อมูลองค์กรสำเร็จ [33m 403[2mms[22m[39m
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร disabled ปุ่มบันทึกเมื่อ isSaving=true
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร disabled ปุ่มบันทึกเมื่อ isSaving=true
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
[32m✓[39m components/admin/ai/__tests__/context-config-editor.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 2786[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render form สำหรับตั้งค่าบริบทข้อมูล [33m 1814[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disabled ปุ่มบันทึกเมื่อ isSaving=true [33m 962[2mms[22m[39m
|
||||
[32m✓[39m hooks/ai/__tests__/use-intent-classification.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 1382[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรดึง definitions สำเร็จ [33m 445[2mms[22m[39m
|
||||
[32m✓[39m components/response-code/ResponseCodeSelector.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 3248[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders the trigger with placeholder text [33m 2677[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders a custom placeholder when provided [33m 561[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/metrics-dashboard.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[33m 1577[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render metrics after successful fetch [33m 333[2mms[22m[39m
|
||||
[32m✓[39m components/ai/__tests__/ai-suggestion-button.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 2198[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disable และแสดงข้อความ fallback เมื่อ AI ถูกปิด [33m 2066[2mms[22m[39m
|
||||
[32m✓[39m components/search/__tests__/filters.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[33m 9346[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render filters card [33m 1293[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง Document Type checkboxes [33m 928[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง active count badge เมื่อมี filters [33m 3774[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรไม่แสดง active count badge เมื่อไม่มี filters [33m 1088[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง Clear all filters button เมื่อมี active filters [33m 1181[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรไม่แสดง Clear all filters button เมื่อไม่มี active filters [33m 757[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/status-badge.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 1029[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ Draft สำหรับสถานะ DRAFT ได้อย่างถูกต้อง [33m 603[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-delegation.test.ts [2m([22m[2m6 tests[22m[2m)[22m[33m 881[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรดึงข้อมูล delegations ของฉันสำเร็จ [33m 623[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/tag-manager.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 4994[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง loading state เมื่อกำลังโหลดข้อมูล tag [33m 408[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก remove mutation เมื่อคลิกปุ่มลบ tag และมีสิทธิ์แก้ไข [33m 3006[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดส่วนเลือก tag และแสดง tag ที่พร้อมให้เพิ่มเมื่อคลิก Add Tag [33m 1371[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/theme-toggle.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 921[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก setTheme("light") เมื่อคลิกขณะ theme เป็น dark [33m 380[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflow-action.test.ts [2m([22m[2m8 tests[22m[2m)[22m[33m 1399[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m Q2 (503): should show "ระบบยุ่ง" toast when Redlock Fail-closed [33m 390[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/list.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 1017[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์รายชื่อเอกสารและหัวตารางได้ถูกต้อง [33m 543[2mms[22m[39m
|
||||
[32m✓[39m components/circulation/__tests__/circulation-list.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 1182[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ DataTable ได้ถูกต้อง [33m 380[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-drawing.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 1056[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should fetch CONTRACT drawings successfully [33m 346[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-numbering.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 750[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรดึงข้อมูล metrics สำเร็จ [33m 344[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-correspondence.test.ts [2m([22m[2m12 tests[22m[2m)[22m[33m 735[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should fetch correspondences successfully [33m 349[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflows.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 681[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-rfa.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 804[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflow-history.test.ts [2m([22m[2m8 tests[22m[2m)[22m[33m 826[2mms[22m[39m
|
||||
[32m✓[39m components/drawings/__tests__/list.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 405[2mms[22m[39m
|
||||
[32m✓[39m components/search/__tests__/results.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 1713[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render loading state เมื่อ loading=true [33m 1269[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/version-history.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 391[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-projects.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 442[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-users.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 558[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-review-teams.test.ts [2m([22m[2m11 tests[22m[2m)[22m[33m 470[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-ai-prompts.test.ts [2m([22m[2m11 tests[22m[2m)[22m[33m 627[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/circulation-status-card.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 484[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/workflow-error-boundary.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 221[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/error-display.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 358[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-circulation.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 297[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-editor.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 414[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render editor สำหรับแก้ไขพรอมต์เทมเพลต [33m 306[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-dashboard.test.ts [2m([22m[2m4 tests[22m[2m)[22m[33m 368[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-transmittal.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 299[2mms[22m[39m
|
||||
[32m✓[39m components/transmittal/__tests__/transmittal-list.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 339[2mms[22m[39m
|
||||
[32m✓[39m components/auth/__tests__/auth-sync.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[33m 304[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/can.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 312[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/auth-store.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 197[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-ai-chat.test.ts [2m([22m[2m4 tests[22m[2m)[22m[33m 373[2mms[22m[39m
|
||||
|
||||
⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
|
||||
Error: Something removed the coverage directory "E:/np-dms/lcbp3/frontend/coverage/.tmp" Vitest created earlier. Make sure you are not running multiple Vitests with the same "coverage.reportsDirectory" at the same time.
|
||||
❯ V8CoverageProvider.normalizeCoverageFileError ../node_modules/.pnpm/vitest@4.1.8_@opentelemetry_fead2092ffa2420d46ccc7b523d0a1ee/node_modules/vitest/dist/chunks/coverage.DM_a_rWm.js:729:128
|
||||
❯ ../node_modules/.pnpm/vitest@4.1.8_@opentelemetry_fead2092ffa2420d46ccc7b523d0a1ee/node_modules/vitest/dist/chunks/coverage.DM_a_rWm.js:745:15
|
||||
|
||||
Caused by: Error: ENOENT: no such file or directory, open 'E:\np-dms\lcbp3\frontend\coverage\.tmp\coverage-75.json'
|
||||
❯ open node:internal/fs/promises:640:25
|
||||
❯ Object.writeFile node:internal/fs/promises:1257:14
|
||||
|
||||
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
|
||||
Serialized Error: { errno: -4058, code: 'ENOENT', syscall: 'open', path: 'E:\np-dms\lcbp3\frontend\coverage\.tmp\coverage-75.json' }
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,958 @@
|
||||
Loaded vitest@4.1.8 and @vitest/coverage-v8@4.1.6 .
|
||||
Running mixed versions is not supported and may lead into bugs
|
||||
Update your dependencies and make sure the versions match.
|
||||
|
||||
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.8 [39m[90mE:/np-dms/lcbp3/frontend[39m
|
||||
[2mCoverage enabled with [22m[33mv8[39m
|
||||
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > creates a user with required fields and selected role
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/admin/__tests__/sidebar.test.tsx > AdminMobileSidebar > opens mobile navigation from trigger button
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
[32m✓[39m components/admin/__tests__/sidebar.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 4137[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m auto-expands the active menu and renders child links [33m 1931[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m toggles a collapsed menu on click [33m 1249[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m opens mobile navigation from trigger button [33m 945[2mms[22m[39m
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
stderr | components/layout/__tests__/user-nav.test.tsx > UserNav Component > ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
The current testing environment is not configured to support act(...)
|
||||
|
||||
[32m✓[39m components/workflow/__tests__/integrated-banner.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 5683[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders metadata, priority, workflow state, and legacy actions [33m 1750[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m requires comment for reject action [33m 3667[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/user-nav.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 5638[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์อักษรย่อชื่อผู้ใช้ได้อย่างถูกต้อง [33m 370[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงรายละเอียดผู้ใช้ใน DropdownMenuContent (forceMount) [33m 2136[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนเส้นทางไปหน้า Profile เมื่อคลิกเมนู Profile [33m 1145[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปลี่ยนเส้นทางไปหน้า Settings เมื่อคลิกเมนู Settings [33m 1108[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรออกจากระบบและเปลี่ยนเส้นทางไปหน้า Login เมื่อคลิกเมนู Log out [33m 860[2mms[22m[39m
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > pre-fills existing user and submits update without empty password
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/correspondences/form.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 5784[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m keeps edit prefilled values after mount (no reset on initial render) [33m 4365[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m keeps dependent fields intact after async effects (reset guard) [33m 1406[2mms[22m[39m
|
||||
stderr | components/admin/__tests__/user-dialog.test.tsx > UserDialog > closes when cancel is clicked
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/admin/__tests__/user-dialog.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 9493[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m creates a user with required fields and selected role [33m 6627[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m pre-fills existing user and submits update without empty password [33m 2132[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m closes when cancel is clicked [33m 724[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/form.test.tsx [2m([22m[2m27 tests[22m[2m)[22m[33m 11328[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render form with all required fields [33m 1363[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render optional fields [33m 669[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render submit button [33m 468[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render AI suggestion button [33m 470[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty project [33m 790[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty contract [33m 570[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty discipline [33m 521[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty type [33m 439[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for short subject [33m 514[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty to organization [33m 546[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow subject input [33m 353[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow description input [33m 355[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow body input [33m 310[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should allow remarks input [33m 417[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render shop drawing section [33m 305[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render as-built drawing section [33m 379[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show search input for as-built drawings [33m 394[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show preview section when form is valid [33m 791[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display preview number [33m 797[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should call create mutation on valid submit [33m 371[2mms[22m[39m
|
||||
[32m✓[39m components/transmittal/__tests__/transmittal-form.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 15758[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders main sections and supports cancel navigation [33m 3523[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m shows validation errors when required fields are missing [33m 1546[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m submits cleaned transmittal payload and navigates to created record [33m 10669[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/manual-override-form.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m 4130[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render form with all required fields [33m 645[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render with default projectId from props [33m 409[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty project [33m 478[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should show validation error for empty recipient [33m 336[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should submit form with valid data [33m 485[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should reset form after successful submission [33m 343[2mms[22m[39m
|
||||
stderr | components/admin/reference/__tests__/generic-crud-table.test.tsx > GenericCrudTable > creates a new item from dialog form
|
||||
Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent}.
|
||||
|
||||
[32m✓[39m components/admin/__tests__/organization-dialog.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 5041[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ Dialog เมื่อ open เป็น true [33m 876[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง title "New Organization" เมื่อไม่มี organization prop [33m 441[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง title "Edit Organization" เมื่อมี organization prop [33m 409[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Cancel และ Create Organization สำหรับ New [33m 1481[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Save Changes สำหรับ Edit [33m 765[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก onOpenChange(false) เมื่อคลิก Cancel [33m 365[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง validation error เมื่อ submit form ว่างเปล่า [33m 559[2mms[22m[39m
|
||||
stderr | components/admin/reference/__tests__/generic-crud-table.test.tsx > GenericCrudTable > creates a new item from dialog form
|
||||
Checkbox is changing from controlled to uncontrolled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
|
||||
|
||||
[32m✓[39m components/admin/reference/__tests__/generic-crud-table.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 4817[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders data rows returned by fetchFn [33m 563[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m creates a new item from dialog form [33m 3956[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/file-preview-modal.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 4450[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders iframe for PDF MIME type [33m 2034[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders img for image MIME type [33m 707[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m shows download link for unsupported MIME type (no iframe or img) [33m 633[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onClose when close button is clicked [33m 686[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onUnavailable when API returns 404 [33m 372[2mms[22m[39m
|
||||
[32m✓[39m components/ui/__tests__/button.test.tsx [2m([22m[2m17 tests[22m[2m)[22m[33m 2486[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render with default variant and size [33m 1304[2mms[22m[39m
|
||||
[32m✓[39m components/workflow/__tests__/workflow-lifecycle.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 3103[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders history steps and opens available attachments [33m 1627[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m uploads and removes pending workflow step attachments [33m 909[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/detail.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[33m 5793[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์รายละเอียดเอกสารและข้อมูลพื้นฐานได้ถูกต้อง [33m 899[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่มและส่งคำขอเมื่อกด Submit for Review ในกรณีที่เป็น DRAFT [33m 1556[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงข้อความเตือนภัยและซ่อนปุ่มการกระทำบางอย่างหากเอกสารถูกยกเลิก [33m 399[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Approve และ Reject ในกรณีที่เอกสารเป็น IN_REVIEW [33m 753[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดการกดยืนยันการอนุมัติและส่งความคิดเห็นได้ถูกต้อง [33m 1167[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดส่วนยกเลิกเอกสารและส่งเหตุผลการยกเลิกได้ถูกต้อง [33m 849[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/sequence-viewer.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 1987[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render loading state initially [33m 468[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should filter sequences by type [33m 338[2mms[22m[39m
|
||||
[32m✓[39m components/admin/security/__tests__/rbac-matrix.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 3438[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders roles and permissions from API data [33m 1689[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m saves pending permission changes [33m 1533[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/detail.test.tsx [2m([22m[2m19 tests[22m[2m)[22m[33m 2276[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render RFA detail with data [33m 565[2mms[22m[39m
|
||||
[32m✓[39m components/response-code/ResponseCodeSelector.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 1536[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders the trigger with placeholder text [33m 1289[2mms[22m[39m
|
||||
stderr | components/layout/__tests__/layout-widgets.test.tsx > layout widgets > ProjectSwitcher ควรเลือก project และ global ได้
|
||||
In HTML, <div> cannot be a child of <select>.
|
||||
This will cause a hydration error.
|
||||
|
||||
<ProjectSwitcher>
|
||||
<Select value="global" onValueChange={function onValueChange}>
|
||||
> <select data-testid="project-select" value="global" onChange={function onChange}>
|
||||
<SelectTrigger className="w-[200px] ...">
|
||||
> <div className="flex items-center gap-2 truncate">
|
||||
...
|
||||
|
||||
<select> cannot contain a nested <div>.
|
||||
See this log for the ancestor stack trace.
|
||||
|
||||
[32m✓[39m components/workflows/__tests__/dsl-editor.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 2877[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls workflowApi.validateDSL when Validate button is clicked [33m 1271[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(true) when validation returns errors [33m 407[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(false) when validation returns valid [33m 339[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m calls onValidationChange(true) on server error [33m 389[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m does not call onValidationChange when prop is not provided [33m 461[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/layout-widgets.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 3105[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m Sidebar ควรแสดงเมนู admin และ collapse label ได้ [33m 1501[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m GlobalSearch ควร submit query และเปิด suggestion route ได้ [33m 946[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/confirm-dialog.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 2383[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์เนื้อหาและปุ่มต่างๆ ได้อย่างถูกต้องเมื่อเปิดใช้งาน [33m 1947[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก onConfirm เมื่อกดปุ่มยืนยันสำเร็จ [33m 425[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/navbar.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 2491[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ header ได้ถูกต้อง [33m 1595[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก toggleSidebar เมื่อคลิกปุ่ม menu [33m 570[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/tag-manager.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 1245[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรียก remove mutation เมื่อคลิกปุ่มลบ tag และมีสิทธิ์แก้ไข [33m 622[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเปิดส่วนเลือก tag และแสดง tag ที่พร้อมให้เพิ่มเมื่อคลิก Add Tag [33m 330[2mms[22m[39m
|
||||
[32m✓[39m components/drawings/__tests__/card.test.tsx [2m([22m[2m19 tests[22m[2m)[22m[33m 2380[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display discipline code from string [33m 334[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-type-dropdown.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 1876[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render dropdown สำหรับเลือกประเภทพรอมต์ [33m 1544[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disabled dropdown เมื่อ disabled=true [33m 323[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/pagination.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 2902[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ข้อมูลหน้าปัจจุบัน หน้าทั้งหมด และรายการทั้งหมดสำเร็จ [33m 1714[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/ocr-engine-selector.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 3054[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders OCR engine data from admin service [33m 484[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m selects a non-active OCR engine and refreshes list [33m 2435[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-version-history.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 4095[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders loading and empty states [33m 340[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders versions and triggers version actions [33m 3746[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/notifications-dropdown.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 2114[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render notification bell icon [33m 1429[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง "No new notifications" เมื่อไม่มี notification [33m 551[2mms[22m[39m
|
||||
[32m✓[39m components/rfas/__tests__/list.test.tsx [2m([22m[2m11 tests[22m[2m)[22m[33m 1934[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render RFA list with data [33m 676[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should display status badges [33m 505[2mms[22m[39m
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร render form สำหรับตั้งค่าบริบทข้อมูล
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร render form สำหรับตั้งค่าบริบทข้อมูล
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร disabled ปุ่มบันทึกเมื่อ isSaving=true
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
stderr | components/admin/ai/__tests__/context-config-editor.test.tsx > ContextConfigEditor > ควร disabled ปุ่มบันทึกเมื่อ isSaving=true
|
||||
An update to ContextConfigEditor inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
[32m✓[39m components/admin/ai/__tests__/context-config-editor.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 1467[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render form สำหรับตั้งค่าบริบทข้อมูล [33m 855[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disabled ปุ่มบันทึกเมื่อ isSaving=true [33m 602[2mms[22m[39m
|
||||
[32m✓[39m components/ai/__tests__/ai-suggestion-button.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 1361[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disable และแสดงข้อความ fallback เมื่อ AI ถูกปิด [33m 1202[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/sandbox-tabs.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 1793[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render 3-step sandbox testing interface [33m 1139[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร disabled ปุ่ม Run OCR เมื่อไม่มีไฟล์ [33m 644[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/global-search.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 2137[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render search input [33m 534[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดง loading spinner เมื่อกำลังโหลด [33m 1386[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/header.test.tsx [2m([22m[2m1 test[22m[2m)[22m[33m 1857[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m renders application title and composed controls [33m 1848[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/user-menu.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 2562[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render user menu เมื่อมี user [33m 2179[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/sidebar.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 3997[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render sidebar พร้อม navigation items [33m 617[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรไม่แสดง Admin Panel เมื่อ user ไม่ใช่ admin [33m 372[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render mobile sidebar พร้อม navigation items [33m 2750[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/ocr-sandbox-prompt-manager.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 2090[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render sandbox tab พร้อม project, contract, engine และ history [33m 1161[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรสลับไป editor และบันทึก prompt version ได้ [33m 387[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร load template จาก history เข้า editor [33m 533[2mms[22m[39m
|
||||
[32m✓[39m hooks/ai/__tests__/use-intent-classification.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 1413[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรดึง definitions สำเร็จ [33m 306[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรดึง definition ตาม intentCode [33m 428[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/project-switcher.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 1614[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render skeleton เมื่อกำลังโหลด [33m 1404[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-master-data.test.ts [2m([22m[2m15 tests[22m[2m)[22m[33m 1549[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรดึงข้อมูลองค์กรสำเร็จ [33m 466[2mms[22m[39m
|
||||
[32m✓[39m components/numbering/__tests__/metrics-dashboard.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[33m 1374[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m should render metrics after successful fetch [33m 449[2mms[22m[39m
|
||||
[32m✓[39m components/ai/__tests__/ai-chat-panel.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 1839[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์คอมโพเนนต์อย่างถูกต้อง [33m 988[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-correspondence.test.ts [2m([22m[2m12 tests[22m[2m)[22m[33m 681[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/list.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 978[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์รายชื่อเอกสารและหัวตารางได้ถูกต้อง [33m 380[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflow-action.test.ts [2m([22m[2m8 tests[22m[2m)[22m[33m 724[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-drawing.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 682[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/prompt-editor.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[33m 366[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควร render editor สำหรับแก้ไขพรอมต์เทมเพลต [33m 316[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflow-history.test.ts [2m([22m[2m8 tests[22m[2m)[22m[33m 660[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-workflows.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 558[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-numbering.test.ts [2m([22m[2m9 tests[22m[2m)[22m[33m 610[2mms[22m[39m
|
||||
[32m✓[39m components/circulation/__tests__/circulation-list.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 765[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-rfa.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 636[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-projects.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 503[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/error-display.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 414[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-review-teams.test.ts [2m([22m[2m11 tests[22m[2m)[22m[33m 446[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/dashboard-shell.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 199[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-users.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 480[2mms[22m[39m
|
||||
[32m✓[39m components/admin/ai/__tests__/version-history.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 512[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-ai-chat.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 229[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-dashboard.test.ts [2m([22m[2m4 tests[22m[2m)[22m[33m 330[2mms[22m[39m
|
||||
stderr | components/admin/ai/__tests__/runtime-parameters-panel.test.tsx > RuntimeParametersPanel > ควร render panel พารามิเตอร์เมื่อโหลดสำเร็จ
|
||||
An update to RuntimeParametersPanel inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
An update to RuntimeParametersPanel inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
[32m✓[39m components/admin/ai/__tests__/runtime-parameters-panel.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 240[2mms[22m[39m
|
||||
[32m✓[39m components/correspondences/circulation-status-card.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[33m 497[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/can.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 280[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/status-badge.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 806[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ Draft สำหรับสถานะ DRAFT ได้อย่างถูกต้อง [33m 617[2mms[22m[39m
|
||||
[32m✓[39m components/layout/__tests__/theme-toggle.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 752[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรแสดงปุ่ม Toggle White/Dark mode [33m 489[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-circulation.test.ts [2m([22m[2m5 tests[22m[2m)[22m[33m 386[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-transmittal.test.ts [2m([22m[2m4 tests[22m[2m)[22m[33m 316[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-delegation.test.ts [2m([22m[2m6 tests[22m[2m)[22m[33m 1037[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรดึงข้อมูล delegations ของฉันสำเร็จ [33m 725[2mms[22m[39m
|
||||
[32m✓[39m components/common/__tests__/workflow-error-boundary.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[33m 420[2mms[22m[39m
|
||||
[33m[2m✓[22m[39m ควรเรนเดอร์ children ตามปกติเมื่อไม่มีข้อผิดพลาด [33m 319[2mms[22m[39m
|
||||
[32m✓[39m components/auth/__tests__/auth-sync.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[32m 299[2mms[22m[39m
|
||||
[32m✓[39m hooks/__tests__/use-ai-prompts.test.ts [2m([22m[2m11 tests[22m[2m)[22m[33m 465[2mms[22m[39m
|
||||
[32m✓[39m components/drawings/__tests__/list.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 577[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/ui-store.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 143[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/draft-store.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 166[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/project-store.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 114[2mms[22m[39m
|
||||
[32m✓[39m lib/stores/__tests__/auth-store.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 219[2mms[22m[39m
|
||||
[32m✓[39m components/transmittal/__tests__/transmittal-list.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 322[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/master-data.service.test.ts [2m([22m[2m26 tests[22m[2m)[22m[32m 56[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/workflow-engine.service.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 49[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/drawing-master-data.service.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 41[2mms[22m[39m
|
||||
[32m✓[39m lib/api/__tests__/client.test.ts [2m([22m[2m14 tests[22m[2m)[22m[32m 33[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/correspondence.service.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/dashboard.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/document-numbering.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/migration.service.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/session.service.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/user.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/rfa.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/contract.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/transmittal.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/project.service.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/ai.service.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/organization.service.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/review-team.service.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 27[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/shop-drawing.service.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/circulation.service.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/search.service.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/contract-drawing.service.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/asbuilt-drawing.service.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
||||
[32m✓[39m lib/utils/__tests__/uuid-guard.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
||||
[32m✓[39m lib/services/__tests__/audit-log.service.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 20[2mms[22m[39m
|
||||
[32m✓[39m lib/i18n/__tests__/index.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
||||
|
||||
[2m Test Files [22m [1m[32m103 passed[39m[22m[90m (103)[39m
|
||||
[2m Tests [22m [1m[32m722 passed[39m[22m[90m (722)[39m
|
||||
[2m Start at [22m 20:54:27
|
||||
[2m Duration [22m 172.63s[2m (transform 32.80s, setup 65.14s, import 218.87s, tests 169.88s, environment 519.10s)[22m
|
||||
|
||||
[34m % [39m[2mCoverage report from [22m[33mv8[39m
|
||||
-------------------|---------|----------|---------|---------|-------------------
|
||||
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
||||
-------------------|---------|----------|---------|---------|-------------------
|
||||
All files | 50.9 | 40.94 | 49.58 | 51.68 |
|
||||
components/admin | 77.23 | 72.34 | 63.46 | 80.73 |
|
||||
...on-dialog.tsx | 71.42 | 72.22 | 66.66 | 75 | 81-90
|
||||
sidebar.tsx | 76.59 | 77.77 | 60 | 79.48 | ...47-275,298-321
|
||||
user-dialog.tsx | 80 | 70.11 | 66.66 | 84 | ...62-283,313-315
|
||||
...nents/admin/ai | 41.66 | 34.21 | 34.84 | 42.8 |
|
||||
...figEditor.tsx | 63.82 | 33.33 | 53.84 | 66.66 | ...20-129,153-192
|
||||
...eSelector.tsx | 96.15 | 95.45 | 100 | 96.15 | 44
|
||||
...ptManager.tsx | 36.88 | 22.36 | 25 | 38.36 | ...86-673,691-964
|
||||
PromptEditor.tsx | 69.23 | 63.63 | 66.66 | 70.83 | ...9,57-61,87,121
|
||||
...eDropdown.tsx | 50 | 100 | 50 | 50 | 31
|
||||
...onHistory.tsx | 100 | 100 | 100 | 100 |
|
||||
...tersPanel.tsx | 35.29 | 25.8 | 20 | 36.92 | ...07-115,128-265
|
||||
SandboxTabs.tsx | 21.62 | 25.31 | 5.88 | 21.62 | ...01-202,227-445
|
||||
...onHistory.tsx | 62.5 | 83.33 | 40 | 62.5 | 98-118
|
||||
...dmin/reference | 54.09 | 54.54 | 40.74 | 53.33 |
|
||||
...rud-table.tsx | 54.09 | 54.54 | 40.74 | 53.33 | ...76,181,259-323
|
||||
...admin/security | 93.87 | 77.41 | 88.23 | 93.61 |
|
||||
rbac-matrix.tsx | 93.87 | 77.41 | 88.23 | 93.61 | 46,98,104
|
||||
components/ai | 23.7 | 17.75 | 25.8 | 25 |
|
||||
...tusBanner.tsx | 0 | 0 | 0 | 0 | 18-40
|
||||
...hatWidget.tsx | 0 | 0 | 0 | 0 | 40-286
|
||||
...hat-input.tsx | 52.94 | 21.42 | 40 | 52.94 | 21-24,28-30,45
|
||||
...-messages.tsx | 54.38 | 56.66 | 100 | 57.4 | ...80,83-88,91-92
|
||||
...hat-panel.tsx | 75 | 33.33 | 80 | 72.72 | 32-34
|
||||
...at-toggle.tsx | 0 | 0 | 0 | 0 | 16
|
||||
...nner-host.tsx | 0 | 0 | 0 | 0 | 13-23
|
||||
...on-button.tsx | 100 | 100 | 100 | 100 |
|
||||
...ion-field.tsx | 0 | 0 | 0 | 0 | 14-147
|
||||
...ison-view.tsx | 0 | 0 | 0 | 0 | 12-133
|
||||
...indicator.tsx | 0 | 100 | 0 | 0 | 8
|
||||
...classification | 0 | 0 | 0 | 0 |
|
||||
...sult-card.tsx | 0 | 0 | 0 | 0 | 17-42
|
||||
intent-form.tsx | 0 | 0 | 0 | 0 | 54-123
|
||||
pattern-form.tsx | 0 | 0 | 0 | 0 | 55-164
|
||||
...ole-panel.tsx | 0 | 0 | 0 | 0 | 20-89
|
||||
...tion/analytics | 0 | 0 | 0 | 0 |
|
||||
...ary-cards.tsx | 0 | 0 | 0 | 0 | 19-49
|
||||
...own-table.tsx | 0 | 0 | 0 | 0 | 26-46
|
||||
...own-table.tsx | 0 | 0 | 0 | 0 | 24-61
|
||||
...ion-panel.tsx | 0 | 0 | 0 | 0 | 28-61
|
||||
components/auth | 100 | 92.85 | 100 | 100 |
|
||||
auth-sync.tsx | 100 | 92.85 | 100 | 100 | 43-45
|
||||
...ts/circulation | 100 | 95.45 | 100 | 100 |
|
||||
...tion-list.tsx | 100 | 95.45 | 100 | 100 | 120
|
||||
components/common | 91.11 | 88.88 | 96.96 | 92 |
|
||||
can.tsx | 100 | 100 | 100 | 100 |
|
||||
...rm-dialog.tsx | 100 | 100 | 100 | 100 |
|
||||
data-table.tsx | 100 | 66.66 | 100 | 100 | 41,50
|
||||
...r-display.tsx | 93.33 | 93.61 | 100 | 92.85 | 69,94
|
||||
...iew-modal.tsx | 87.8 | 84.61 | 88.88 | 90.9 | 35,76,92
|
||||
pagination.tsx | 100 | 100 | 100 | 100 |
|
||||
status-badge.tsx | 78.26 | 77.77 | 100 | 78.26 | 37-38,48-50
|
||||
...-boundary.tsx | 100 | 100 | 100 | 100 |
|
||||
...orrespondences | 48.69 | 43.65 | 50.37 | 49.87 |
|
||||
...atus-card.tsx | 100 | 83.33 | 100 | 100 | 30-32,51-52,94
|
||||
...s-content.tsx | 0 | 0 | 0 | 0 | 17-212
|
||||
detail.tsx | 80.64 | 67.74 | 77.27 | 88.67 | ...93,151,195,238
|
||||
form.tsx | 55.55 | 43.08 | 53.33 | 56.2 | ...43,564,593-729
|
||||
list.tsx | 92.85 | 67.74 | 100 | 96.29 | 112
|
||||
...-selector.tsx | 0 | 0 | 0 | 0 | 38-203
|
||||
...n-history.tsx | 0 | 0 | 0 | 0 | 13-56
|
||||
tag-manager.tsx | 92.85 | 88.46 | 84.61 | 91.66 | 24,131
|
||||
...ow-dialog.tsx | 0 | 0 | 0 | 0 | 15-198
|
||||
components/custom | 1.35 | 0 | 0 | 1.4 |
|
||||
...load-zone.tsx | 2 | 0 | 0 | 2.12 | 35-187
|
||||
...isualizer.tsx | 0 | 0 | 0 | 0 | 30-68
|
||||
...ents/dashboard | 0 | 0 | 0 | 0 |
|
||||
...ing-tasks.tsx | 0 | 0 | 0 | 0 | 15-55
|
||||
...k-actions.tsx | 0 | 100 | 0 | 0 | 8
|
||||
...-activity.tsx | 0 | 0 | 0 | 0 | 16-51
|
||||
stats-cards.tsx | 0 | 0 | 0 | 0 | 13-58
|
||||
...nts/delegation | 0 | 0 | 0 | 0 |
|
||||
...ationForm.tsx | 0 | 0 | 0 | 0 | 29-162
|
||||
...s/distribution | 0 | 0 | 0 | 0 |
|
||||
...ionStatus.tsx | 0 | 0 | 0 | 0 | 30-54
|
||||
...cuments/common | 0 | 0 | 0 | 0 |
|
||||
...ata-table.tsx | 0 | 0 | 0 | 0 | 39-161
|
||||
...nents/drawings | 12.26 | 25.87 | 6.06 | 13.13 |
|
||||
card.tsx | 100 | 96.15 | 100 | 100 | 73
|
||||
columns.tsx | 10 | 0 | 0 | 10 | 21-66
|
||||
list.tsx | 100 | 100 | 100 | 100 |
|
||||
...n-history.tsx | 0 | 0 | 0 | 0 | 11-17
|
||||
upload-form.tsx | 0 | 0 | 0 | 0 | 29-435
|
||||
components/layout | 93.83 | 86.3 | 93.75 | 93.52 |
|
||||
...ard-shell.tsx | 100 | 100 | 100 | 100 |
|
||||
...al-search.tsx | 86.48 | 67.85 | 92.85 | 85.71 | 24,44,62-66
|
||||
header.tsx | 100 | 100 | 100 | 100 |
|
||||
navbar.tsx | 100 | 100 | 100 | 100 |
|
||||
...-dropdown.tsx | 100 | 78.94 | 100 | 100 | 24,28-31,67
|
||||
...-switcher.tsx | 100 | 100 | 100 | 100 |
|
||||
sidebar.tsx | 90.9 | 96.66 | 77.77 | 90 | 152,224,236,250
|
||||
theme-toggle.tsx | 100 | 100 | 100 | 100 |
|
||||
user-menu.tsx | 100 | 75 | 100 | 100 | 34
|
||||
user-nav.tsx | 100 | 60 | 100 | 100 | 26-38
|
||||
...ents/migration | 0 | 0 | 0 | 0 |
|
||||
...eue-table.tsx | 0 | 0 | 0 | 0 | 58-479
|
||||
...ents/numbering | 29.94 | 19.69 | 31.57 | 29.94 |
|
||||
...ogs-table.tsx | 0 | 0 | 0 | 0 | 10-52
|
||||
...port-form.tsx | 0 | 0 | 0 | 0 | 11-38
|
||||
...mber-form.tsx | 0 | 0 | 0 | 0 | 14-72
|
||||
...ride-form.tsx | 100 | 80 | 100 | 100 | 45
|
||||
...dashboard.tsx | 100 | 100 | 100 | 100 |
|
||||
...ce-viewer.tsx | 100 | 93.33 | 100 | 100 | 21
|
||||
...te-editor.tsx | 0 | 0 | 0 | 0 | 16-181
|
||||
...te-tester.tsx | 0 | 0 | 0 | 0 | 36-182
|
||||
...lace-form.tsx | 0 | 0 | 0 | 0 | 15-91
|
||||
...nents/reminder | 0 | 0 | 0 | 0 |
|
||||
...erHistory.tsx | 0 | 0 | 0 | 0 | 21-55
|
||||
...rRuleForm.tsx | 0 | 0 | 0 | 0 | 15-129
|
||||
.../response-code | 26.41 | 17.33 | 20.83 | 26.53 |
|
||||
...lications.tsx | 0 | 0 | 0 | 0 | 14-72
|
||||
MatrixEditor.tsx | 0 | 0 | 0 | 0 | 44-134
|
||||
...deManager.tsx | 0 | 0 | 0 | 0 | 53-137
|
||||
...eSelector.tsx | 100 | 72.22 | 100 | 100 | 40,74-89
|
||||
...ts/review-task | 0 | 0 | 0 | 0 |
|
||||
...eviewForm.tsx | 0 | 0 | 0 | 0 | 24-88
|
||||
...atedBadge.tsx | 0 | 0 | 0 | 0 | 22-26
|
||||
...lProgress.tsx | 0 | 0 | 0 | 0 | 27-64
|
||||
...TaskInbox.tsx | 0 | 0 | 0 | 0 | 43-159
|
||||
...ideDialog.tsx | 0 | 0 | 0 | 0 | 25-87
|
||||
...ts/review-team | 0 | 0 | 0 | 0 |
|
||||
...wTeamForm.tsx | 0 | 0 | 0 | 0 | 22-136
|
||||
...mSelector.tsx | 0 | 0 | 0 | 0 | 17-67
|
||||
...erManager.tsx | 0 | 0 | 0 | 0 | 45-172
|
||||
components/rfas | 57.14 | 55.08 | 43.58 | 57.56 |
|
||||
detail.tsx | 58.13 | 64.28 | 62.5 | 58.53 | ...,82-92,189-194
|
||||
form.tsx | 55.08 | 50.23 | 30.18 | 55.68 | ...84,496,514-778
|
||||
list.tsx | 72.72 | 70.83 | 88.88 | 71.42 | 78-89
|
||||
components/search | 0 | 0 | 0 | 0 |
|
||||
filters.tsx | 0 | 0 | 0 | 0 | 10-81
|
||||
results.tsx | 0 | 0 | 0 | 0 | 16-68
|
||||
...ts/transmittal | 72.72 | 55.76 | 72.22 | 74.19 |
|
||||
...ttal-form.tsx | 93.61 | 75 | 89.28 | 93.47 | 100,317,405
|
||||
...ttal-list.tsx | 21.05 | 12.5 | 12.5 | 18.75 | 24-67
|
||||
components/ui | 90.84 | 79.06 | 80 | 90.84 |
|
||||
alert-dialog.tsx | 100 | 100 | 100 | 100 |
|
||||
alert.tsx | 90 | 100 | 66.66 | 90 | 31
|
||||
avatar.tsx | 100 | 100 | 100 | 100 |
|
||||
badge.tsx | 100 | 100 | 100 | 100 |
|
||||
button.tsx | 100 | 100 | 100 | 100 |
|
||||
calendar.tsx | 0 | 0 | 0 | 0 | 13-54
|
||||
card.tsx | 100 | 100 | 100 | 100 |
|
||||
checkbox.tsx | 100 | 100 | 100 | 100 |
|
||||
command.tsx | 91.66 | 100 | 75 | 91.66 | 83,104
|
||||
dialog.tsx | 100 | 100 | 100 | 100 |
|
||||
...down-menu.tsx | 92.3 | 42.85 | 71.42 | 92.3 | 79,98
|
||||
form.tsx | 97.29 | 90 | 100 | 97.29 | 43
|
||||
hover-card.tsx | 100 | 100 | 100 | 100 |
|
||||
input.tsx | 100 | 100 | 100 | 100 |
|
||||
label.tsx | 100 | 100 | 100 | 100 |
|
||||
popover.tsx | 100 | 100 | 100 | 100 |
|
||||
progress.tsx | 100 | 100 | 100 | 100 |
|
||||
scroll-area.tsx | 100 | 80 | 100 | 100 | 30
|
||||
select.tsx | 95.83 | 100 | 85.71 | 95.83 | 128
|
||||
separator.tsx | 100 | 75 | 100 | 100 | 16
|
||||
sheet.tsx | 86.95 | 100 | 50 | 86.95 | 73,78,94
|
||||
skeleton.tsx | 100 | 100 | 100 | 100 |
|
||||
sonner.tsx | 0 | 0 | 0 | 0 | 9-11
|
||||
switch.tsx | 100 | 100 | 100 | 100 |
|
||||
table.tsx | 91.66 | 100 | 75 | 91.66 | 28,67
|
||||
tabs.tsx | 0 | 100 | 0 | 0 | 8-53
|
||||
textarea.tsx | 100 | 100 | 100 | 100 |
|
||||
...nents/workflow | 83.63 | 81.48 | 78.57 | 88.54 |
|
||||
...ed-banner.tsx | 86.36 | 74.54 | 90 | 94.59 | 45,135
|
||||
...lifecycle.tsx | 81.81 | 88.67 | 72.22 | 84.74 | 57,60,63,255-261
|
||||
...ents/workflows | 15.38 | 15.32 | 12.12 | 16 |
|
||||
dsl-editor.tsx | 63.15 | 61.76 | 50 | 64.86 | 41-46,51,79-88
|
||||
...l-builder.tsx | 0 | 0 | 0 | 0 | 70-406
|
||||
hooks | 64.06 | 43.05 | 62.76 | 64.15 |
|
||||
use-ai-chat.ts | 84.21 | 50 | 75 | 88.88 | 18-21,85
|
||||
...ai-prompts.ts | 100 | 75 | 100 | 100 | 107,117-175
|
||||
use-ai-status.ts | 18.18 | 7.14 | 9.09 | 21.42 | 17-25,41-82
|
||||
...audit-logs.ts | 0 | 100 | 0 | 0 | 5-13
|
||||
...irculation.ts | 44.44 | 0 | 50 | 44.44 | 7,16-26
|
||||
...espondence.ts | 51.28 | 10 | 49.05 | 51.28 | 81,98-117,136-224
|
||||
use-dashboard.ts | 100 | 100 | 100 | 100 |
|
||||
...delegation.ts | 100 | 100 | 100 | 100 |
|
||||
...n-matrices.ts | 0 | 0 | 0 | 0 | 47-98
|
||||
use-drawing.ts | 63.15 | 54.16 | 62.5 | 62.96 | ...05,124,141-179
|
||||
...aster-data.ts | 100 | 61.53 | 100 | 100 | 39-72,98-99
|
||||
...ion-review.ts | 0 | 0 | 0 | 0 | 20-101
|
||||
...tification.ts | 0 | 100 | 0 | 0 | 5-28
|
||||
use-numbering.ts | 100 | 100 | 100 | 100 |
|
||||
use-projects.ts | 100 | 100 | 100 | 100 |
|
||||
...rence-data.ts | 0 | 0 | 0 | 0 | 10-118
|
||||
use-reminder.ts | 0 | 100 | 0 | 0 | 45-126
|
||||
...onse-codes.ts | 0 | 0 | 0 | 0 | 6-41
|
||||
...view-teams.ts | 100 | 50 | 100 | 100 | 27
|
||||
use-rfa.ts | 78.37 | 100 | 80 | 78.37 | 41-52,87
|
||||
use-search.ts | 0 | 0 | 0 | 0 | 5-23
|
||||
...anslations.ts | 0 | 100 | 0 | 0 | 9-12
|
||||
...ransmittal.ts | 100 | 100 | 100 | 100 |
|
||||
use-users.ts | 100 | 100 | 100 | 100 |
|
||||
...low-action.ts | 90.47 | 74.19 | 100 | 90.24 | 77-80,97,107
|
||||
...ow-history.ts | 100 | 100 | 100 | 100 |
|
||||
use-workflows.ts | 100 | 100 | 100 | 100 |
|
||||
hooks/ai | 44.11 | 100 | 48.14 | 44.11 |
|
||||
...sification.ts | 44.11 | 100 | 48.14 | 44.11 | 72-122
|
||||
lib | 6.66 | 0 | 23.07 | 6.94 |
|
||||
auth.ts | 0 | 0 | 0 | 0 | 9-232
|
||||
test-utils.tsx | 66.66 | 100 | 66.66 | 66.66 | 33-34
|
||||
utils.ts | 100 | 100 | 100 | 100 |
|
||||
lib/api | 18.77 | 23.12 | 5.2 | 21.14 |
|
||||
admin.ts | 0 | 0 | 0 | 0 | 4-111
|
||||
ai.ts | 0 | 0 | 0 | 0 | 9-222
|
||||
client.ts | 81.35 | 72.54 | 62.5 | 82.45 | 70-87,177
|
||||
dashboard.ts | 0 | 100 | 0 | 0 | 8-53
|
||||
drawings.ts | 0 | 100 | 0 | 0 | 4-41
|
||||
files.ts | 14.28 | 100 | 0 | 16.66 | 15-24
|
||||
notifications.ts | 0 | 0 | 0 | 0 | 4-49
|
||||
numbering.ts | 0 | 0 | 0 | 0 | 124-343
|
||||
workflows.ts | 0 | 0 | 0 | 0 | 4-86
|
||||
lib/i18n | 100 | 100 | 100 | 100 |
|
||||
index.ts | 100 | 100 | 100 | 100 |
|
||||
lib/services | 70.06 | 65.93 | 70.19 | 69.3 |
|
||||
...ai.service.ts | 6.38 | 0 | 2.77 | 6.38 | ...84-191,209-459
|
||||
...nt.service.ts | 0 | 0 | 0 | 0 | 9-229
|
||||
...ts.service.ts | 0 | 0 | 0 | 0 | 9-76
|
||||
ai.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ng.service.ts | 100 | 100 | 100 | 100 |
|
||||
...og.service.ts | 100 | 100 | 100 | 100 |
|
||||
...on.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ng.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ct.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ce.service.ts | 61.29 | 100 | 60 | 61.29 | ...2,67-68,90-115
|
||||
...rd.service.ts | 100 | 89.13 | 100 | 100 | 68,80-82
|
||||
...ng.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ta.service.ts | 100 | 82.35 | 100 | 100 | 117-149
|
||||
index.ts | 0 | 0 | 0 | 0 |
|
||||
...ma.service.ts | 0 | 100 | 0 | 0 | 5-69
|
||||
...ta.service.ts | 84.5 | 71.42 | 88.23 | 82.81 | ...46-147,226-241
|
||||
...on.service.ts | 88.23 | 59.45 | 100 | 87.87 | 29,67-77
|
||||
...ng.service.ts | 0 | 100 | 0 | 0 | 9-25
|
||||
...on.service.ts | 0 | 100 | 0 | 0 | 4-19
|
||||
...on.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ct.service.ts | 100 | 100 | 100 | 100 |
|
||||
...am.service.ts | 100 | 100 | 100 | 100 |
|
||||
rfa.service.ts | 100 | 100 | 100 | 100 |
|
||||
...ch.service.ts | 100 | 100 | 100 | 100 |
|
||||
...on.service.ts | 94.11 | 81.81 | 100 | 93.33 | 32
|
||||
...ng.service.ts | 100 | 100 | 100 | 100 |
|
||||
...al.service.ts | 100 | 100 | 100 | 100 |
|
||||
user.service.ts | 96.15 | 80 | 100 | 96 | 27
|
||||
...ne.service.ts | 96.72 | 66.17 | 100 | 96.49 | 51,62
|
||||
lib/stores | 100 | 100 | 100 | 100 |
|
||||
auth-store.ts | 100 | 100 | 100 | 100 |
|
||||
draft-store.ts | 100 | 100 | 100 | 100 |
|
||||
project-store.ts | 100 | 100 | 100 | 100 |
|
||||
ui-store.ts | 100 | 100 | 100 | 100 |
|
||||
lib/utils | 100 | 100 | 100 | 100 |
|
||||
uuid-guard.ts | 100 | 100 | 100 | 100 |
|
||||
-------------------|---------|----------|---------|---------|-------------------
|
||||
@@ -0,0 +1,82 @@
|
||||
// File: lib/__tests__/auth.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { getJwtExpiry, unwrapApiResponse, isTokenPayload } from '../auth';
|
||||
|
||||
// Mock NextAuth
|
||||
vi.mock('next-auth', () => ({
|
||||
default: vi.fn(() => ({
|
||||
handlers: { GET: vi.fn(), POST: vi.fn() },
|
||||
auth: vi.fn(),
|
||||
signIn: vi.fn(),
|
||||
signOut: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('auth.ts helper functions', () => {
|
||||
describe('getJwtExpiry', () => {
|
||||
it('ควรคำนวณ expiry time จาก valid JWT token', () => {
|
||||
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODAwMDAwMDB9.test';
|
||||
const expiry = getJwtExpiry(token);
|
||||
|
||||
expect(expiry).toBe(1680000000000);
|
||||
});
|
||||
|
||||
it('ควร return Date.now() เมื่อ token ไม่ valid', () => {
|
||||
const invalidToken = 'invalid.token.here';
|
||||
const expiry = getJwtExpiry(invalidToken);
|
||||
|
||||
expect(expiry).toBeLessThanOrEqual(Date.now() + 1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unwrapApiResponse', () => {
|
||||
it('ควร return value ทันทีเมื่อไม่ใช่ object', () => {
|
||||
const value = 'test string';
|
||||
const result = unwrapApiResponse(value);
|
||||
expect(result).toBe('test string');
|
||||
});
|
||||
|
||||
it('ควร unwrap data เมื่อไม่มี access_token', () => {
|
||||
const value = { data: { some: 'value' } };
|
||||
const result = unwrapApiResponse(value);
|
||||
expect(result).toEqual({ some: 'value' });
|
||||
});
|
||||
|
||||
it('ควร return value เมื่อมี access_token', () => {
|
||||
const value = { access_token: 'test_token' };
|
||||
const result = unwrapApiResponse(value);
|
||||
expect(result).toEqual({ access_token: 'test_token' });
|
||||
});
|
||||
|
||||
it('ควร unwrap data ซ้อนกันสูงสุด 5 ชั้น', () => {
|
||||
const value = { data: { data: { data: { data: { access_token: 'test_token' } } } } };
|
||||
const result = unwrapApiResponse(value);
|
||||
expect(result).toEqual({ access_token: 'test_token' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('isTokenPayload', () => {
|
||||
it('ควร return true เมื่อมี access_token เป็น string', () => {
|
||||
const value = { access_token: 'test_token' };
|
||||
expect(isTokenPayload(value)).toBe(true);
|
||||
});
|
||||
|
||||
it('ควร return false เมื่อไม่มี access_token', () => {
|
||||
const value = { some: 'value' };
|
||||
expect(isTokenPayload(value)).toBe(false);
|
||||
});
|
||||
|
||||
it('ควร return false เมื่อ access_token ไม่ใช่ string', () => {
|
||||
const value = { access_token: 123 };
|
||||
expect(isTokenPayload(value)).toBe(false);
|
||||
});
|
||||
|
||||
it('ควร return false เมื่อ value เป็น null', () => {
|
||||
const value = null;
|
||||
expect(isTokenPayload(value)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,123 @@
|
||||
// File: lib/api/__tests__/admin.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { adminApi } from '../admin';
|
||||
|
||||
describe('adminApi', () => {
|
||||
describe('getUsers', () => {
|
||||
it('ควร return array of users', async () => {
|
||||
const users = await adminApi.getUsers();
|
||||
|
||||
expect(Array.isArray(users)).toBe(true);
|
||||
expect(users.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('ควร return users ที่มี publicId, username, email', async () => {
|
||||
const users = await adminApi.getUsers();
|
||||
|
||||
expect(users[0]).toHaveProperty('publicId');
|
||||
expect(users[0]).toHaveProperty('username');
|
||||
expect(users[0]).toHaveProperty('email');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createUser', () => {
|
||||
it('ควร create user ใหม่และ return user object', async () => {
|
||||
const userData = {
|
||||
username: 'testuser',
|
||||
email: 'test@example.com',
|
||||
firstName: 'Test',
|
||||
lastName: 'User',
|
||||
isActive: true,
|
||||
roles: [2],
|
||||
};
|
||||
|
||||
const newUser = await adminApi.createUser(userData);
|
||||
|
||||
expect(newUser).toHaveProperty('publicId');
|
||||
expect(newUser.username).toBe('testuser');
|
||||
expect(newUser.email).toBe('test@example.com');
|
||||
});
|
||||
|
||||
it('ควร assign userId ใหม่ให้ user', async () => {
|
||||
const userData = {
|
||||
username: 'newuser',
|
||||
email: 'new@example.com',
|
||||
firstName: 'New',
|
||||
lastName: 'User',
|
||||
isActive: true,
|
||||
roles: [2],
|
||||
};
|
||||
|
||||
const newUser = await adminApi.createUser(userData);
|
||||
|
||||
expect(newUser.userId).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOrganizations', () => {
|
||||
it('ควร return array of organizations', async () => {
|
||||
const orgs = await adminApi.getOrganizations();
|
||||
|
||||
expect(Array.isArray(orgs)).toBe(true);
|
||||
expect(orgs.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('ควร return organizations ที่มี publicId, orgCode, orgName', async () => {
|
||||
const orgs = await adminApi.getOrganizations();
|
||||
|
||||
expect(orgs[0]).toHaveProperty('publicId');
|
||||
expect(orgs[0]).toHaveProperty('orgCode');
|
||||
expect(orgs[0]).toHaveProperty('orgName');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createOrganization', () => {
|
||||
it('ควร create organization ใหม่และ return org object', async () => {
|
||||
const orgData = {
|
||||
publicId: 'org-003',
|
||||
orgCode: 'TEST',
|
||||
orgName: 'Test Organization',
|
||||
description: 'Test description',
|
||||
};
|
||||
|
||||
const newOrg = await adminApi.createOrganization(orgData);
|
||||
|
||||
expect(newOrg).toHaveProperty('publicId');
|
||||
expect(newOrg.orgCode).toBe('TEST');
|
||||
expect(newOrg.orgName).toBe('Test Organization');
|
||||
});
|
||||
|
||||
it('ควร assign orgId ใหม่ให้ organization', async () => {
|
||||
const orgData = {
|
||||
publicId: 'org-004',
|
||||
orgCode: 'TEST2',
|
||||
orgName: 'Test Organization 2',
|
||||
description: 'Test description 2',
|
||||
};
|
||||
|
||||
const newOrg = await adminApi.createOrganization(orgData);
|
||||
|
||||
expect(newOrg.orgId).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAuditLogs', () => {
|
||||
it('ควร return array of audit logs', async () => {
|
||||
const logs = await adminApi.getAuditLogs();
|
||||
|
||||
expect(Array.isArray(logs)).toBe(true);
|
||||
expect(logs.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('ควร return logs ที่มี publicId, userName, action', async () => {
|
||||
const logs = await adminApi.getAuditLogs();
|
||||
|
||||
expect(logs[0]).toHaveProperty('publicId');
|
||||
expect(logs[0]).toHaveProperty('userName');
|
||||
expect(logs[0]).toHaveProperty('action');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
// File: lib/api/__tests__/ai.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { extractData } from '../ai';
|
||||
|
||||
describe('ai.ts helper functions', () => {
|
||||
describe('extractData', () => {
|
||||
it('ควร return value ทันทีเมื่อไม่ใช่ object', () => {
|
||||
const value = 'test string';
|
||||
const result = extractData(value);
|
||||
expect(result).toBe('test string');
|
||||
});
|
||||
|
||||
it('ควร return value ทันทีเมื่อไม่มี data property', () => {
|
||||
const value = { some: 'value' };
|
||||
const result = extractData(value);
|
||||
expect(result).toEqual({ some: 'value' });
|
||||
});
|
||||
|
||||
it('ควร unwrap data เมื่อมี data property', () => {
|
||||
const value = { data: { some: 'value' } };
|
||||
const result = extractData(value);
|
||||
expect(result).toEqual({ some: 'value' });
|
||||
});
|
||||
|
||||
it('ควร unwrap data ซ้อนกันสูงสุด 5 ชั้น', () => {
|
||||
const value = { data: { data: { data: { data: { data: 'final' } } } } };
|
||||
const result = extractData(value);
|
||||
expect(result).toBe('final');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
// File: lib/api/__tests__/dashboard.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { dashboardApi } from '../dashboard';
|
||||
|
||||
describe('dashboardApi', () => {
|
||||
describe('getStats', () => {
|
||||
it('ควร return dashboard stats', async () => {
|
||||
const stats = await dashboardApi.getStats();
|
||||
|
||||
expect(stats).toHaveProperty('totalDocuments');
|
||||
expect(stats).toHaveProperty('documentsThisMonth');
|
||||
expect(stats).toHaveProperty('pendingApprovals');
|
||||
expect(stats).toHaveProperty('approved');
|
||||
expect(stats).toHaveProperty('totalRfas');
|
||||
expect(stats).toHaveProperty('totalCirculations');
|
||||
});
|
||||
|
||||
it('ควร return numbers สำหรับ stats', async () => {
|
||||
const stats = await dashboardApi.getStats();
|
||||
|
||||
expect(typeof stats.totalDocuments).toBe('number');
|
||||
expect(typeof stats.documentsThisMonth).toBe('number');
|
||||
expect(typeof stats.pendingApprovals).toBe('number');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRecentActivity', () => {
|
||||
it('ควร return array of activity logs', async () => {
|
||||
const activities = await dashboardApi.getRecentActivity();
|
||||
|
||||
expect(Array.isArray(activities)).toBe(true);
|
||||
expect(activities.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('ควร return activities ที่มี id, user, action, description', async () => {
|
||||
const activities = await dashboardApi.getRecentActivity();
|
||||
|
||||
expect(activities[0]).toHaveProperty('id');
|
||||
expect(activities[0]).toHaveProperty('user');
|
||||
expect(activities[0]).toHaveProperty('action');
|
||||
expect(activities[0]).toHaveProperty('description');
|
||||
});
|
||||
|
||||
it('ควร return activities ที่มี user.name และ user.initials', async () => {
|
||||
const activities = await dashboardApi.getRecentActivity();
|
||||
|
||||
expect(activities[0].user).toHaveProperty('name');
|
||||
expect(activities[0].user).toHaveProperty('initials');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPendingTasks', () => {
|
||||
it('ควร return array of pending tasks', async () => {
|
||||
const tasks = await dashboardApi.getPendingTasks();
|
||||
|
||||
expect(Array.isArray(tasks)).toBe(true);
|
||||
expect(tasks.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('ควร return tasks ที่มี publicId, workflowCode, currentState', async () => {
|
||||
const tasks = await dashboardApi.getPendingTasks();
|
||||
|
||||
expect(tasks[0]).toHaveProperty('publicId');
|
||||
expect(tasks[0]).toHaveProperty('workflowCode');
|
||||
expect(tasks[0]).toHaveProperty('currentState');
|
||||
});
|
||||
|
||||
it('ควร return tasks ที่มี entityType, documentNumber, subject', async () => {
|
||||
const tasks = await dashboardApi.getPendingTasks();
|
||||
|
||||
expect(tasks[0]).toHaveProperty('entityType');
|
||||
expect(tasks[0]).toHaveProperty('documentNumber');
|
||||
expect(tasks[0]).toHaveProperty('subject');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
// File: lib/api/__tests__/drawings.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { drawingApi } from '../drawings';
|
||||
|
||||
describe('drawingApi', () => {
|
||||
describe('getAll', () => {
|
||||
it('ควร return array of drawings พร้อม meta', async () => {
|
||||
const result = await drawingApi.getAll();
|
||||
|
||||
expect(result).toHaveProperty('data');
|
||||
expect(result).toHaveProperty('meta');
|
||||
expect(Array.isArray(result.data)).toBe(true);
|
||||
});
|
||||
|
||||
it('ควร return drawings ที่มี publicId, drawingNumber, title', async () => {
|
||||
const result = await drawingApi.getAll();
|
||||
|
||||
expect(result.data[0]).toHaveProperty('publicId');
|
||||
expect(result.data[0]).toHaveProperty('drawingNumber');
|
||||
expect(result.data[0]).toHaveProperty('title');
|
||||
});
|
||||
|
||||
it('ควร return meta.total เท่ากับจำนวน drawings', async () => {
|
||||
const result = await drawingApi.getAll();
|
||||
|
||||
expect(result.meta.total).toBe(result.data.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getById', () => {
|
||||
it('ควร return drawing เมื่อ id ถูกต้อง', async () => {
|
||||
const drawing = await drawingApi.getById('dwg-001');
|
||||
|
||||
expect(drawing).toBeDefined();
|
||||
expect(drawing?.publicId).toBe('dwg-001');
|
||||
});
|
||||
|
||||
it('ควร return undefined เมื่อ id ไม่ถูกต้อง', async () => {
|
||||
const drawing = await drawingApi.getById('non-existent');
|
||||
|
||||
expect(drawing).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getByContract', () => {
|
||||
it('ควร return array of drawings สำหรับ contract', async () => {
|
||||
const result = await drawingApi.getByContract('contract-001');
|
||||
|
||||
expect(result).toHaveProperty('data');
|
||||
expect(Array.isArray(result.data)).toBe(true);
|
||||
});
|
||||
|
||||
it('ควร return drawings ที่มี discipline, status, revision', async () => {
|
||||
const result = await drawingApi.getByContract('contract-001');
|
||||
|
||||
expect(result.data[0]).toHaveProperty('discipline');
|
||||
expect(result.data[0]).toHaveProperty('status');
|
||||
expect(result.data[0]).toHaveProperty('revision');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
// File: lib/api/__tests__/notifications.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { notificationApi } from '../notifications';
|
||||
|
||||
describe('notificationApi', () => {
|
||||
beforeEach(() => {
|
||||
// Reset mock data before each test
|
||||
// Note: This is a simplified reset since the mock is in the same file
|
||||
});
|
||||
|
||||
describe('getUnread', () => {
|
||||
it('ควร return notifications พร้อม unreadCount', async () => {
|
||||
const result = await notificationApi.getUnread();
|
||||
|
||||
expect(result).toHaveProperty('items');
|
||||
expect(result).toHaveProperty('unreadCount');
|
||||
expect(Array.isArray(result.items)).toBe(true);
|
||||
});
|
||||
|
||||
it('ควร return notifications ที่มี publicId, title, message', async () => {
|
||||
const result = await notificationApi.getUnread();
|
||||
|
||||
expect(result.items[0]).toHaveProperty('publicId');
|
||||
expect(result.items[0]).toHaveProperty('title');
|
||||
expect(result.items[0]).toHaveProperty('message');
|
||||
});
|
||||
|
||||
it('ควร return notifications ที่มี type, isRead, createdAt', async () => {
|
||||
const result = await notificationApi.getUnread();
|
||||
|
||||
expect(result.items[0]).toHaveProperty('type');
|
||||
expect(result.items[0]).toHaveProperty('isRead');
|
||||
expect(result.items[0]).toHaveProperty('createdAt');
|
||||
});
|
||||
|
||||
it('ควร count unread notifications อย่างถูกต้อง', async () => {
|
||||
const result = await notificationApi.getUnread();
|
||||
|
||||
expect(typeof result.unreadCount).toBe('number');
|
||||
expect(result.unreadCount).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('markAsRead', () => {
|
||||
it('ควร mark notification เป็น read', async () => {
|
||||
await notificationApi.markAsRead(1);
|
||||
|
||||
const result = await notificationApi.getUnread();
|
||||
const notification = result.items.find((n) => n.notificationId === 1);
|
||||
|
||||
expect(notification?.isRead).toBe(true);
|
||||
});
|
||||
|
||||
it('ควรไม่ affect notifications อื่น', async () => {
|
||||
await notificationApi.markAsRead(1);
|
||||
|
||||
const result = await notificationApi.getUnread();
|
||||
const otherNotification = result.items.find((n) => n.notificationId === 2);
|
||||
|
||||
expect(otherNotification?.isRead).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,232 @@
|
||||
// File: lib/api/__tests__/numbering.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { numberingApi } from '../numbering';
|
||||
|
||||
// Mock apiClient
|
||||
vi.mock('@/lib/api/client', () => ({
|
||||
default: {
|
||||
get: vi.fn(),
|
||||
post: vi.fn(),
|
||||
patch: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
import apiClient from '@/lib/api/client';
|
||||
|
||||
describe('numberingApi', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getTemplates', () => {
|
||||
it('ควร return array of templates', async () => {
|
||||
const mockTemplates = [{ id: 1, formatTemplate: 'TEST-{YYYY}-{NNNN}' }];
|
||||
(apiClient.get as any).mockResolvedValue({ data: mockTemplates });
|
||||
|
||||
const result = await numberingApi.getTemplates();
|
||||
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result).toEqual(mockTemplates);
|
||||
});
|
||||
|
||||
it('ควร handle nested data structure', async () => {
|
||||
const mockTemplates = [{ id: 1, formatTemplate: 'TEST-{YYYY}-{NNNN}' }];
|
||||
(apiClient.get as any).mockResolvedValue({ data: { data: mockTemplates } });
|
||||
|
||||
const result = await numberingApi.getTemplates();
|
||||
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result).toEqual(mockTemplates);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTemplatesByProject', () => {
|
||||
it('ควร call API ด้วย projectId parameter', async () => {
|
||||
(apiClient.get as any).mockResolvedValue({ data: [] });
|
||||
|
||||
await numberingApi.getTemplatesByProject(1);
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/admin/document-numbering/templates?projectId=1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTemplate', () => {
|
||||
it('ควร return template เมื่อ id ถูกต้อง', async () => {
|
||||
const mockTemplates = [{ id: 1, formatTemplate: 'TEST-{YYYY}-{NNNN}' }];
|
||||
(apiClient.get as any).mockResolvedValue({ data: mockTemplates });
|
||||
|
||||
const result = await numberingApi.getTemplate(1);
|
||||
|
||||
expect(result).toEqual(mockTemplates[0]);
|
||||
});
|
||||
|
||||
it('ควร return undefined เมื่อ id ไม่พบ', async () => {
|
||||
const mockTemplates = [{ id: 1, formatTemplate: 'TEST-{YYYY}-{NNNN}' }];
|
||||
(apiClient.get as any).mockResolvedValue({ data: mockTemplates });
|
||||
|
||||
const result = await numberingApi.getTemplate(999);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveTemplate', () => {
|
||||
it('ควร call API ด้วย DTO ที่ clean แล้ว', async () => {
|
||||
const mockTemplate = { id: 1, formatTemplate: 'TEST-{YYYY}-{NNNN}' };
|
||||
(apiClient.post as any).mockResolvedValue({ data: mockTemplate });
|
||||
|
||||
const dto = {
|
||||
projectId: 1,
|
||||
correspondenceTypeId: null,
|
||||
formatTemplate: 'TEST-{YYYY}-{NNNN}',
|
||||
};
|
||||
|
||||
const result = await numberingApi.saveTemplate(dto);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/admin/document-numbering/templates', expect.any(Object));
|
||||
expect(result).toEqual(mockTemplate);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteTemplate', () => {
|
||||
it('ควร call API ด้วย id', async () => {
|
||||
(apiClient.delete as any).mockResolvedValue({});
|
||||
|
||||
await numberingApi.deleteTemplate(1);
|
||||
|
||||
expect(apiClient.delete).toHaveBeenCalledWith('/admin/document-numbering/templates/1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAuditLogs', () => {
|
||||
it('ควร return array of audit logs', async () => {
|
||||
const mockLogs = [{ id: 1, generatedNumber: 'TEST-001' }];
|
||||
(apiClient.get as any).mockResolvedValue({ data: mockLogs });
|
||||
|
||||
const result = await numberingApi.getAuditLogs();
|
||||
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result).toEqual(mockLogs);
|
||||
});
|
||||
|
||||
it('ควร call API ด้วย limit parameter', async () => {
|
||||
(apiClient.get as any).mockResolvedValue({ data: [] });
|
||||
|
||||
await numberingApi.getAuditLogs(50);
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/document-numbering/logs/audit?limit=50');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getErrorLogs', () => {
|
||||
it('ควร return array of error logs', async () => {
|
||||
const mockErrors = [{ id: 1, errorMessage: 'Test error' }];
|
||||
(apiClient.get as any).mockResolvedValue({ data: mockErrors });
|
||||
|
||||
const result = await numberingApi.getErrorLogs();
|
||||
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result).toEqual(mockErrors);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMetrics', () => {
|
||||
it('ควร return metrics ที่มี audit และ errors', async () => {
|
||||
const mockMetrics = { audit: [], errors: [] };
|
||||
(apiClient.get as any).mockResolvedValue({ data: mockMetrics });
|
||||
|
||||
const result = await numberingApi.getMetrics();
|
||||
|
||||
expect(result).toHaveProperty('audit');
|
||||
expect(result).toHaveProperty('errors');
|
||||
});
|
||||
});
|
||||
|
||||
describe('manualOverride', () => {
|
||||
it('ควร call API ด้วย DTO', async () => {
|
||||
const mockResponse = { success: true, message: 'Override successful' };
|
||||
(apiClient.post as any).mockResolvedValue({ data: mockResponse });
|
||||
|
||||
const dto = { projectId: 1, correspondenceTypeId: null, year: 2026, newValue: 100 };
|
||||
const result = await numberingApi.manualOverride(dto);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/admin/document-numbering/manual-override', dto);
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('voidAndReplace', () => {
|
||||
it('ควร call API ด้วย DTO', async () => {
|
||||
const mockResponse = { newNumber: 'TEST-002', auditId: 123 };
|
||||
(apiClient.post as any).mockResolvedValue({ data: mockResponse });
|
||||
|
||||
const dto = { documentId: 1, reason: 'Test reason' };
|
||||
const result = await numberingApi.voidAndReplace(dto);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/admin/document-numbering/void-and-replace', dto);
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancelNumber', () => {
|
||||
it('ควร call API ด้วย DTO', async () => {
|
||||
const mockResponse = { success: true };
|
||||
(apiClient.post as any).mockResolvedValue({ data: mockResponse });
|
||||
|
||||
const dto = { documentNumber: 'TEST-001', reason: 'Test reason' };
|
||||
const result = await numberingApi.cancelNumber(dto);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/admin/document-numbering/cancel', dto);
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulkImport', () => {
|
||||
it('ควร call API ด้วย items array', async () => {
|
||||
const mockResponse = { imported: 10, errors: [] };
|
||||
(apiClient.post as any).mockResolvedValue({ data: mockResponse });
|
||||
|
||||
const items = [{ projectId: 1, correspondenceTypeId: null, year: 2026, lastNumber: 100 }];
|
||||
const result = await numberingApi.bulkImport(items);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/admin/document-numbering/bulk-import', items);
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateCounter', () => {
|
||||
it('ควร call API ด้วย counterId และ sequence', async () => {
|
||||
(apiClient.patch as any).mockResolvedValue({});
|
||||
|
||||
await numberingApi.updateCounter(1, 100);
|
||||
|
||||
expect(apiClient.patch).toHaveBeenCalledWith('/document-numbering/counters/1', { sequence: 100 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('previewNumber', () => {
|
||||
it('ควร return preview number', async () => {
|
||||
const mockResponse = { previewNumber: 'TEST-2026-0001', nextSequence: 1, isDefault: true };
|
||||
(apiClient.post as any).mockResolvedValue({ data: mockResponse });
|
||||
|
||||
const ctx = { projectId: 1, originatorOrganizationId: 1, correspondenceTypeId: 1 };
|
||||
const result = await numberingApi.previewNumber(ctx);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/document-numbering/preview', ctx);
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateTestNumber', () => {
|
||||
it('ควร return mock test number', async () => {
|
||||
const result = await numberingApi.generateTestNumber(1, { organizationId: '1', disciplineId: '1' });
|
||||
|
||||
expect(result).toHaveProperty('number');
|
||||
expect(result.number).toMatch(/^TEST-\d{4}-\d{4}$/);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,133 @@
|
||||
// File: lib/api/__tests__/workflows.test.ts
|
||||
// Change Log:
|
||||
// - 2026-06-14: สร้างใหม่สำหรับ Phase 3 Coverage
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { workflowApi } from '../workflows';
|
||||
|
||||
describe('workflowApi', () => {
|
||||
beforeEach(() => {
|
||||
// Reset mock data before each test
|
||||
// Note: This is a simplified reset since the mock is in the same file
|
||||
});
|
||||
|
||||
describe('getWorkflows', () => {
|
||||
it('ควร return array of workflows', async () => {
|
||||
const workflows = await workflowApi.getWorkflows();
|
||||
|
||||
expect(Array.isArray(workflows)).toBe(true);
|
||||
expect(workflows.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('ควร return workflows ที่มี publicId, workflowName, workflowType', async () => {
|
||||
const workflows = await workflowApi.getWorkflows();
|
||||
|
||||
expect(workflows[0]).toHaveProperty('publicId');
|
||||
expect(workflows[0]).toHaveProperty('workflowName');
|
||||
expect(workflows[0]).toHaveProperty('workflowType');
|
||||
});
|
||||
|
||||
it('ควร return workflows ที่มี dslDefinition, version, isActive', async () => {
|
||||
const workflows = await workflowApi.getWorkflows();
|
||||
|
||||
expect(workflows[0]).toHaveProperty('dslDefinition');
|
||||
expect(workflows[0]).toHaveProperty('version');
|
||||
expect(workflows[0]).toHaveProperty('isActive');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getWorkflow', () => {
|
||||
it('ควร return workflow เมื่อ id ถูกต้อง', async () => {
|
||||
const workflow = await workflowApi.getWorkflow('wf-001');
|
||||
|
||||
expect(workflow).toBeDefined();
|
||||
expect(workflow?.publicId).toBe('wf-001');
|
||||
});
|
||||
|
||||
it('ควร return undefined เมื่อ id ไม่ถูกต้อง', async () => {
|
||||
const workflow = await workflowApi.getWorkflow('non-existent');
|
||||
|
||||
expect(workflow).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('createWorkflow', () => {
|
||||
it('ควร create workflow ใหม่และ return workflow object', async () => {
|
||||
const data = {
|
||||
workflowName: 'Test Workflow',
|
||||
description: 'Test description',
|
||||
workflowType: 'RFA',
|
||||
dslDefinition: 'name: Test\nsteps: []',
|
||||
};
|
||||
|
||||
const newWorkflow = await workflowApi.createWorkflow(data);
|
||||
|
||||
expect(newWorkflow).toHaveProperty('publicId');
|
||||
expect(newWorkflow.workflowName).toBe('Test Workflow');
|
||||
expect(newWorkflow.version).toBe(1);
|
||||
expect(newWorkflow.isActive).toBe(true);
|
||||
});
|
||||
|
||||
it('ควร assign workflowId ใหม่ให้ workflow', async () => {
|
||||
const data = {
|
||||
workflowName: 'New Workflow',
|
||||
description: 'New description',
|
||||
workflowType: 'CORRESPONDENCE',
|
||||
dslDefinition: 'name: New\nsteps: []',
|
||||
};
|
||||
|
||||
const newWorkflow = await workflowApi.createWorkflow(data);
|
||||
|
||||
expect(newWorkflow.workflowId).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateWorkflow', () => {
|
||||
it('ควร update workflow และ return updated object', async () => {
|
||||
const data = {
|
||||
workflowName: 'Updated Workflow',
|
||||
description: 'Updated description',
|
||||
};
|
||||
|
||||
const updatedWorkflow = await workflowApi.updateWorkflow('wf-001', data);
|
||||
|
||||
expect(updatedWorkflow.workflowName).toBe('Updated Workflow');
|
||||
expect(updatedWorkflow.description).toBe('Updated description');
|
||||
});
|
||||
|
||||
it('ควร throw error เมื่อ workflow ไม่พบ', async () => {
|
||||
const data = { workflowName: 'Test' };
|
||||
|
||||
await expect(workflowApi.updateWorkflow('non-existent', data)).rejects.toThrow('Workflow not found');
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateDSL', () => {
|
||||
it('ควร return valid=true เมื่อ DSL ถูกต้อง', async () => {
|
||||
const dsl = 'name: Test Workflow\nsteps:\n - name: Step 1\n type: REVIEW';
|
||||
|
||||
const result = await workflowApi.validateDSL(dsl);
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
expect(result.errors).toEqual([]);
|
||||
});
|
||||
|
||||
it('ควร return valid=false เมื่อ DSL ไม่มี name', async () => {
|
||||
const dsl = 'invalid dsl without name or steps';
|
||||
|
||||
const result = await workflowApi.validateDSL(dsl);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.errors.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('ควร return valid=false เมื่อ DSL ไม่มี steps', async () => {
|
||||
const dsl = 'name: Test Workflow';
|
||||
|
||||
const result = await workflowApi.validateDSL(dsl);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.errors.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -50,7 +50,7 @@ interface WrappedData<T> {
|
||||
data?: T;
|
||||
}
|
||||
|
||||
const extractData = <T>(value: unknown): T => {
|
||||
export const extractData = <T>(value: unknown): T => {
|
||||
let current: unknown = value;
|
||||
for (let index = 0; index < 5; index += 1) {
|
||||
if (!current || typeof current !== 'object' || !('data' in current)) {
|
||||
|
||||
@@ -17,7 +17,7 @@ const baseUrl =
|
||||
'http://localhost:3001/api';
|
||||
|
||||
// Helper to parse JWT expiry
|
||||
function getJwtExpiry(token: string): number {
|
||||
export function getJwtExpiry(token: string): number {
|
||||
try {
|
||||
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||
return payload.exp * 1000; // Convert to ms
|
||||
@@ -44,7 +44,7 @@ interface LoginPayload extends TokenPayload {
|
||||
};
|
||||
}
|
||||
|
||||
function unwrapApiResponse(value: unknown): unknown {
|
||||
export function unwrapApiResponse(value: unknown): unknown {
|
||||
let current = value;
|
||||
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
@@ -67,7 +67,7 @@ function unwrapApiResponse(value: unknown): unknown {
|
||||
return current;
|
||||
}
|
||||
|
||||
function isTokenPayload(value: unknown): value is TokenPayload {
|
||||
export function isTokenPayload(value: unknown): value is TokenPayload {
|
||||
return !!value && typeof value === 'object' && typeof (value as Record<string, unknown>).access_token === 'string';
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
// - 2026-06-13: T042-T043 — เพิ่ม applyProfile และ getProductionDefaults สำหรับปรับใช้และดึงค่า production parameters
|
||||
// - 2026-06-13: US4 — อัปเดต submitSandboxExtract และ submitSandboxAiExtract ให้รองรับ project/contract publicId
|
||||
|
||||
|
||||
import api from '../api/client';
|
||||
import { AiJobResponse } from '../../types/ai';
|
||||
import { PromptType, PromptVersion, ContextConfig } from '../types/ai-prompts';
|
||||
@@ -155,6 +154,21 @@ export interface SandboxProfileParams {
|
||||
keepAliveSeconds: number;
|
||||
}
|
||||
|
||||
export interface ExecutionProfile {
|
||||
id: number;
|
||||
profileName: string;
|
||||
canonicalModel?: 'np-dms-ai' | 'np-dms-ocr';
|
||||
temperature: number;
|
||||
topP: number;
|
||||
repeatPenalty: number;
|
||||
maxTokens: number | null;
|
||||
numCtx: number | null;
|
||||
keepAlive: number;
|
||||
isActive: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
const extractData = <T>(value: unknown): T => {
|
||||
if (value && typeof value === 'object' && 'data' in value) {
|
||||
return (value as { data: T }).data;
|
||||
@@ -162,9 +176,7 @@ const extractData = <T>(value: unknown): T => {
|
||||
return value as T;
|
||||
};
|
||||
|
||||
const normalizeLoadedModels = (
|
||||
models: Array<string | LoadedModelInfo> | undefined
|
||||
): LoadedModelInfo[] => {
|
||||
const normalizeLoadedModels = (models: Array<string | LoadedModelInfo> | undefined): LoadedModelInfo[] => {
|
||||
if (!Array.isArray(models)) {
|
||||
return [];
|
||||
}
|
||||
@@ -184,9 +196,7 @@ const normalizeVramStatus = (value: unknown): VramStatusResponse => {
|
||||
const raw = extractData<RawVramStatusResponse>(value);
|
||||
const totalVRAMMB = raw.totalVRAMMB ?? raw.totalVramMb ?? 0;
|
||||
const usedVRAMMB = raw.usedVRAMMB ?? raw.usedVramMb ?? 0;
|
||||
const usagePercent =
|
||||
raw.usagePercent ??
|
||||
(totalVRAMMB > 0 ? Math.round((usedVRAMMB / totalVRAMMB) * 100) : 0);
|
||||
const usagePercent = raw.usagePercent ?? (totalVRAMMB > 0 ? Math.round((usedVRAMMB / totalVRAMMB) * 100) : 0);
|
||||
|
||||
return {
|
||||
totalVRAMMB,
|
||||
@@ -199,6 +209,10 @@ const normalizeVramStatus = (value: unknown): VramStatusResponse => {
|
||||
};
|
||||
};
|
||||
|
||||
const createIdempotencyKey = (): string => {
|
||||
return globalThis.crypto?.randomUUID?.() ?? `idem-${Date.now()}`;
|
||||
};
|
||||
|
||||
/** Service สำหรับเรียก AI Admin Console API ผ่าน DMS Backend เท่านั้น */
|
||||
export const adminAiService = {
|
||||
getStatus: async (): Promise<AiAdminSettings> => {
|
||||
@@ -356,26 +370,18 @@ export const adminAiService = {
|
||||
updates: Partial<SandboxProfileParams>,
|
||||
idempotencyKey: string
|
||||
): Promise<SandboxProfileParams> => {
|
||||
const { data } = await api.put(
|
||||
`/ai/sandbox-profiles/${encodeURIComponent(profileName)}`,
|
||||
updates,
|
||||
{ headers: { 'Idempotency-Key': idempotencyKey } }
|
||||
);
|
||||
const { data } = await api.put(`/ai/sandbox-profiles/${encodeURIComponent(profileName)}`, updates, {
|
||||
headers: { 'Idempotency-Key': idempotencyKey },
|
||||
});
|
||||
return extractData<SandboxProfileParams>(data);
|
||||
},
|
||||
|
||||
resetSandboxProfile: async (profileName: string): Promise<SandboxProfileParams> => {
|
||||
const { data } = await api.post(
|
||||
`/ai/sandbox-profiles/${encodeURIComponent(profileName)}/reset`,
|
||||
{}
|
||||
);
|
||||
const { data } = await api.post(`/ai/sandbox-profiles/${encodeURIComponent(profileName)}/reset`, {});
|
||||
return extractData<SandboxProfileParams>(data);
|
||||
},
|
||||
|
||||
applyProfile: async (
|
||||
profileName: string,
|
||||
idempotencyKey: string
|
||||
): Promise<SandboxProfileParams> => {
|
||||
applyProfile: async (profileName: string, idempotencyKey: string): Promise<SandboxProfileParams> => {
|
||||
const { data } = await api.post(
|
||||
`/ai/profiles/${encodeURIComponent(profileName)}/apply`,
|
||||
{},
|
||||
@@ -415,7 +421,9 @@ export const adminAiService = {
|
||||
type: PromptType,
|
||||
updates: { template: string; contextConfig?: ContextConfig | null; manualNote?: string }
|
||||
): Promise<PromptVersion> => {
|
||||
const { data } = await api.post(`/ai/prompts/${type}`, updates);
|
||||
const { data } = await api.post(`/ai/prompts/${type}`, updates, {
|
||||
headers: { 'Idempotency-Key': createIdempotencyKey() },
|
||||
});
|
||||
return extractData<PromptVersion>(data);
|
||||
},
|
||||
|
||||
@@ -424,15 +432,15 @@ export const adminAiService = {
|
||||
},
|
||||
|
||||
activatePrompt: async (type: PromptType, versionNumber: number): Promise<PromptVersion> => {
|
||||
const { data } = await api.post(`/ai/prompts/${type}/${versionNumber}/activate`);
|
||||
const { data } = await api.post(
|
||||
`/ai/prompts/${type}/${versionNumber}/activate`,
|
||||
{},
|
||||
{ headers: { 'Idempotency-Key': createIdempotencyKey() } }
|
||||
);
|
||||
return extractData<PromptVersion>(data);
|
||||
},
|
||||
|
||||
updatePromptNote: async (
|
||||
type: PromptType,
|
||||
versionNumber: number,
|
||||
manualNote: string
|
||||
): Promise<PromptVersion> => {
|
||||
updatePromptNote: async (type: PromptType, versionNumber: number, manualNote: string): Promise<PromptVersion> => {
|
||||
const { data } = await api.patch(`/ai/prompts/${type}/${versionNumber}/note`, { manualNote });
|
||||
return extractData<PromptVersion>(data);
|
||||
},
|
||||
@@ -447,17 +455,46 @@ export const adminAiService = {
|
||||
versionNumber: number,
|
||||
contextConfig: ContextConfig
|
||||
): Promise<ContextConfig> => {
|
||||
const { data } = await api.put(`/ai/prompts/${type}/${versionNumber}/context-config`, contextConfig);
|
||||
const { data } = await api.put(`/ai/prompts/${type}/${versionNumber}/context-config`, contextConfig, {
|
||||
headers: { 'Idempotency-Key': createIdempotencyKey() },
|
||||
});
|
||||
return extractData<ContextConfig>(data);
|
||||
},
|
||||
|
||||
submitSandboxRagPrep: async (
|
||||
text: string,
|
||||
profileId?: string | null
|
||||
): Promise<{ jobId: string; status: string }> => {
|
||||
const { data } = await api.post('/ai/admin/sandbox/rag-prep', { text, profileId });
|
||||
submitSandboxRagPrep: async (text: string, profileId?: string | null): Promise<{ jobId: string; status: string }> => {
|
||||
const { data } = await api.post(
|
||||
'/ai/admin/sandbox/rag-prep',
|
||||
{ text, profileId },
|
||||
{ headers: { 'Idempotency-Key': createIdempotencyKey() } }
|
||||
);
|
||||
return extractData<{ jobId: string; status: string }>(data);
|
||||
},
|
||||
|
||||
// --- Execution Profiles (US4 — T051) ---
|
||||
|
||||
getExecutionProfiles: async (): Promise<ExecutionProfile[]> => {
|
||||
const { data } = await api.get('/ai/execution-profiles');
|
||||
return extractData<ExecutionProfile[]>(data);
|
||||
},
|
||||
|
||||
createExecutionProfile: async (
|
||||
profile: Omit<ExecutionProfile, 'id' | 'isActive' | 'createdAt' | 'updatedAt'>
|
||||
): Promise<ExecutionProfile> => {
|
||||
const { data } = await api.post('/ai/execution-profiles', profile);
|
||||
return extractData<ExecutionProfile>(data);
|
||||
},
|
||||
|
||||
updateExecutionProfile: async (
|
||||
id: number,
|
||||
updates: Partial<Omit<ExecutionProfile, 'id' | 'isActive' | 'createdAt' | 'updatedAt'>>
|
||||
): Promise<ExecutionProfile> => {
|
||||
const { data } = await api.put(`/ai/execution-profiles/${id}`, updates);
|
||||
return extractData<ExecutionProfile>(data);
|
||||
},
|
||||
|
||||
deleteExecutionProfile: async (id: number): Promise<void> => {
|
||||
await api.delete(`/ai/execution-profiles/${id}`);
|
||||
},
|
||||
};
|
||||
|
||||
export interface OcrEngineResponse {
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"i18next": "^26.3.1",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"lucide-react": "^0.577.0",
|
||||
"next": "16.2.6",
|
||||
"next-auth": "5.0.0-beta.30",
|
||||
@@ -54,6 +56,7 @@
|
||||
"react-dom": "^19.2.4",
|
||||
"react-dropzone": "^15.0.0",
|
||||
"react-hook-form": "^7.71.2",
|
||||
"react-i18next": "^17.0.8",
|
||||
"reactflow": "^11.11.4",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
|
||||
@@ -53,5 +53,84 @@
|
||||
"error_max_tokens_forbidden": "maxTokens override is not allowed. Runtime parameters are managed by policy.",
|
||||
"error_cpu_timeout": "Retrieval operation timed out on CPU fallback. Please retry later.",
|
||||
"error_large_context_unauthorized": "The large-context profile requires administrator privileges."
|
||||
},
|
||||
"execution_profiles": {
|
||||
"title": "AI Execution Profiles",
|
||||
"description": "Manage runtime AI model parameters for different use cases",
|
||||
"create_profile": "Create Profile",
|
||||
"edit_profile": "Edit Profile",
|
||||
"delete_profile": "Delete Profile",
|
||||
"profile_name": "Profile Name",
|
||||
"canonical_model": "Canonical Model",
|
||||
"temperature": "Temperature",
|
||||
"temperature_hint": "Controls randomness (0.0 = deterministic, 1.0 = creative)",
|
||||
"top_p": "Top-P",
|
||||
"top_p_hint": "Nucleus sampling threshold (0.0 = conservative, 1.0 = diverse)",
|
||||
"repeat_penalty": "Repeat Penalty",
|
||||
"repeat_penalty_hint": "Penalize repetition (1.0 = no penalty, 2.0 = strong penalty)",
|
||||
"max_tokens": "Max Tokens",
|
||||
"max_tokens_hint": "Maximum tokens to generate",
|
||||
"num_ctx": "Context Window",
|
||||
"num_ctx_hint": "Context window size (num_ctx)",
|
||||
"keep_alive": "Keep Alive (seconds)",
|
||||
"keep_alive_hint": "How long to keep model in memory after use",
|
||||
"no_profiles": "No execution profiles found",
|
||||
"delete_confirm": "Delete this execution profile?",
|
||||
"active_profiles": "Active Profiles",
|
||||
"standard": "Standard",
|
||||
"ocr_extract": "OCR Extract",
|
||||
"rag_prep": "RAG Prep"
|
||||
},
|
||||
"prompt_management": {
|
||||
"title": "Prompt Management",
|
||||
"description": "Manage AI prompt templates and versions",
|
||||
"prompt_type": "Prompt Type",
|
||||
"all_types": "All Types",
|
||||
"version_history": "Version History",
|
||||
"create_version": "Create Version",
|
||||
"activate_version": "Activate Version",
|
||||
"delete_version": "Delete Version",
|
||||
"edit_template": "Edit Template",
|
||||
"edit_context_config": "Edit Context Config",
|
||||
"edit_note": "Edit Note",
|
||||
"template": "Template",
|
||||
"context_config": "Context Config",
|
||||
"manual_note": "Manual Note",
|
||||
"last_tested": "Last Tested",
|
||||
"activated_at": "Activated At",
|
||||
"created_by": "Created By",
|
||||
"is_active": "Active",
|
||||
"filter": "Filter",
|
||||
"project_filter": "Project Filter",
|
||||
"contract_filter": "Contract Filter",
|
||||
"page_size": "Page Size",
|
||||
"language": "Language",
|
||||
"output_language": "Output Language",
|
||||
"no_versions": "No versions found",
|
||||
"cannot_delete_active": "Cannot delete active version",
|
||||
"optimistic_lock_error": "This version was modified by another user. Please refresh and try again.",
|
||||
"validation_error": "Validation failed",
|
||||
"pageSize_invalid": "Page size must be between 1 and 1000",
|
||||
"language_required": "Language is required",
|
||||
"output_language_required": "Output language is required",
|
||||
"project_not_found": "Project not found",
|
||||
"contract_not_found": "Contract not found"
|
||||
},
|
||||
"sandbox_test": {
|
||||
"title": "Sandbox Test Area",
|
||||
"description": "Test AI models and prompts in a safe environment",
|
||||
"ocr_tab": "OCR",
|
||||
"ai_extract_tab": "AI Extract",
|
||||
"rag_prep_tab": "RAG Prep",
|
||||
"submit_test": "Submit Test",
|
||||
"test_result": "Test Result",
|
||||
"no_result": "No test result available",
|
||||
"processing": "Processing...",
|
||||
"error": "Error occurred",
|
||||
"select_profile": "Select Execution Profile",
|
||||
"ocr_text": "OCR Text",
|
||||
"llm_output": "LLM Output",
|
||||
"rag_chunks": "RAG Chunks",
|
||||
"runtime_parameters": "Runtime Parameters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,5 +85,84 @@
|
||||
"error_max_tokens_forbidden": "ไม่อนุญาตให้ override ค่า maxTokens พารามิเตอร์ถูกควบคุมโดย Runtime Policy",
|
||||
"error_cpu_timeout": "การดึงข้อมูลหมดเวลาขณะใช้ CPU fallback กรุณาลองใหม่อีกครั้ง",
|
||||
"error_large_context_unauthorized": "Profile large-context ต้องการสิทธิ์ผู้ดูแลระบบ"
|
||||
},
|
||||
"execution_profiles": {
|
||||
"title": "AI Execution Profiles",
|
||||
"description": "จัดการพารามิเตอร์โมเดล AI สำหรับ use case ต่าง ๆ",
|
||||
"create_profile": "สร้างโปรไฟล์",
|
||||
"edit_profile": "แก้ไขโปรไฟล์",
|
||||
"delete_profile": "ลบโปรไฟล์",
|
||||
"profile_name": "ชื่อโปรไฟล์",
|
||||
"canonical_model": "Canonical Model",
|
||||
"temperature": "Temperature",
|
||||
"temperature_hint": "ควบคุมความสุ่ม (0.0 = แน่นอน, 1.0 = สร้างสรรค์)",
|
||||
"top_p": "Top-P",
|
||||
"top_p_hint": "Nucleus sampling threshold (0.0 = อนุรักษ์, 1.0 = หลากหลาย)",
|
||||
"repeat_penalty": "Repeat Penalty",
|
||||
"repeat_penalty_hint": "ลงโทษการซ้ำ (1.0 = ไม่ลงโทษ, 2.0 = ลงโทษหนัก)",
|
||||
"max_tokens": "Max Tokens",
|
||||
"max_tokens_hint": "จำนวน tokens สูงสุดที่จะสร้าง",
|
||||
"num_ctx": "Context Window",
|
||||
"num_ctx_hint": "ขนาด context window (num_ctx)",
|
||||
"keep_alive": "Keep Alive (วินาที)",
|
||||
"keep_alive_hint": "ระยะเวลาที่จะคงโมเดลไว้ใน memory หลังใช้งาน",
|
||||
"no_profiles": "ไม่พบ execution profiles",
|
||||
"delete_confirm": "ต้องการลบ execution profile นี้?",
|
||||
"active_profiles": "Active Profiles",
|
||||
"standard": "Standard",
|
||||
"ocr_extract": "OCR Extract",
|
||||
"rag_prep": "RAG Prep"
|
||||
},
|
||||
"prompt_management": {
|
||||
"title": "Prompt Management",
|
||||
"description": "จัดการเทมเพลตและเวอร์ชันของ AI prompt",
|
||||
"prompt_type": "ประเภท Prompt",
|
||||
"all_types": "ทุกประเภท",
|
||||
"version_history": "ประวัติเวอร์ชัน",
|
||||
"create_version": "สร้างเวอร์ชัน",
|
||||
"activate_version": "เปิดใช้งานเวอร์ชัน",
|
||||
"delete_version": "ลบเวอร์ชัน",
|
||||
"edit_template": "แก้ไขเทมเพลต",
|
||||
"edit_context_config": "แก้ไข Context Config",
|
||||
"edit_note": "แก้ไขโน้ต",
|
||||
"template": "เทมเพลต",
|
||||
"context_config": "Context Config",
|
||||
"manual_note": "โน้ต",
|
||||
"last_tested": "ทดสอบล่าสุด",
|
||||
"activated_at": "เปิดใช้งานเมื่อ",
|
||||
"created_by": "สร้างโดย",
|
||||
"is_active": "Active",
|
||||
"filter": "ตัวกรอง",
|
||||
"project_filter": "ตัวกรองโครงการ",
|
||||
"contract_filter": "ตัวกรองสัญญา",
|
||||
"page_size": "ขนาดหน้า",
|
||||
"language": "ภาษา",
|
||||
"output_language": "ภาษาผลลัพธ์",
|
||||
"no_versions": "ไม่พบเวอร์ชัน",
|
||||
"cannot_delete_active": "ไม่สามารถลบ active version ได้",
|
||||
"optimistic_lock_error": "เวอร์ชันนี้ถูกแก้ไขโดยผู้ใช้อื่น กรุณารีเฟรชแล้วลองใหม่",
|
||||
"validation_error": "การตรวจสอบล้มเหลว",
|
||||
"pageSize_invalid": "Page size ต้องอยู่ระหว่าง 1 ถึง 1000",
|
||||
"language_required": "ต้องระบุภาษา",
|
||||
"output_language_required": "ต้องระบุภาษาผลลัพธ์",
|
||||
"project_not_found": "ไม่พบโครงการ",
|
||||
"contract_not_found": "ไม่พบสัญญา"
|
||||
},
|
||||
"sandbox_test": {
|
||||
"title": "Sandbox Test Area",
|
||||
"description": "ทดสอบโมเดล AI และ prompts ในสภาพแวดล้อมที่ปลอดภัย",
|
||||
"ocr_tab": "OCR",
|
||||
"ai_extract_tab": "AI Extract",
|
||||
"rag_prep_tab": "RAG Prep",
|
||||
"submit_test": "ส่งทดสอบ",
|
||||
"test_result": "ผลการทดสอบ",
|
||||
"no_result": "ไม่มีผลการทดสอบ",
|
||||
"processing": "กำลังประมวลผล...",
|
||||
"error": "เกิดข้อผิดพลาด",
|
||||
"select_profile": "เลือก Execution Profile",
|
||||
"ocr_text": "OCR Text",
|
||||
"llm_output": "LLM Output",
|
||||
"rag_chunks": "RAG Chunks",
|
||||
"runtime_parameters": "Runtime Parameters"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user