Skip to content

Commit e030f9e

Browse files
test: add E2E tests for editor auto-save persistence (#221) (#228)
* test: add E2E tests for editor auto-save persistence (#221) Co-authored-by: Ona <no-reply@ona.com> * fix: move waitForResponse listener before typing to prevent race condition The waitForContentSave promise was created after typing finished. If the 500ms debounce fired before Playwright registered the listener, the PATCH response would be missed causing a flaky 10s timeout. Matches the pattern used in e2e/search.spec.ts. Co-authored-by: Ona <no-reply@ona.com> --------- Co-authored-by: Ona <no-reply@ona.com>
1 parent 7475ed7 commit e030f9e

1 file changed

Lines changed: 80 additions & 0 deletions

File tree

e2e/editor-auto-save.spec.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { test, expect } from "./fixtures/auth";
2+
import { navigateToEditorPage } from "./fixtures/editor-helpers";
3+
4+
/**
5+
* Wait for a successful Supabase PATCH to /rest/v1/pages (content auto-save).
6+
* Resolves once the response arrives with a 2xx status.
7+
*/
8+
function waitForContentSave(page: import("@playwright/test").Page) {
9+
return page.waitForResponse(
10+
(resp) =>
11+
resp.url().includes("/rest/v1/pages") &&
12+
resp.request().method() === "PATCH" &&
13+
resp.status() >= 200 &&
14+
resp.status() < 300,
15+
{ timeout: 10_000 }
16+
);
17+
}
18+
19+
test.describe("Editor auto-save", () => {
20+
test("content typed in the editor persists after page reload", async ({
21+
authenticatedPage: page,
22+
}) => {
23+
await navigateToEditorPage(page);
24+
25+
const editor = page.locator('[contenteditable="true"]');
26+
await expect(editor).toBeVisible({ timeout: 10_000 });
27+
28+
// Use a unique string so we can verify it survives the reload
29+
const uniqueText = `autosave-test-${Date.now()}`;
30+
31+
// Register the response listener BEFORE typing so we never miss the
32+
// PATCH response if the debounce fires quickly.
33+
const saveResponse = waitForContentSave(page);
34+
35+
// Type content into the editor
36+
await editor.click();
37+
await page.keyboard.press("End");
38+
await page.keyboard.press("Enter");
39+
await page.keyboard.type(uniqueText);
40+
41+
// Wait for the debounced auto-save PATCH to complete
42+
await saveResponse;
43+
44+
// Reload the page
45+
await page.reload({ waitUntil: "domcontentloaded" });
46+
47+
// Wait for the editor to re-render with persisted content
48+
const reloadedEditor = page.locator('[contenteditable="true"]');
49+
await expect(reloadedEditor).toBeVisible({ timeout: 10_000 });
50+
51+
// Verify the typed content survived the reload
52+
await expect(reloadedEditor).toContainText(uniqueText, {
53+
timeout: 10_000,
54+
});
55+
});
56+
57+
test("save status indicator shows Saving and Saved after editing", async ({
58+
authenticatedPage: page,
59+
}) => {
60+
await navigateToEditorPage(page);
61+
62+
const editor = page.locator('[contenteditable="true"]');
63+
await expect(editor).toBeVisible({ timeout: 10_000 });
64+
65+
// The save status container is below the editor
66+
const saveIndicator = page.locator("main .text-muted-foreground").last();
67+
68+
// Type content to trigger auto-save
69+
await editor.click();
70+
await page.keyboard.press("End");
71+
await page.keyboard.press("Enter");
72+
await page.keyboard.type("indicator-test");
73+
74+
// "Saving..." should appear immediately after the editor state changes
75+
await expect(saveIndicator).toContainText("Saving", { timeout: 5_000 });
76+
77+
// After the debounced save completes, "Saved" should appear
78+
await expect(saveIndicator).toContainText("Saved", { timeout: 10_000 });
79+
});
80+
});

0 commit comments

Comments
 (0)