Files
lindyson-ai/apps/api/tests/tkPromptEngineService.test.ts
Juno ChowandClaude Fable 5.1 f665082dad chore: 建立产品仓库,完成开源前的敏感信息清理
前端(Vite + React)、API/worker(Fastify + BullMQ)、api-contracts 契约包、
迁移脚本、测试与自托管 docker-compose 示例。

开源准备:运维脚本与机器信息已拆到私有仓库;公司名、备案号、隐私邮箱改读
publicCompliance.local.json(仓库只保留占位模板);站点地址与客服二维码改为
VITE_ 环境变量;fixtures 中的真实用户标识已匿名化;三个 package.json 标注
Apache-2.0。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-16 02:10:46 +08:00

127 lines
4.1 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
materializeReviewedFactPack,
materializeTkPromptEvidenceProfile,
tkPromptImageMimeType,
} from '../src/domain/tkPromptEngineService.js';
const imageIds = [
'00000000-0000-4000-8000-000000000201',
'00000000-0000-4000-8000-000000000202',
] as const;
describe('TK Prompt Engine 事实动作闭包', () => {
it('事实分析把动作绑定为稳定 ID、支撑事实与原图来源', () => {
const profile = materializeTkPromptEvidenceProfile(factAnalysis(), images());
expect(profile.demonstrableActions).toEqual([{
actionId: 'action-001',
text: '手部按下左侧结构',
supportingFactIds: ['visible-001'],
sourceImageAssetIds: [imageIds[0]],
}, {
actionId: 'action-002',
text: '手部旋转右侧旋钮',
supportingFactIds: ['visible-002'],
sourceImageAssetIds: [imageIds[1]],
}]);
});
it('用户拒绝支撑事实后过滤对应动作且保留其余稳定 actionId', () => {
const profile = materializeTkPromptEvidenceProfile(factAnalysis(), images());
const factPack = materializeReviewedFactPack({
evidenceProfile: profile,
evidenceReview: {
productName: '参考商品',
category: '家居用品',
rejectedVisibleFactIds: ['visible-001'],
userConfirmedFacts: [],
forbiddenClaims: [],
},
creativeInput: {
targetMarket: 'United States',
targetAudience: '',
verifiedOffer: '',
appearance: { mode: 'product_closeup' },
availableScenes: [],
availableAssets: [],
},
});
expect(factPack.facts.map(fact => fact.factId)).toEqual(['visible-002']);
expect(factPack.demonstrableActions).toEqual([{
actionId: 'action-002',
text: '手部旋转右侧旋钮',
supportingFactIds: ['visible-002'],
sourceImageAssetIds: [imageIds[1]],
}]);
});
it('Provider 动作引用越界事实序号时返回明确合同错误', () => {
const invalid = factAnalysis();
invalid.demonstrableActions[0]!.supportingFactIndexes = [2];
expect(() => materializeTkPromptEvidenceProfile(invalid, images()))
.toThrow(/存在的图片事实序号/u);
});
it('无后缀商品图使用已完成上传会话的可信 JPEG/PNG 类型', () => {
expect(tkPromptImageMimeType({
objectKey: 'users/user/uploads/session/product',
uploadContentType: 'image/jpeg',
})).toBe('image/jpeg');
expect(tkPromptImageMimeType({
objectKey: 'users/user/uploads/session/product',
uploadContentType: 'image/png',
})).toBe('image/png');
});
it('已有上传类型不可信时拒绝且不按伪造后缀降级,缺失记录只允许安全后缀回退', () => {
expect(() => tkPromptImageMimeType({
objectKey: 'users/user/uploads/session/product.jpg',
uploadContentType: 'text/plain',
})).toThrow(/可信 JPEG、PNG 或 WebP/u);
expect(tkPromptImageMimeType({
objectKey: 'users/user/historical/product.webp',
})).toBe('image/webp');
expect(() => tkPromptImageMimeType({
objectKey: 'users/user/historical/product',
})).toThrow(/可信 JPEG、PNG 或 WebP/u);
});
});
function factAnalysis() {
return {
productName: '参考商品',
category: '家居用品',
confidence: 'high' as const,
visibleFacts: [{
text: '左侧有可按压结构',
sourceImageIndexes: [0],
confidence: 'high' as const,
}, {
text: '右侧有可旋转旋钮',
sourceImageIndexes: [1],
confidence: 'high' as const,
}],
internalHypotheses: [],
demonstrableActions: [{
actionId: 'action-001',
text: '手部按下左侧结构',
supportingFactIndexes: [0],
}, {
actionId: 'action-002',
text: '手部旋转右侧旋钮',
supportingFactIndexes: [1],
}],
};
}
function images() {
return imageIds.map((assetId, index) => ({
assetId,
name: `product-${index + 1}.png`,
url: `https://assets.example.com/product-${index + 1}.png`,
mimeType: 'image/png' as const,
sizeBytes: 1_024,
}));
}