Emdash source with visual editor image upload fix
Fixes: 1. media.ts: wrap placeholder generation in try-catch 2. toolbar.ts: check r.ok, display error message in popover
This commit is contained in:
130
e2e/tests/autosave.spec.ts
Normal file
130
e2e/tests/autosave.spec.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Autosave E2E Tests
|
||||
*
|
||||
* Tests that autosave updates the existing draft revision in place
|
||||
* rather than creating a new revision on each keystroke.
|
||||
*
|
||||
* Covers issue #5: skipRevision was stripped by Zod validation,
|
||||
* causing every autosave to create a new revision.
|
||||
*/
|
||||
|
||||
import { test, expect } from "../fixtures";
|
||||
|
||||
test.describe("Autosave", () => {
|
||||
let collectionSlug: string;
|
||||
let postId: string;
|
||||
let headers: Record<string, string>;
|
||||
let baseUrl: string;
|
||||
|
||||
test.beforeEach(async ({ admin, serverInfo }) => {
|
||||
await admin.devBypassAuth();
|
||||
|
||||
baseUrl = serverInfo.baseUrl;
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${serverInfo.token}`,
|
||||
"X-EmDash-Request": "1",
|
||||
Origin: baseUrl,
|
||||
};
|
||||
|
||||
// Create a collection with revision support
|
||||
collectionSlug = `autosave_${Date.now()}`;
|
||||
await fetch(`${baseUrl}/_emdash/api/schema/collections`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({
|
||||
slug: collectionSlug,
|
||||
label: "Autosave Test",
|
||||
labelSingular: "Autosave Test",
|
||||
supports: ["revisions", "drafts"],
|
||||
}),
|
||||
});
|
||||
|
||||
await fetch(`${baseUrl}/_emdash/api/schema/collections/${collectionSlug}/fields`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({ slug: "title", type: "string", label: "Title", required: true }),
|
||||
});
|
||||
|
||||
// Create and publish a post
|
||||
const createRes = await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({ data: { title: "Original" }, slug: "autosave-test" }),
|
||||
});
|
||||
const createData: any = await createRes.json();
|
||||
postId = createData.data?.item?.id ?? createData.data?.id;
|
||||
|
||||
await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/publish`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}`, {
|
||||
method: "DELETE",
|
||||
headers,
|
||||
}).catch(() => {});
|
||||
await fetch(`${baseUrl}/_emdash/api/schema/collections/${collectionSlug}`, {
|
||||
method: "DELETE",
|
||||
headers,
|
||||
}).catch(() => {});
|
||||
});
|
||||
|
||||
test("multiple autosaves update draft in place instead of creating new revisions", async ({
|
||||
admin,
|
||||
}) => {
|
||||
const contentUrl = `/_emdash/api/content/${collectionSlug}/${postId}`;
|
||||
const isPut = (res: any) => res.url().includes(contentUrl) && res.request().method() === "PUT";
|
||||
const isGet = (res: any) =>
|
||||
res.url().includes(contentUrl) &&
|
||||
!res.url().includes("/revisions") &&
|
||||
res.request().method() === "GET";
|
||||
|
||||
await admin.goToEditContent(collectionSlug, postId);
|
||||
await admin.waitForLoading();
|
||||
|
||||
const titleInput = admin.page.locator("#field-title");
|
||||
await expect(titleInput).toHaveValue("Original");
|
||||
|
||||
// First edit — listen for both the PUT and the subsequent cache re-fetch GET
|
||||
const firstPut = admin.page.waitForResponse(isPut, { timeout: 10000 });
|
||||
await titleInput.fill("Edit One");
|
||||
await firstPut;
|
||||
|
||||
// Wait for the cache invalidation GET to settle so form doesn't get overwritten
|
||||
const refetchGet = admin.page.waitForResponse(isGet, { timeout: 5000 }).catch(() => {});
|
||||
await refetchGet;
|
||||
// Extra settle time for React state updates
|
||||
await admin.page.waitForTimeout(500);
|
||||
|
||||
// Check revision count after first autosave
|
||||
const res1 = await fetch(
|
||||
`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/revisions`,
|
||||
{ headers },
|
||||
);
|
||||
const data1: any = await res1.json();
|
||||
const countAfterFirst = data1.data.total;
|
||||
|
||||
// Second edit — set up listener BEFORE typing
|
||||
const secondPut = admin.page.waitForResponse(isPut, { timeout: 10000 });
|
||||
await titleInput.fill("Edit Two");
|
||||
await secondPut;
|
||||
|
||||
// Check revision count — should be same (updated in place, not new revision)
|
||||
const res2 = await fetch(
|
||||
`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/revisions`,
|
||||
{ headers },
|
||||
);
|
||||
const data2: any = await res2.json();
|
||||
const countAfterSecond = data2.data.total;
|
||||
|
||||
expect(countAfterSecond).toBe(countAfterFirst);
|
||||
|
||||
// Verify the latest revision contains the last autosaved data
|
||||
const latestRevision = data2.data.items?.[0];
|
||||
expect(latestRevision?.data?.title).toBe("Edit Two");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user