/** * Etapa 9 Sprint 1.5 — Badge ⚡ naranja InQ en BpmnCanvas. * * Validaciones: * 1. El badge aparece cuando una actividad se marca como automatizable * 2. El badge desaparece cuando se desmarca (toggle off) * 3. El badge reaparece al volver a marcar (toggle on) * 4. El badge usa var(--inq-orange) / naranja InQ (no ámbar legacy) * 5. Screenshots: workspace-badge-on.png + workspace-badge-detail.png */ import { test, expect } from '@playwright/test' import { resolve } from 'path' import { mkdirSync } from 'fs' import { fileURLToPath } from 'url' const __dirname = fileURLToPath(new URL('.', import.meta.url)) const BPMN_DIR = resolve(__dirname, '../../public/sample-processes') const SCREENSHOTS_DIR = resolve(__dirname, '../screenshots/etapa-9') test.beforeAll(() => { mkdirSync(SCREENSHOTS_DIR, { recursive: true }) }) async function loadProcess(page: import('@playwright/test').Page, filename: string) { await page.goto('/') await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, filename)) await page.waitForURL(/\/workspace\//, { timeout: 15_000 }) await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 }) await page.waitForTimeout(800) } async function markAutomatable(page: import('@playwright/test').Page, elementId: string) { await page.locator(`[data-element-id="${elementId}"]`).first().click() await page.waitForTimeout(400) const toggle = page.getByRole('switch', { name: /automatizable/i }) const checked = await toggle.getAttribute('aria-checked') if (checked === 'false') { await toggle.click() await page.waitForTimeout(200) // Guardar es necesario para persistir al store → actualiza automatableElementIds await page.getByRole('button', { name: /Guardar/i }).click() } await page.waitForSelector('.automatable-badge', { timeout: 8_000 }) } async function unmarkAutomatable(page: import('@playwright/test').Page, elementId: string) { await page.locator(`[data-element-id="${elementId}"]`).first().click() await page.waitForTimeout(400) const toggle = page.getByRole('switch', { name: /automatizable/i }) const checked = await toggle.getAttribute('aria-checked') if (checked === 'true') { await toggle.click() await page.waitForTimeout(200) await page.getByRole('button', { name: /Guardar/i }).click() } await page.waitForTimeout(800) // esperar que el overlay se elimine } test('badge ⚡ aparece al marcar actividad como automatizable', async ({ page }) => { await loadProcess(page, 'medium-with-gateways.bpmn') await markAutomatable(page, 'task_recv') const badge = page.locator('.automatable-badge').first() await expect(badge).toBeVisible({ timeout: 5_000 }) await expect(badge).toHaveText('⚡') }) test('badge ⚡ desaparece al desmarcar actividad', async ({ page }) => { await loadProcess(page, 'medium-with-gateways.bpmn') // Marcar await markAutomatable(page, 'task_recv') await expect(page.locator('.automatable-badge').first()).toBeVisible({ timeout: 5_000 }) // Desmarcar await unmarkAutomatable(page, 'task_recv') await expect(page.locator('.automatable-badge')).toHaveCount(0, { timeout: 5_000 }) }) test('badge ⚡ reaparece después de toggle on → off → on', async ({ page }) => { await loadProcess(page, 'medium-with-gateways.bpmn') await markAutomatable(page, 'task_recv') await expect(page.locator('.automatable-badge')).toHaveCount(1, { timeout: 5_000 }) await unmarkAutomatable(page, 'task_recv') await expect(page.locator('.automatable-badge')).toHaveCount(0, { timeout: 5_000 }) await markAutomatable(page, 'task_recv') await expect(page.locator('.automatable-badge')).toHaveCount(1, { timeout: 5_000 }) }) test('screenshot workspace-badge-on: múltiples badges visibles', async ({ page }) => { await loadProcess(page, 'medium-with-gateways.bpmn') for (const id of ['task_recv', 'task_score', 'task_analisis']) { const el = page.locator(`[data-element-id="${id}"]`) if (await el.count() > 0) { await markAutomatable(page, id) } } await page.waitForTimeout(400) await page.screenshot({ path: resolve(SCREENSHOTS_DIR, 'workspace-badge-on.png'), fullPage: false, }) const badgeCount = await page.locator('.automatable-badge').count() expect(badgeCount).toBeGreaterThanOrEqual(1) }) test('screenshot workspace-badge-detail: zoom in sobre nodo automatizable', async ({ page }) => { await loadProcess(page, 'medium-with-gateways.bpmn') await markAutomatable(page, 'task_recv') // Capturar área del nodo con el badge const nodeWithBadge = page.locator('[data-element-id="task_recv"]').first() const box = await nodeWithBadge.boundingBox() if (box) { const padding = 40 await page.screenshot({ path: resolve(SCREENSHOTS_DIR, 'workspace-badge-detail.png'), clip: { x: Math.max(0, box.x - padding), y: Math.max(0, box.y - padding), width: box.width + padding * 2, height: box.height + padding * 2, }, }) } else { await page.screenshot({ path: resolve(SCREENSHOTS_DIR, 'workspace-badge-detail.png') }) } await expect(page.locator('.automatable-badge')).toBeVisible() })