feat: consolidate shared UI and harden browser authority for release
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
|
||||
async function install(page: Page) {
|
||||
const errors: string[] = [];
|
||||
page.on("pageerror", error => { errors.push(error.message); console.error("Attachment fixture:", error.message); });
|
||||
let revision = 1;
|
||||
const zip = { enabled: true, archives: [{ id: "zip-1", name: "recipient.zip", method: "zip_standard", password_enabled: true }] };
|
||||
let raw = { campaign: { name: "Fixture" }, template: { subject: "Fixture", text: "" }, server: {},
|
||||
attachments: { base_paths: [{ id: "source-1", name: "Source", path: ".", source: "managed:user:user-1", allow_individual: true }],
|
||||
global: [], zip } };
|
||||
const writes: Record<string, any>[] = [];
|
||||
const version = () => ({ id: "version-attachments", campaign_id: "campaign-attachments", version_number: 1,
|
||||
edit_revision: revision, strong_etag: `"version-attachments:${revision}"`, editor_state: {},
|
||||
current_flow: "manual", current_step: "files", workflow_state: "editing", is_complete: false,
|
||||
updated_at: "2026-09-07T10:00:00Z", raw_json: raw });
|
||||
await page.route((url) => url.pathname.startsWith("/api/"), async route => {
|
||||
const request = route.request(); const url = new URL(request.url());
|
||||
if (request.method() === "GET") {
|
||||
if (url.pathname.endsWith("/workspace/delta")) return route.fulfill({ json: {
|
||||
campaign: { id: "campaign-attachments", name: "Fixture", current_version_id: "version-attachments", status: "draft" },
|
||||
versions: [version()], current_version: version(), summary: null, deleted: [], full: true, has_more: false, watermark: `w${revision}`
|
||||
} });
|
||||
if (url.pathname === "/api/v1/files/spaces") return route.fulfill({ json: { spaces: [{ id: "space-1", label: "My files", space_type: "managed", owner_type: "user", owner_id: "user-1" }] } });
|
||||
if (url.pathname === "/api/v1/files/folders") return route.fulfill({ json: { folders: [], next_cursor: null } });
|
||||
if (url.pathname === "/api/v1/files") return route.fulfill({ json: { files: [], next_cursor: null } });
|
||||
if (url.pathname === "/api/v1/files/delta") return route.fulfill({ json: { files: [], folders: [{ id: "folder-1", owner_type: "user", owner_id: "user-1", path: "letters", name: "letters" }], deleted: [], full: true, has_more: false, watermark: "files-w1" } });
|
||||
if (url.pathname.endsWith("/versions/version-attachments")) return route.fulfill({ json: version() });
|
||||
if (url.pathname.endsWith("/archive-encryption-policy")) return route.fulfill({ json: {
|
||||
available: true, allowed_password_encryption_methods: ["aes"], allowed_password_delivery_channels: ["separate_mail"],
|
||||
policy_hash: "fixture", source_path: [], diagnostics: [], reason: "Legacy ZipCrypto is blocked by policy.", legacy_label: "Legacy ZipCrypto"
|
||||
} });
|
||||
return route.fulfill({ json: {} });
|
||||
}
|
||||
if (request.method() === "POST" && url.pathname.endsWith("/autosave")) {
|
||||
const body = request.postDataJSON(); writes.push(body);
|
||||
raw = body.campaign_json; revision++;
|
||||
return route.fulfill({ json: version() });
|
||||
}
|
||||
return route.abort();
|
||||
});
|
||||
await page.goto("/?campaign-attachments");
|
||||
await expect(page.locator("#campaign-attachment-sources .chooser-display-input")).toBeEnabled();
|
||||
return { writes, errors, zip };
|
||||
}
|
||||
|
||||
test("actual Files chooser opens repeatedly from attachment path by click and keyboard", async ({ page }) => {
|
||||
const fixture = await install(page);
|
||||
const input = page.locator("#campaign-attachment-sources .chooser-display-input");
|
||||
for (const action of ["click", "Enter", "Space", "click"]) {
|
||||
if (action === "click") await input.click();
|
||||
else { await input.focus(); await page.keyboard.press(action); }
|
||||
await expect(page.getByRole("dialog")).toBeVisible();
|
||||
await expect(page.getByRole("dialog").getByRole("button", { name: /Use.*folder|Select.*folder/i })).toBeEnabled();
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(page.getByRole("dialog")).toHaveCount(0);
|
||||
}
|
||||
expect(fixture.writes).toHaveLength(0);
|
||||
expect(fixture.errors).toEqual([]);
|
||||
});
|
||||
|
||||
test("temporarily unavailable Files capability does not silently turn managed paths into text edits", async ({ page }) => {
|
||||
const fixture = await install(page);
|
||||
await page.getByRole("button", { name: "Toggle Files capability" }).click();
|
||||
await expect(page.locator("#campaign-attachment-sources .chooser-display-input")).toBeDisabled();
|
||||
await expect(page.getByText(/The Files browser is currently unavailable/).first()).toBeVisible();
|
||||
await page.getByRole("button", { name: "Toggle Files capability" }).click();
|
||||
await page.locator("#campaign-attachment-sources .chooser-display-input").click();
|
||||
await expect(page.getByRole("dialog")).toBeVisible();
|
||||
await page.keyboard.press("Escape");
|
||||
expect(fixture.writes).toHaveLength(0);
|
||||
expect(fixture.errors).toEqual([]);
|
||||
});
|
||||
|
||||
test("attachment source corrections save without changing or reauthorizing legacy ZIP configuration", async ({ page }) => {
|
||||
const fixture = await install(page);
|
||||
await page.locator('#campaign-attachment-sources input[placeholder="Campaign files"]').fill("Updated source name");
|
||||
await page.getByRole("button", { name: "Save", exact: true }).click();
|
||||
await expect.poll(() => fixture.writes.length).toBe(1);
|
||||
expect(fixture.writes[0].campaign_json.attachments.zip).toEqual(fixture.zip);
|
||||
expect(fixture.writes[0].campaign_json.attachments.base_paths[0].name).toBe("Updated source name");
|
||||
await page.reload();
|
||||
await expect(page.locator('#campaign-attachment-sources input[placeholder="Campaign files"]')).toHaveValue("Updated source name");
|
||||
expect(fixture.errors).toEqual([]);
|
||||
});
|
||||
Reference in New Issue
Block a user