168 lines
5.9 KiB
TypeScript
168 lines
5.9 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import {
|
|
captureBrowserFailures,
|
|
gotoLiveView,
|
|
loginWithPassword,
|
|
projectEmail,
|
|
} from "./helpers";
|
|
|
|
async function submitSupportRequest(
|
|
page: import("@playwright/test").Page,
|
|
requesterEmail: string,
|
|
kind: "privacy_request" | "data_export",
|
|
subject: string,
|
|
details: string,
|
|
): Promise<void> {
|
|
await page.goto("/support");
|
|
await page.getByLabel("What do you need help with?").selectOption(kind);
|
|
await expect(page.getByLabel("Contact email")).toHaveValue(requesterEmail);
|
|
await expect(page.getByLabel("Contact email")).toHaveAttribute(
|
|
"readonly",
|
|
"",
|
|
);
|
|
await page.getByLabel("Subject").fill(subject);
|
|
await page.getByLabel("Describe the problem").fill(details);
|
|
await page.getByRole("button", { name: "Send support request" }).click();
|
|
await expect(page).toHaveURL(/\/support\/received\?reference=SUP-/);
|
|
await expect(
|
|
page.getByRole("heading", { name: "Support request created" }),
|
|
).toBeVisible();
|
|
}
|
|
|
|
test.skip(
|
|
process.env.E2E_PRODUCTION_RUN_SCOPED !== "1",
|
|
"This support intake and staff queue check requires the production run-scoped fixture",
|
|
);
|
|
|
|
test("run-scoped support intake and legal fixture reach production staff", async ({
|
|
browser,
|
|
}, testInfo) => {
|
|
const runID = process.env.E2E_RUN_ID;
|
|
const fixturePassword = process.env.E2E_FIXTURE_PASSWORD;
|
|
const adminEmail =
|
|
process.env.E2E_ADMIN_EMAIL ?? projectEmail("admin", testInfo.project.name);
|
|
const requesterEmail = projectEmail("requester", testInfo.project.name);
|
|
|
|
if (!runID || !fixturePassword) {
|
|
throw new Error("E2E_RUN_ID and E2E_FIXTURE_PASSWORD are required");
|
|
}
|
|
|
|
const supportSubject = `Production E2E support ${runID}`;
|
|
const supportDetails =
|
|
"Run-scoped read-only browser fixture for the production support queue.";
|
|
const privacySubject = `Production E2E privacy ${runID}`;
|
|
const dataExportSubject = `Production E2E data export ${runID}`;
|
|
const accountDeletionSubject = "Delete my Who Need Help account";
|
|
const removalExplanation =
|
|
"Run-scoped read-only browser fixture for the production legal review queue.";
|
|
const takeItDownExplanation =
|
|
"Run-scoped read-only browser fixture for the production TAKE IT DOWN queue.";
|
|
const removalReference = `REM-E2E-${runID.toUpperCase()}`;
|
|
const takeItDownReference = `REM-E2E-TID-${runID.toUpperCase()}`;
|
|
|
|
const requester = await loginWithPassword(
|
|
browser,
|
|
requesterEmail,
|
|
fixturePassword,
|
|
);
|
|
const admin = await loginWithPassword(browser, adminEmail, fixturePassword);
|
|
const assertRequesterClean = captureBrowserFailures(requester.page);
|
|
const assertAdminClean = captureBrowserFailures(admin.page);
|
|
|
|
await submitSupportRequest(
|
|
requester.page,
|
|
requesterEmail,
|
|
"privacy_request",
|
|
privacySubject,
|
|
"Run-scoped production browser verification for the authenticated privacy-request intake.",
|
|
);
|
|
await submitSupportRequest(
|
|
requester.page,
|
|
requesterEmail,
|
|
"data_export",
|
|
dataExportSubject,
|
|
"Run-scoped production browser verification for the authenticated data-export intake.",
|
|
);
|
|
|
|
await requester.page.goto("/account/delete");
|
|
await expect(requester.page.getByLabel("Account email")).toHaveValue(
|
|
requesterEmail,
|
|
);
|
|
await expect(requester.page.getByLabel("Account email")).toHaveAttribute(
|
|
"readonly",
|
|
"",
|
|
);
|
|
await requester.page
|
|
.getByLabel("Additional information")
|
|
.fill(
|
|
"Run-scoped production browser verification for the account-deletion support workflow.",
|
|
);
|
|
await requester.page
|
|
.getByRole("button", { name: "Request account deletion" })
|
|
.click();
|
|
await expect(requester.page).toHaveURL(/\/support\/received\?reference=SUP-/);
|
|
|
|
await gotoLiveView(admin.page, "/support/operations?queue=support");
|
|
await admin.page
|
|
.locator("#support-case-filters")
|
|
.getByLabel("Search")
|
|
.fill(requesterEmail);
|
|
const supportRows = admin.page.locator("main tbody tr");
|
|
await expect(supportRows).toHaveCount(4);
|
|
await expect(supportRows.filter({ hasText: privacySubject })).toHaveCount(1);
|
|
await expect(supportRows.filter({ hasText: dataExportSubject })).toHaveCount(
|
|
1,
|
|
);
|
|
await expect(
|
|
supportRows.filter({ hasText: accountDeletionSubject }),
|
|
).toHaveCount(1);
|
|
|
|
await admin.page
|
|
.locator("#support-case-filters")
|
|
.getByLabel("Search")
|
|
.fill(supportSubject);
|
|
const supportRow = admin.page
|
|
.locator("main tbody tr")
|
|
.filter({ hasText: supportSubject });
|
|
await expect(supportRow).toHaveCount(1);
|
|
await supportRow.getByRole("link", { name: "Open" }).click();
|
|
await expect(
|
|
admin.page.getByRole("heading", { name: supportSubject }),
|
|
).toBeVisible();
|
|
await expect(
|
|
admin.page.getByText(supportDetails, { exact: true }),
|
|
).toBeVisible();
|
|
|
|
await gotoLiveView(admin.page, "/support/operations?queue=legal");
|
|
await admin.page
|
|
.locator("#legal-case-filters")
|
|
.getByLabel("Search")
|
|
.fill(removalReference);
|
|
const generalLegalRow = admin.page.locator("main tbody tr");
|
|
await expect(generalLegalRow).toHaveCount(1);
|
|
await expect(generalLegalRow).toContainText("general");
|
|
await generalLegalRow.getByRole("link", { name: "Open" }).click();
|
|
await expect(
|
|
admin.page.getByText(removalExplanation, { exact: true }),
|
|
).toBeVisible();
|
|
|
|
await gotoLiveView(admin.page, "/support/operations?queue=legal");
|
|
await admin.page
|
|
.locator("#legal-case-filters")
|
|
.getByLabel("Search")
|
|
.fill(takeItDownReference);
|
|
const takeItDownRow = admin.page.locator("main tbody tr");
|
|
await expect(takeItDownRow).toHaveCount(1);
|
|
await expect(takeItDownRow).toContainText(/take it down/i);
|
|
await expect(takeItDownRow).toContainText("urgent review");
|
|
await takeItDownRow.getByRole("link", { name: "Open" }).click();
|
|
await expect(
|
|
admin.page.getByText(takeItDownExplanation, { exact: true }),
|
|
).toBeVisible();
|
|
|
|
assertRequesterClean();
|
|
assertAdminClean();
|
|
await requester.context.close();
|
|
await admin.context.close();
|
|
});
|