import assert from "node:assert/strict"; import test from "node:test"; import { compileSetBlueprint, creativePlannerInstruction, validateSetBlueprint } from "./reference-first-set-blueprint.mjs"; function plan() { const ids = ["white_complete", "selling_form", "selling_material", "scene_core_environment", "scene_human_interaction", "decision_scale_fit", "decision_value_summary"]; return { product_creative_brief: { category: "测试商品", form: "完整立体商品", colors: ["深色"], material_cues: ["哑光表面"], identity_cues: ["正面标识"], visible_selling_point_candidates: ["完整轮廓", "表面纹理"], natural_support_and_use: ["自然稳定承载"], human_interactions: ["自然手持"], commercial_direction: "现代商业产品摄影", unsupported_copy_facts: ["精确尺寸"], }, visual_bible: { commercial_style: "现代克制", palette: ["深灰", "米白"], lighting: "柔和侧光", prop_language: "少量自然道具" }, pages: ids.map((template_id, index) => ({ template_id, selection_reason: `理由${index}`, page_job: `页面任务${index}`, scene: index === 0 ? "纯白无缝背景" : `具体物理场景${index}`, product_pose: `稳定商品姿态${index}`, camera: `独立摄影机位${index}`, human_relation: `独立人物关系${index}`, props: [`道具${index}`], composition: `独立构图${index}`, text_safe_zone: `独立留白${index}`, difference_from_peer: `与同定位页面在任务、镜头、关系和构图上不同${index}`, })), }; } test("dynamic blueprint combines product planning, specialized recipes and platform design", () => { const blueprint = compileSetBlueprint({ runId: "run-20260804120000-aabbcc", generatedReferences: ["https://example.test/three.png", "https://example.test/board.png"], brief: { instruction: "生成淘宝七图", platform: "taobao" }, creativePlan: plan(), }); assert.deepEqual(blueprint.pages.map((page) => page.role), [ "white_background", "selling_point", "selling_point", "usage_scene", "usage_scene", "purchase_decision", "purchase_decision", ]); assert.equal(new Set(blueprint.pages.map((page) => page.template_id)).size, 7); assert.equal(blueprint.platform_strategy.resolved_profile, "taobao"); assert.match(blueprint.visual_bible.material_source, /三视图/); assert.match(blueprint.visual_bible.setting_board_role, /场景/); }); test("blueprint rejects repeated recipes and insufficient peer differentiation", () => { const duplicate = compileSetBlueprint({ runId: "run-20260804120000-aabbcc", generatedReferences: ["a", "b"], brief: { platform: "jd" }, creativePlan: plan() }); duplicate.pages[2].template_id = duplicate.pages[1].template_id; assert.throws(() => validateSetBlueprint(duplicate), /SET_BLUEPRINT_TEMPLATE_REPEATED/); const same = compileSetBlueprint({ runId: "run-20260804120000-aabbcc", generatedReferences: ["a", "b"], brief: { platform: "jd" }, creativePlan: plan() }); for (const key of ["page_job", "camera", "human_relation", "composition", "text_safe_zone"]) same.pages[2][key] = same.pages[1][key]; assert.throws(() => validateSetBlueprint(same), /SET_BLUEPRINT_PEER_DIFFERENCE_INSUFFICIENT/); }); test("creative planner instruction requires product-aware seven-page JSON rather than free directions", () => { const instruction = creativePlannerInstruction({ brief: { instruction: "生成抖音七图", platform: "douyin" } }); assert.match(instruction, /visible_selling_point_candidates/); assert.match(instruction, /selling_form/); assert.match(instruction, /scene_human_interaction/); assert.match(instruction, /decision_scale_fit/); assert.match(instruction, /不能只是同一模板换背景/); });