reference-first-set-blueprint.test.mjs 3.7 KB

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