Replace plain textarea with shared tiptap editor and sanitized html rendering. Adds interactive checklists on read surfaces and mobile overflow fixes.
85 lines
3.4 KiB
TypeScript
85 lines
3.4 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import postgres from "postgres";
|
|
|
|
const databaseUrl = process.env["DATABASE_URL"] ?? "postgres://famapp:famapp@localhost:5432/famapp";
|
|
|
|
test("notes happy path", async ({ page }) => {
|
|
const suffix = Date.now().toString();
|
|
const title = `E2E Note ${suffix}`;
|
|
const editedTitle = `E2E Updated ${suffix}`;
|
|
const heading = `Heading ${suffix}`;
|
|
const reminder = "2026-05-20T09:30";
|
|
|
|
await page.goto("/notes");
|
|
await expect(page.getByRole("heading", { name: "Notes" })).toBeVisible();
|
|
|
|
await page.getByRole("link", { name: "New note" }).click();
|
|
await page.getByLabel("Title").fill(title);
|
|
await page.getByLabel("Body").click();
|
|
await page.getByRole("button", { name: "Heading" }).click();
|
|
await page.getByLabel("Body").type(heading);
|
|
await page.getByLabel("Body").press("Enter");
|
|
await page.getByRole("button", { name: "Bullet list" }).click();
|
|
await page.getByLabel("Body").type("Milk");
|
|
await page.getByLabel("Body").press("Enter");
|
|
await page.getByLabel("Body").type("Bread");
|
|
await page.getByLabel("Body").press("Enter");
|
|
await page.getByLabel("Body").type("<script>window.__famappInjected = true</script>");
|
|
await page.getByLabel("Reminder").fill(reminder);
|
|
await page.getByRole("button", { name: "Save note" }).click();
|
|
|
|
await expect(page).toHaveURL(/\/notes\/[0-9a-f-]+$/);
|
|
await expect(page.getByRole("heading", { name: new RegExp(title) })).toBeVisible();
|
|
await expect(
|
|
page.getByRole("complementary").getByRole("heading", { name: heading }),
|
|
).toBeVisible();
|
|
await expect(page.getByRole("complementary").getByText("Milk")).toBeVisible();
|
|
await expect(page.locator("script", { hasText: "window.__famappInjected" })).toHaveCount(0);
|
|
await expect
|
|
.poll(() => page.evaluate(() => Reflect.get(window, "__famappInjected")))
|
|
.toBeUndefined();
|
|
|
|
await page.getByRole("button", { name: "Pin note" }).click();
|
|
await expect(page.getByRole("button", { name: "Unpin note" })).toBeVisible();
|
|
|
|
await page.getByLabel("Title").fill(editedTitle);
|
|
await page.getByRole("button", { name: "Save note" }).click();
|
|
await expect(page.getByRole("heading", { name: new RegExp(editedTitle) })).toBeVisible();
|
|
|
|
const noteId = new URL(page.url()).pathname.split("/").pop();
|
|
expect(noteId).toBeTruthy();
|
|
|
|
const sql = postgres(databaseUrl);
|
|
try {
|
|
const reminders = await sql`
|
|
select entity_type, entity_id, fire_at
|
|
from reminders
|
|
where entity_type = 'notes.note' and entity_id = ${noteId}
|
|
`;
|
|
expect(reminders).toHaveLength(1);
|
|
expect(reminders[0]?.entity_type).toBe("notes.note");
|
|
} finally {
|
|
await sql.end();
|
|
}
|
|
|
|
await page.goto("/notes");
|
|
await expect(page.getByRole("link", { name: new RegExp(editedTitle) })).toBeVisible();
|
|
await page.getByRole("link", { name: new RegExp(editedTitle) }).click();
|
|
await page.getByRole("button", { name: "Delete note" }).click();
|
|
await expect(page).toHaveURL(/\/notes$/);
|
|
await expect(page.getByRole("link", { name: new RegExp(editedTitle) })).toBeHidden();
|
|
});
|
|
|
|
test("notes mobile layout has no horizontal overflow", async ({ page }) => {
|
|
await page.setViewportSize({ width: 375, height: 812 });
|
|
await page.goto("/notes/new");
|
|
await expect(page.getByLabel("Title")).toBeVisible();
|
|
|
|
const overflow = await page.evaluate(() => {
|
|
const doc = document.documentElement;
|
|
return doc.scrollWidth > doc.clientWidth;
|
|
});
|
|
|
|
expect(overflow).toBe(false);
|
|
});
|