who_need_help/e2e/tests/support-legal.spec.ts

272 lines
9.5 KiB
TypeScript

import { APIRequestContext, expect, test } from "@playwright/test";
import {
captureBrowserFailures,
gotoLiveView,
latestMessageID,
loginWithMagicLink,
loginWithPassword,
projectEmail,
registerAndConfirm,
} from "./helpers";
async function waitForNewEmail(
request: APIRequestContext,
email: string,
previousMessageID: string | undefined,
expectedText: string,
): Promise<void> {
let messageID: string | undefined;
await expect
.poll(
async () => {
messageID = await latestMessageID(request, email);
return messageID && messageID !== previousMessageID
? messageID
: undefined;
},
{
message: `waiting for a new application email for ${email}`,
timeout: 15_000,
},
)
.toBeTruthy();
const response = await request.get(
`${process.env.MAILPIT_URL}/api/v1/message/${messageID}`,
);
expect(response.ok()).toBeTruthy();
const message = (await response.json()) as { Text?: string; HTML?: string };
expect(`${message.Text ?? ""}\n${message.HTML ?? ""}`).toContain(
expectedText,
);
}
test("authenticated support and legal notices reach the scoped staff queues", async ({
browser,
request,
}, testInfo) => {
const projectName = testInfo.project.name;
const requesterEmail = projectEmail("requester", projectName);
const fixturePassword = process.env.E2E_FIXTURE_PASSWORD;
const adminEmail = process.env.E2E_ADMIN_EMAIL ?? "e2e-admin@example.invalid";
const supportSubject = `E2E support delivery [${projectName}]`;
const supportDetails =
"Browser E2E verifies the authenticated private case without a duplicate receipt email.";
const supportReply = `E2E support reply [${projectName}]`;
const supportFollowUp = `E2E support inbox follow-up [${projectName}]`;
const generalExplanation =
"Browser E2E verifies that a signed-in general removal notice reaches the legal queue.";
const urgentExplanation =
"Browser E2E verifies the urgent workflow without reproducing or uploading any material.";
const legalResolution = `E2E legal review completed [${projectName}]`;
const requester = fixturePassword
? await loginWithPassword(browser, requesterEmail, fixturePassword)
: await registerAndConfirm(
browser,
request,
requesterEmail,
"E2E Support Requester",
);
const admin = fixturePassword
? await loginWithPassword(browser, adminEmail, fixturePassword)
: await loginWithMagicLink(browser, request, adminEmail);
const assertRequesterClean = captureBrowserFailures(requester.page);
const assertAdminClean = captureBrowserFailures(admin.page);
const supportEmailBefore = await latestMessageID(request, requesterEmail);
await requester.page.goto("/support");
await requester.page
.getByLabel("What do you need help with?")
.selectOption("technical_issue");
await expect(requester.page.getByLabel("Contact email")).toHaveValue(
requesterEmail,
);
await expect(requester.page.getByLabel("Contact email")).toHaveAttribute(
"readonly",
"",
);
await requester.page.getByLabel("Subject").fill(supportSubject);
await requester.page.getByLabel("Describe the problem").fill(supportDetails);
await requester.page
.getByRole("button", { name: "Send support request" })
.click();
await expect(requester.page).toHaveURL(/\/support\/received\?reference=SUP-/);
await expect(
requester.page.getByRole("heading", { name: "Support request created" }),
).toBeVisible();
await requester.page.waitForTimeout(1_000);
expect(await latestMessageID(request, requesterEmail)).toBe(
supportEmailBefore,
);
await gotoLiveView(admin.page, "/support/operations?queue=support");
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 admin.page.getByLabel("Case status").selectOption("resolved");
await admin.page
.getByLabel("Reply to requester (optional)")
.fill(supportReply);
const replyEmailBefore = await latestMessageID(request, requesterEmail);
await admin.page.getByRole("button", { name: "Save and notify" }).click();
await expect(admin.page.getByText("Support request updated.")).toBeVisible();
await waitForNewEmail(
request,
requesterEmail,
replyEmailBefore,
"Status: resolved",
);
const followUpEmailBefore = await latestMessageID(request, requesterEmail);
await admin.page
.getByLabel("Reply to requester (optional)")
.fill(supportFollowUp);
await admin.page.getByRole("button", { name: "Save and notify" }).click();
await expect(admin.page.getByText("Support request updated.")).toBeVisible();
await admin.page.waitForTimeout(1_000);
expect(await latestMessageID(request, requesterEmail)).toBe(
followUpEmailBefore,
);
await requester.page.goto("/support/requests");
const requesterCase = requester.page
.locator("main")
.getByRole("link")
.filter({ hasText: supportSubject });
await expect(requesterCase).toHaveCount(1);
await requesterCase.click();
await expect(
requester.page.getByText(supportReply, { exact: true }),
).toBeVisible();
await expect(
requester.page.getByText(supportFollowUp, { exact: true }),
).toBeVisible();
const generalEmailBefore = await latestMessageID(request, requesterEmail);
await requester.page.goto("/legal/content-removal");
await requester.page.getByLabel("Reason").selectOption("privacy_violation");
await requester.page
.getByLabel("Your name or organisation")
.fill("E2E Requester");
await requester.page
.getByLabel("Your relationship to the affected person or rights holder")
.selectOption("self");
await requester.page
.getByLabel("Exact content URLs — one per line")
.fill(`${process.env.BASE_URL}/requests/e2e-reported-content`);
await requester.page
.getByLabel("Why do you believe this content should be removed?")
.fill(generalExplanation);
await requester.page
.getByLabel("Law, right, or policy involved, if known")
.fill("Privacy review requested by the affected account holder.");
await requester.page
.getByLabel("Electronic signature (type your full name)")
.fill("E2E Requester");
await requester.page
.getByLabel(/I believe in good faith that the identified content/)
.check();
await requester.page
.getByLabel(/I confirm that this notice is accurate and complete/)
.check();
await requester.page
.getByRole("button", { name: "Submit removal notice" })
.click();
await expect(requester.page).toHaveURL(
/\/legal\/content-removal\/received\?reference=REM-/,
);
await waitForNewEmail(
request,
requesterEmail,
generalEmailBefore,
"Status: open",
);
const urgentEmailBefore = await latestMessageID(request, requesterEmail);
await requester.page.goto("/legal/take-it-down");
await requester.page
.getByLabel("Material involved")
.selectOption("non_consensual_intimate_media");
await requester.page
.getByRole("textbox", { name: "Your full name", exact: true })
.fill("E2E Requester");
await requester.page
.getByLabel("Who are you submitting for?")
.selectOption("self");
await requester.page
.getByLabel("Exact content URLs — one per line")
.fill(`${process.env.BASE_URL}/requests/e2e-urgent-reported-content`);
await requester.page
.getByLabel(/Identify the material without reproducing it/)
.fill(urgentExplanation);
await requester.page
.getByLabel("Electronic signature (type your full name)")
.fill("E2E Requester");
await requester.page
.getByLabel(/I have a good-faith belief that this intimate visual material/)
.check();
await requester.page
.getByLabel(/I confirm that the information in this request is accurate/)
.check();
await requester.page
.getByRole("button", { name: "Submit urgent removal request" })
.click();
await expect(requester.page).toHaveURL(
/\/legal\/content-removal\/received\?reference=REM-/,
);
await waitForNewEmail(
request,
requesterEmail,
urgentEmailBefore,
"Status: urgent_review",
);
await gotoLiveView(admin.page, "/support/operations?queue=legal");
await admin.page
.locator("#legal-case-filters")
.getByLabel("Search")
.fill(requesterEmail);
await expect(admin.page.locator("main tbody tr")).toHaveCount(2);
const urgentRow = admin.page
.locator("main tbody tr")
.filter({ hasText: "take it down" });
await expect(urgentRow).toHaveCount(1);
await urgentRow.getByRole("link", { name: "Open" }).click();
await expect(
admin.page.getByText(urgentExplanation, { exact: true }),
).toBeVisible();
await admin.page.getByLabel("Case status").selectOption("actioned");
await admin.page
.getByLabel("Decision or information request")
.fill(legalResolution);
const legalDecisionEmailBefore = await latestMessageID(
request,
requesterEmail,
);
await admin.page.getByRole("button", { name: "Save and notify" }).click();
await expect(admin.page.getByText("Removal notice updated.")).toBeVisible();
await waitForNewEmail(
request,
requesterEmail,
legalDecisionEmailBefore,
legalResolution,
);
assertRequesterClean();
assertAdminClean();
await requester.context.close();
await admin.context.close();
});