1
17import { test, expect } from "../fixtures";
18import { createPage, createBlock, getBlocks } from "../utils/api";
19import type { PageDto, BlockDto } from "../fixtures";
20
21interface TemplateDto {
22 id: string;
23 name: string;
24 type: string;
25 isBuiltin: boolean;
26}
27
28test.describe("Templates — P1 (T-141/T-142)", () => {
29 test("snapshot → list → apply deep-copies the page with its blocks", async ({
30 authPage,
31 api,
32 freshWorkspace
33 }) => {
34 const ws = await freshWorkspace("Template Space");
35
36
37 const src = (await createPage(api, ws.id, { title: "Weekly Standup" })) as PageDto;
38
39
40
41
42 const BLOCK_TEXT = "Standup source block text";
43 await createBlock(api, src.id, { type: "PARAGRAPH", content: { text: BLOCK_TEXT } });
44 await createBlock(api, src.id, { type: "PARAGRAPH", content: { text: "second line" } });
45
46
47 const tRes = await api.post(`/api/v1/pages/${src.id}/templates`, {
48 data: { name: "Standup Template", icon: "📋" }
49 });
50 expect(tRes.status(), await tRes.text()).toBe(201);
51 const tpl = (await tRes.json()) as TemplateDto;
52 expect(tpl.id).toBeTruthy();
53 expect(tpl.name).toBe("Standup Template");
54 expect(tpl.isBuiltin).toBe(false);
55
56
57 await authPage.goto(`/w/${ws.slug}/templates`);
58 await expect(authPage.getByRole("heading", { name: /templates/i })).toBeVisible();
59
60
61
62 const item = authPage.getByTestId(`template-item-${tpl.id}`);
63 await expect(item).toBeVisible({ timeout: 15_000 });
64 await expect(item).toContainText("Standup Template");
65
66
67 await item.getByTestId(`template-apply-${tpl.id}`).click();
68
69 await authPage.waitForURL(/\/w\/[^/]+\/page\/[^/]+$/, { timeout: 20_000 });
70 const newId = new URL(authPage.url()).pathname.split("/").pop() ?? "";
71 expect(newId).toBeTruthy();
72 expect(newId).not.toBe(src.id);
73
74
75
76 const newPageRes = await api.get(`/api/v1/pages/${newId}`);
77 expect(newPageRes.status(), await newPageRes.text()).toBe(200);
78 const envelope = (await newPageRes.json()) as {
79 page: PageDto & { workspaceId?: string };
80 workspace?: { id?: string };
81 };
82 expect(envelope.page.id).toBe(newId);
83
84
85 expect(envelope.page.workspaceId ?? envelope.workspace?.id).toBe(ws.id);
86
87 const blocks = await getBlocks(api, newId);
88 expect(Array.isArray(blocks) ? blocks.length : 0).toBeGreaterThanOrEqual(2);
89 const texts = (Array.isArray(blocks) ? blocks : []).map(
90 (b: BlockDto) => (b.content as { text?: string } | null)?.text ?? ""
91 );
92 expect(texts).toContain(BLOCK_TEXT);
93 });
94});
95