|
| 1 | +import { expect, test } from "@playwright/test"; |
| 2 | + |
| 3 | +import { |
| 4 | + ensureCurrentYearDeclaration, |
| 5 | + resetDeclarationToDraft, |
| 6 | +} from "./helpers/db"; |
| 7 | + |
| 8 | +const TEST_SIREN = "130025265"; |
| 9 | + |
| 10 | +test.describe("admin impersonation — read-only guards", () => { |
| 11 | + test.beforeEach(async () => { |
| 12 | + // A declaration row must exist before impersonation starts, because |
| 13 | + // `declaration.getOrCreate` blocks the insert branch during mimoquage |
| 14 | + // (issue #3230). The server component on step 1 calls getOrCreate on |
| 15 | + // every render and would otherwise throw FORBIDDEN. |
| 16 | + await ensureCurrentYearDeclaration(); |
| 17 | + await resetDeclarationToDraft(); |
| 18 | + }); |
| 19 | + |
| 20 | + test.afterEach(async ({ page }) => { |
| 21 | + // Best-effort stop of any impersonation left over so the next test |
| 22 | + // (or the next describe block) starts from a clean session. |
| 23 | + await page.goto("/admin/impersonate"); |
| 24 | + const stopBtn = page.getByRole("button", { name: /arrêter le mimoquage/i }); |
| 25 | + if (await stopBtn.isVisible({ timeout: 1_000 }).catch(() => false)) { |
| 26 | + await stopBtn.click(); |
| 27 | + } |
| 28 | + }); |
| 29 | + |
| 30 | + test("form submit is disabled with a read-only tooltip during mimoquage", async ({ |
| 31 | + page, |
| 32 | + }) => { |
| 33 | + await page.goto("/admin/impersonate"); |
| 34 | + await page.getByLabel("SIREN de l'entreprise").fill(TEST_SIREN); |
| 35 | + await page.getByRole("button", { name: "Rechercher" }).click(); |
| 36 | + await page.getByRole("button", { name: /valider et mimoquer/i }).click(); |
| 37 | + |
| 38 | + await page.waitForURL("**/mon-espace"); |
| 39 | + await expect(page.getByText(/vous mimoquez l'entreprise/i)).toBeVisible(); |
| 40 | + |
| 41 | + await page.goto("/declaration-remuneration/etape/1"); |
| 42 | + |
| 43 | + const submitButton = page.getByRole("button", { name: /suivant/i }); |
| 44 | + await expect(submitButton).toBeVisible(); |
| 45 | + await expect(submitButton).toBeDisabled(); |
| 46 | + const tooltipId = await submitButton.getAttribute("aria-describedby"); |
| 47 | + expect(tooltipId).not.toBeNull(); |
| 48 | + await expect(page.locator(`#${tooltipId}`)).toContainText(/mimoquage/i); |
| 49 | + }); |
| 50 | + |
| 51 | + test("file upload endpoint returns 403 during impersonation", async ({ |
| 52 | + page, |
| 53 | + }) => { |
| 54 | + await page.goto("/admin/impersonate"); |
| 55 | + await page.getByLabel("SIREN de l'entreprise").fill(TEST_SIREN); |
| 56 | + await page.getByRole("button", { name: "Rechercher" }).click(); |
| 57 | + await page.getByRole("button", { name: /valider et mimoquer/i }).click(); |
| 58 | + await page.waitForURL("**/mon-espace"); |
| 59 | + |
| 60 | + const response = await page.request.post("/api/upload", { |
| 61 | + headers: { |
| 62 | + "content-type": "application/pdf", |
| 63 | + "x-filename": "impersonated.pdf", |
| 64 | + "x-flow-type": "cse_opinion", |
| 65 | + }, |
| 66 | + data: Buffer.from("%PDF-"), |
| 67 | + }); |
| 68 | + expect(response.status()).toBe(403); |
| 69 | + const body = await response.json(); |
| 70 | + expect(body.error).toMatch(/mimoquage/i); |
| 71 | + }); |
| 72 | +}); |
0 commit comments