216 lines
7.2 KiB
TypeScript
216 lines
7.2 KiB
TypeScript
// File: backend/tests/e2e/prompt-management.e2e-spec.ts
|
|
// Change Log:
|
|
// - 2026-06-15: Created E2E test for full prompt management workflow (T061)
|
|
|
|
type PromptType =
|
|
| 'ocr_extraction'
|
|
| 'rag_query_prompt'
|
|
| 'rag_prep_prompt'
|
|
| 'classification_prompt';
|
|
|
|
describe('Prompt Management Workflow (E2E)', () => {
|
|
// This is a simplified E2E-like test that verifies the workflow logic
|
|
// For true E2E tests with full infrastructure, use the separate test:e2e script
|
|
|
|
describe('Full Prompt Management Workflow', () => {
|
|
it('ควรสร้าง version ใหม่ สำหรับหลาย prompt types แยกกัน', () => {
|
|
// Simulate version increment per prompt type
|
|
const promptTypes: PromptType[] = [
|
|
'ocr_extraction',
|
|
'rag_query_prompt',
|
|
'rag_prep_prompt',
|
|
'classification_prompt',
|
|
];
|
|
|
|
const versionMap = new Map<PromptType, number>();
|
|
|
|
// Simulate creating versions for each type
|
|
promptTypes.forEach((type) => {
|
|
const currentVersion = versionMap.get(type) || 0;
|
|
versionMap.set(type, currentVersion + 1);
|
|
});
|
|
|
|
// Verify each type has its own version counter
|
|
expect(versionMap.get('ocr_extraction')).toBe(1);
|
|
expect(versionMap.get('rag_query_prompt')).toBe(1);
|
|
expect(versionMap.get('rag_prep_prompt')).toBe(1);
|
|
expect(versionMap.get('classification_prompt')).toBe(1);
|
|
|
|
// Create second version for one type
|
|
const ocrVersion = versionMap.get('ocr_extraction') || 0;
|
|
versionMap.set('ocr_extraction', ocrVersion + 1);
|
|
|
|
// Verify version increment is isolated
|
|
expect(versionMap.get('ocr_extraction')).toBe(2);
|
|
expect(versionMap.get('rag_query_prompt')).toBe(1);
|
|
});
|
|
|
|
it('ควร activate version และ deactivate version เก่า', () => {
|
|
// Simulate activation workflow
|
|
const versions = [
|
|
{ versionNumber: 1, isActive: false },
|
|
{ versionNumber: 2, isActive: false },
|
|
{ versionNumber: 3, isActive: false },
|
|
];
|
|
|
|
// Activate version 2
|
|
const activatedVersions = versions.map((v) => ({
|
|
...v,
|
|
isActive: v.versionNumber === 2,
|
|
}));
|
|
|
|
// Verify only version 2 is active
|
|
const activeCount = activatedVersions.filter((v) => v.isActive).length;
|
|
expect(activeCount).toBe(1);
|
|
expect(activatedVersions[1].isActive).toBe(true);
|
|
});
|
|
|
|
it('ควร validate context config ก่อนบันทึก', () => {
|
|
// Simulate context config validation
|
|
const validConfig = {
|
|
pageSize: 5,
|
|
language: 'th',
|
|
outputLanguage: 'th',
|
|
filter: { projectId: 'valid-uuid' },
|
|
};
|
|
|
|
const invalidConfig = {
|
|
pageSize: 0, // Invalid: must be 1-100
|
|
language: 'invalid', // Invalid: must be 'th' or 'en'
|
|
outputLanguage: 'th',
|
|
filter: null,
|
|
};
|
|
|
|
// Validate pageSize
|
|
expect(validConfig.pageSize).toBeGreaterThanOrEqual(1);
|
|
expect(validConfig.pageSize).toBeLessThanOrEqual(100);
|
|
expect(invalidConfig.pageSize).toBeLessThan(1);
|
|
|
|
// Validate language
|
|
expect(['th', 'en']).toContain(validConfig.language);
|
|
expect(['th', 'en']).not.toContain(invalidConfig.language);
|
|
});
|
|
|
|
it('ควรส่งงาน sandbox 3 steps ต่อเนื่อง', () => {
|
|
// Simulate 3-step sandbox workflow
|
|
const _workflowSteps = ['ocr', 'ai-extract', 'rag-prep'];
|
|
const stepResults = new Map<string, boolean>();
|
|
|
|
// Step 1: OCR
|
|
stepResults.set('ocr', true);
|
|
|
|
// Step 2: AI Extract (depends on OCR)
|
|
if (stepResults.get('ocr')) {
|
|
stepResults.set('ai-extract', true);
|
|
}
|
|
|
|
// Step 3: RAG Prep (depends on OCR)
|
|
if (stepResults.get('ocr')) {
|
|
stepResults.set('rag-prep', true);
|
|
}
|
|
|
|
// Verify all steps completed
|
|
expect(stepResults.get('ocr')).toBe(true);
|
|
expect(stepResults.get('ai-extract')).toBe(true);
|
|
expect(stepResults.get('rag-prep')).toBe(true);
|
|
expect(stepResults.size).toBe(3);
|
|
});
|
|
|
|
it('ควร apply runtime parameters จาก profile ใน sandbox jobs', () => {
|
|
// Simulate runtime parameter application
|
|
const profile = {
|
|
temperature: 0.2,
|
|
topP: 0.7,
|
|
maxTokens: 2048,
|
|
numCtx: 4096,
|
|
repeatPenalty: 1.2,
|
|
keepAliveSeconds: 30,
|
|
};
|
|
|
|
const jobPayload = {
|
|
jobType: 'sandbox-rag-prep',
|
|
snapshotParams: profile,
|
|
};
|
|
|
|
// Verify parameters are applied
|
|
expect(jobPayload.snapshotParams.temperature).toBe(0.2);
|
|
expect(jobPayload.snapshotParams.topP).toBe(0.7);
|
|
expect(jobPayload.snapshotParams.maxTokens).toBe(2048);
|
|
});
|
|
|
|
it('ควร validate placeholder ใน template ก่อนบันทึก', () => {
|
|
// Simulate placeholder validation
|
|
const templates = {
|
|
ocr_extraction: {
|
|
template: 'Extract {{ocr_text}} from document',
|
|
required: ['{{ocr_text}}'],
|
|
},
|
|
rag_query_prompt: {
|
|
template: 'Query: {{query}} Context: {{context}}',
|
|
required: ['{{query}}', '{{context}}'],
|
|
},
|
|
rag_prep_prompt: {
|
|
template: 'Chunk {{text}} into semantic parts',
|
|
required: ['{{text}}'],
|
|
},
|
|
classification_prompt: {
|
|
template: 'Classify {{document_text}}',
|
|
required: ['{{document_text}}'],
|
|
},
|
|
};
|
|
|
|
// Validate each template has required placeholders
|
|
Object.entries(templates).forEach(([_type, data]) => {
|
|
data.required.forEach((placeholder) => {
|
|
expect(data.template).toContain(placeholder);
|
|
});
|
|
});
|
|
|
|
// Test invalid template
|
|
const invalidTemplate = 'This template has no placeholders';
|
|
expect(invalidTemplate).not.toContain('{{ocr_text}}');
|
|
});
|
|
});
|
|
|
|
describe('Integration Scenarios', () => {
|
|
it('ควรรองรับ workflow: Create → Activate → Use in Sandbox', () => {
|
|
// Simulate full workflow
|
|
const workflow = {
|
|
step1: { action: 'create', result: 'success' },
|
|
step2: { action: 'activate', result: 'success' },
|
|
step3: { action: 'sandbox-test', result: 'success' },
|
|
};
|
|
|
|
// Verify workflow completes
|
|
expect(workflow.step1.result).toBe('success');
|
|
expect(workflow.step2.result).toBe('success');
|
|
expect(workflow.step3.result).toBe('success');
|
|
});
|
|
|
|
it('ควร handle error เมื่อ activate version ที่ไม่มีอยู่', () => {
|
|
// Simulate error handling
|
|
const existingVersions = [1, 2, 3];
|
|
const targetVersion = 99;
|
|
|
|
const versionExists = existingVersions.includes(targetVersion);
|
|
expect(versionExists).toBe(false);
|
|
});
|
|
|
|
it('ควร cache prompt parameters สำหรับ performance', () => {
|
|
// Simulate caching behavior
|
|
const cache = new Map<string, unknown>();
|
|
const profileName = 'standard';
|
|
|
|
// First call - cache miss
|
|
if (!cache.has(profileName)) {
|
|
cache.set(profileName, { temperature: 0.5, topP: 0.8 });
|
|
}
|
|
|
|
// Second call - cache hit
|
|
const cached = cache.get(profileName);
|
|
expect(cached).toBeDefined();
|
|
expect(cached).toEqual({ temperature: 0.5, topP: 0.8 });
|
|
});
|
|
});
|
|
});
|