FieldOps/e2e/tests/mai-call.spec.ts

80 lines
4.1 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { ADMIN_BASE } from '../playwright.config';
/**
* Happy-path E2E for MAI CALL v0.1:
* operator creates request → admin claims → admin resolves
*
* Preconditions (met by `pnpm db:seed` + running docker compose):
* - Demo Factory tenant with workstations CTR04, QVN_RTL_2, MTG_01
* - admin@demo.local with role ADMIN
* - AUTH_DEV_AUTOLOGIN=true on both servers (set in playwright.config.ts)
*/
test('MAI CALL happy path: create → claim → resolve', async ({ page, context }) => {
// Use a unique description so the test can find its own card in the queue.
const desc = `E2E ${Date.now()} — ruído anormal no posto`;
// ── 0. Badge in to a workstation (the request posto now comes from the
// operator's active session, not a per-request dropdown) ────────────
await page.goto('/');
const requestBtn = page.getByTestId('btn-request-maintenance');
if (!(await requestBtn.isVisible().catch(() => false))) {
// No active session yet → pick the first workstation in the badge-in panel.
await page.getByTestId('badge-in-station').first().click();
await expect(requestBtn).toBeVisible({ timeout: 15_000 });
}
// ── 1. Operator creates a request ────────────────────────────────────────
await requestBtn.click();
await page.waitForURL('**/maintenance/new**');
// The workstation is shown read-only from the session; just describe + submit.
await page.fill('#description', desc);
await expect(page.locator('button[type=submit]')).toBeEnabled({ timeout: 15_000 });
await page.click('button[type=submit]');
// ── 2. Wait for the sync to complete ─────────────────────────────────────
// The form queues to IndexedDB; the SyncProvider immediately syncs when
// online. The sent page changes from "Em fila" → "Pedido enviado".
await page.waitForURL('**/maintenance/sent**');
await expect(page.locator('h1')).toHaveText('Pedido enviado', { timeout: 30_000 });
// ── 3. Admin queue shows the request ─────────────────────────────────────
const adminPage = await context.newPage();
await adminPage.goto(`${ADMIN_BASE}/maintenance`);
// Find the card that contains our description (admin polls every 5s)
const card = adminPage
.locator('[data-testid="request-card"]')
.filter({ hasText: desc.slice(0, 40) });
await expect(card).toBeVisible({ timeout: 15_000 });
// Card starts as OPEN
await expect(card.locator('span', { hasText: 'Aberto' })).toBeVisible();
// ── 4. Admin claims the request ───────────────────────────────────────────
await card.locator('button', { hasText: 'Aceitar' }).click();
// Card changes to CLAIMED
await expect(card.locator('span', { hasText: 'Em curso' })).toBeVisible({ timeout: 10_000 });
await expect(card.locator('button', { hasText: 'Aceitar' })).not.toBeVisible();
// ── 5. Enable RESOLVED filter so the card stays visible after resolve ─────
await adminPage.locator('label', { hasText: 'Resolvido' }).click();
// ── 6. Admin resolves the request ────────────────────────────────────────
await card.locator('button', { hasText: 'Marcar resolvido' }).click();
const dialog = adminPage.locator('h2', { hasText: 'Marcar como resolvido' });
await expect(dialog).toBeVisible({ timeout: 5_000 });
await adminPage.locator('button', { hasText: 'Confirmar' }).click();
// Card changes to RESOLVED
await expect(card.locator('span', { hasText: 'Resolvido' })).toBeVisible({ timeout: 10_000 });
// No action buttons remain on RESOLVED card
await expect(card.locator('button', { hasText: 'Aceitar' })).not.toBeVisible();
await expect(card.locator('button', { hasText: 'Marcar resolvido' })).not.toBeVisible();
});