From 3ac5d303e806efbb041c28bc929f38314ee355dd Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 2 Aug 2026 23:14:53 +0000 Subject: [PATCH] =?UTF-8?q?test(B136):=20assert=203=C3=972=20grid=20by=20c?= =?UTF-8?q?olumn=20clusters=20(tolerant=20row=20heights)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/e2e/campaignMunicipalities.e2e.spec.ts | 7 ++++ tests/e2e/helpers/actionGridGeometry.ts | 39 +++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/e2e/campaignMunicipalities.e2e.spec.ts b/tests/e2e/campaignMunicipalities.e2e.spec.ts index f7e3d7ad..f254582f 100644 --- a/tests/e2e/campaignMunicipalities.e2e.spec.ts +++ b/tests/e2e/campaignMunicipalities.e2e.spec.ts @@ -513,6 +513,13 @@ test.describe('Municípios — FAB overlay polish (B126)', () => { const actionsRegion = overlay.getByLabel('Ações rápidas') await expect(actionsRegion.locator('ul[data-layout="grid-3"]')).toBeVisible() + for (const label of staffActionLabels) { + await expect( + actionsRegion + .getByRole('link', { name: label, exact: true }) + .or(actionsRegion.getByRole('button', { name: label, exact: true })), + ).toBeVisible() + } const boxes = await collectActionBoundingBoxes(actionsRegion, staffActionLabels) assertThreeColumnActionGrid(groupActionsByRow(boxes), 2) diff --git a/tests/e2e/helpers/actionGridGeometry.ts b/tests/e2e/helpers/actionGridGeometry.ts index fc0adfc8..673c5a02 100644 --- a/tests/e2e/helpers/actionGridGeometry.ts +++ b/tests/e2e/helpers/actionGridGeometry.ts @@ -2,6 +2,7 @@ import type { Locator } from '@playwright/test' import { expect } from '@playwright/test' const ROW_Y_TOLERANCE_PX = 12 +const COLUMN_X_TOLERANCE_PX = 24 export type ActionBoundingBox = { label: string @@ -54,11 +55,47 @@ export function groupActionsByRow( return rows } +function clusterActionsByColumn( + boxes: readonly ActionBoundingBox[], + tolerancePx = COLUMN_X_TOLERANCE_PX, +): ActionBoundingBox[][] { + const sorted = [...boxes].sort((left, right) => left.x - right.x) + const columns: ActionBoundingBox[][] = [] + + for (const box of sorted) { + const column = columns.find((entry) => Math.abs(entry[0]!.x - box.x) <= tolerancePx) + if (column) { + column.push(box) + } else { + columns.push([box]) + } + } + + for (const column of columns) { + column.sort((left, right) => left.y - right.y) + } + + return columns.sort((left, right) => left[0]!.x - right[0]!.x) +} + /** Asserts a 3-column grid with `expectedRowCount` rows (staff = 2 rows of 3). */ export function assertThreeColumnActionGrid( - rows: readonly ActionBoundingBox[][], + boxes: readonly ActionBoundingBox[], expectedRowCount: number, ) { + expect(boxes).toHaveLength(expectedRowCount * 3) + + const columns = clusterActionsByColumn(boxes) + expect(columns).toHaveLength(3) + for (const column of columns) { + expect(column).toHaveLength(expectedRowCount) + } + + const medianHeight = [...boxes].map((box) => box.height).sort((left, right) => left - right)[ + Math.floor(boxes.length / 2) + ]! + const rowTolerance = Math.max(ROW_Y_TOLERANCE_PX, medianHeight * 0.35) + const rows = groupActionsByRow(boxes, rowTolerance) expect(rows).toHaveLength(expectedRowCount) for (const row of rows) {