import { authenticate, content, expect, ready, roomPath, test } from "./room"; import { seedCardGapChannel } from "./sidecar-spacing-database"; // Computed line-height and browser layout quantize at different precisions. const GEOMETRY_EPSILON = 1 / 64; const WIDGET = "01K0N4TR8K7JGM4R1J7PW4R8YJ"; const QUESTION = "01K0N4V4E7Y6P4MJ5WD8XZF3B2"; const OPTION = "01K0N4W3B7P27CBAEC7A8C8WEA"; const SECOND_QUESTION = "01K0N4W3B7P27CBAEC7A8C8WEB"; const SECOND_OPTION = "01K0N4W3B7P27CBAEC7A8C8WEC"; const SECOND_WIDGET = "01K0N4TR8K7JGM4R1J7PW4R8YK"; const ADJACENT_CARDS = ` `; test("adjacent decision cards keep at most one line of space around one empty paragraph", async ({ baseURL, page, room, seed }) => { await seed(ADJACENT_CARDS); await authenticate(page, "ana", baseURL!); await page.goto(roomPath(room)); await ready(page); await page.getByRole("button", { name: "Document", exact: true }).click(); let editor = content(page); let cards = editor.locator( `:scope > :is([data-plan-questionnaire="${WIDGET}"], [data-plan-questionnaire="${SECOND_WIDGET}"])`, ); await expect(cards).toHaveCount(2); let gap = async () => { let first = await cards.nth(0).boundingBox(); let second = await cards.nth(1).boundingBox(); if (!first || !second) throw new Error("decision card geometry unavailable"); return second.y - first.y - first.height; }; let lineHeight = await editor.evaluate(element => Number.parseFloat(getComputedStyle(element).lineHeight) ); expect(await gap()).toBeLessThanOrEqual(lineHeight + GEOMETRY_EPSILON); let interstitial = (count: number) => cards.nth(0).evaluate((host, count) => { let second = host.nextElementSibling; if (!second?.hasAttribute("data-plan-questionnaire")) { throw new Error("the seeded cards are not adjacent"); } let paragraphs = Array.from({ length: count }, () => { let paragraph = document.createElement("p"); paragraph.dir = "auto"; let lineBreak = document.createElement("br"); lineBreak.setAttribute("data-lexical-managed-linebreak", "true"); paragraph.append(lineBreak); return paragraph; }); host.after(...paragraphs); let firstBox = host.getBoundingClientRect(); let secondBox = second.getBoundingClientRect(); let heights = paragraphs.map(paragraph => paragraph.getBoundingClientRect().height); paragraphs.forEach(paragraph => paragraph.remove()); return { gap: secondBox.top - firstBox.bottom, heights }; }, count); let single = await interstitial(1); expect(single.heights).toHaveLength(1); expect(Math.abs(single.heights[0]! - lineHeight)).toBeLessThanOrEqual(GEOMETRY_EPSILON); expect(single.gap).toBeLessThanOrEqual(lineHeight + GEOMETRY_EPSILON); }); test("retained empty paragraphs between decisions compact after sync and reload", async ({ baseURL, page, room }) => { await seedCardGapChannel(Number(new URL(baseURL!).port), room, ADJACENT_CARDS); await authenticate(page, "ana", baseURL!); await page.goto(roomPath(room)); await ready(page); let inspect = async () => { await page.getByRole("button", { name: "Document", exact: true }).click(); let editor = content(page); await expect.poll(() => editor.evaluate((root, ids) => { let children = [...root.children]; let first = children.findIndex(node => node.getAttribute("data-plan-questionnaire") === ids[0] ); let second = children.findIndex(node => node.getAttribute("data-plan-questionnaire") === ids[1] ); return children.slice(first + 1, second).filter(node => node.tagName === "P").length; }, [WIDGET, SECOND_WIDGET]) ).toBe(1); let cards = editor.locator( `:scope > :is([data-plan-questionnaire="${WIDGET}"], [data-plan-questionnaire="${SECOND_WIDGET}"])`, ); let first = await cards.nth(0).boundingBox(); let second = await cards.nth(1).boundingBox(); if (!first || !second) throw new Error("decision card geometry unavailable"); let lineHeight = await editor.evaluate(element => Number.parseFloat(getComputedStyle(element).lineHeight) ); expect(second.y - first.y - first.height).toBeLessThanOrEqual(lineHeight + GEOMETRY_EPSILON); }; await inspect(); let caret = content(page).locator(`[data-plan-questionnaire="${WIDGET}"] + p`); await caret.click(); await page.keyboard.type("x"); await expect(caret).toHaveText("x"); await page.keyboard.press("Backspace"); await expect(caret).toHaveText(""); await page.reload(); await inspect(); });