riseup-squad18/MEDICONNECT 2/src/__tests__/accessibilityMenu.e2e.test.ts
2025-10-07 14:53:47 -03:00

144 lines
4.5 KiB
TypeScript

import { describe, it, expect, beforeAll, afterAll } from "vitest";
import puppeteer, { Browser, Page } from "puppeteer";
import * as net from "net";
import { build, preview } from "vite";
// Porta padrão do Vite
const PORT = 5173;
const ORIGIN = `http://127.0.0.1:${PORT}`;
function waitForPort(port: number, timeoutMs = 20000): Promise<void> {
const start = Date.now();
return new Promise((resolve, reject) => {
const tryOnce = () => {
const socket = net.connect(port, "127.0.0.1");
socket.on("connect", () => {
socket.end();
resolve();
});
socket.on("error", () => {
socket.destroy();
if (Date.now() - start > timeoutMs)
reject(new Error("Timeout aguardando Vite dev server"));
else setTimeout(tryOnce, 300);
});
};
tryOnce();
});
}
let browser: Browser;
let page: Page;
let previewServer: Awaited<ReturnType<typeof preview>> | undefined;
let built = false;
async function ensurePreviewServer() {
// Se já existe algo na porta (ex dev aberto manualmente), apenas usa
try {
await waitForPort(PORT, 800);
return;
} catch {
/* inicia preview */
}
if (!built) {
await build();
built = true;
}
previewServer = await preview({
preview: { port: PORT, host: "127.0.0.1" },
server: { middlewareMode: false },
} as unknown as Parameters<typeof preview>[0]);
await waitForPort(PORT);
}
describe("E2E Accessibility Menu", () => {
beforeAll(async () => {
await ensurePreviewServer();
browser = await puppeteer.launch({ headless: true });
page = await browser.newPage();
await page.goto(ORIGIN, { waitUntil: "domcontentloaded" });
}, 90000);
afterAll(async () => {
if (browser) await browser.close();
if (previewServer) {
// @ts-expect-error acesso interno não tipado
const httpServer =
previewServer.httpServer || previewServer.server?.httpServer;
if (httpServer) httpServer.close();
}
});
it("abre e fecha o diálogo de acessibilidade", async () => {
// Botão flutuante
await page.waitForSelector('button[aria-label="Menu de Acessibilidade"]', {
timeout: 10000,
});
await page.click('button[aria-label="Menu de Acessibilidade"]');
await page.waitForSelector('div[role="dialog"][aria-modal="true"]', {
timeout: 5000,
});
const exists = await page.$('div[role="dialog"][aria-modal="true"]');
expect(exists).not.toBeNull();
// Pressiona ESC para fechar
await page.keyboard.press("Escape");
// Pequeno delay
await new Promise((r) => setTimeout(r, 150));
const still = await page.$('div[role="dialog"][aria-modal="true"]');
expect(still).toBeNull();
}, 30000);
it("ativa dark mode e alto contraste e persiste após reload", async () => {
// Abre menu (caso esteja fechado)
const trigger = await page.$('button[aria-label="Menu de Acessibilidade"]');
if (trigger) {
await trigger.click();
await page.waitForSelector('div[role="dialog"][aria-modal="true"]', {
timeout: 5000,
});
}
// Helper para clicar botão pelo texto visível interno
async function clickToggleByAria(label: string) {
const selector = `button[aria-label="${label}"]`;
await page.waitForSelector(selector, { timeout: 5000 });
await page.click(selector);
}
// Ativa Modo Escuro e Alto Contraste (aria-label fica igual ao label)
await clickToggleByAria("Modo Escuro");
await clickToggleByAria("Alto Contraste");
// Verifica classes aplicadas
const classesBefore = await page.evaluate(() =>
Array.from(document.documentElement.classList)
);
expect(classesBefore).toContain("dark");
expect(classesBefore).toContain("high-contrast");
// Recarrega página para validar persistência (localStorage -> rehidratação)
await page.reload({ waitUntil: "domcontentloaded" });
const classesAfter = await page.evaluate(() =>
Array.from(document.documentElement.classList)
);
expect(classesAfter).toContain("dark");
expect(classesAfter).toContain("high-contrast");
// (Opcional) Reabre menu e desfaz para não impactar execuções subsequentes
const trigger2 = await page.$(
'button[aria-label="Menu de Acessibilidade"]'
);
if (trigger2) {
await trigger2.click();
await page.waitForSelector('div[role="dialog"][aria-modal="true"]', {
timeout: 5000,
});
await clickToggleByAria("Modo Escuro");
await clickToggleByAria("Alto Contraste");
await page.keyboard.press("Escape");
}
}, 45000);
});