import { test } from "node:test"; import assert from "node:assert/strict"; import { ShotOverrides } from "../src/ai/shotTuner.js"; import { applyShotOverrides } from "../src/ai/recipes.js"; test("applyShotOverrides: dopiski trafiają na koniec promptu, baza nietknięta", () => { const base = "Recreate the exact furniture. Strictly no recliners."; const out = applyShotOverrides(base, { prompt_additions: "camera at slightly lower angle", negative_prompt_additions: "blanket, throw, patchwork", }); assert.equal( out, "Recreate the exact furniture. Strictly no recliners. camera at slightly lower angle Strictly no: blanket, throw, patchwork." ); // baza pozostaje niezmieniona — kolejne przebiegi startują z czystego szablonu assert.equal(applyShotOverrides(base, null), base); assert.equal(applyShotOverrides(base, undefined), base); assert.equal(applyShotOverrides(base, { prompt_additions: "", negative_prompt_additions: " " }), base); }); test("ShotOverrides: schemat domyśla puste pola i odrzuca złe typy", () => { const parsed = ShotOverrides.parse({ prompt_additions: "softer light" }); assert.equal(parsed.prompt_additions, "softer light"); assert.equal(parsed.negative_prompt_additions, ""); assert.deepEqual(parsed.disabled_ref_ids, []); // nieznane klucze z odpowiedzi LLM są odcinane — nic nie wycieka do payloadu const stripped = ShotOverrides.parse({ explanation_pl: "x", admin: true } as unknown); assert.equal("admin" in stripped, false); assert.throws(() => ShotOverrides.parse({ disabled_ref_ids: "src_1" })); });