/** * SEL-series (desktop selection mode) — Fase 5.11 * * The long-press entry is gestural and Chromium touch emulation is too flaky * to drive reliably, so mobile-only tests stay deferred. The desktop toggle * button exercises the same state machine end-to-end, so these three tests * give us confidence on the full selection → bulk-action flow. */ import { test, expect } from '@playwright/test'; import { USERS } from '../fixtures/users.js'; import { loginAs } from '../fixtures/login.js'; const SEED_LIST = '/lists/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'; const ADD_ITEM = /add item|añadir producto/i; test.describe('Selection mode — desktop', () => { test.beforeEach(async ({ page }) => { await loginAs(page, USERS.borja); }); test('SEL-01: toggle enters selection, row click toggles selection, Cancel exits', async ({ page }) => { await page.goto(SEED_LIST); // Seed data guarantees at least one row (Milk, Bread, Eggs…). await expect(page.getByTestId('item-row').first()).toBeVisible({ timeout: 10_000 }); // Enter selection mode via the header toggle. await page.getByTestId('selection-toggle').click(); await expect(page.getByTestId('selection-bar')).toBeVisible({ timeout: 3_000 }); // Click a row — it becomes selected (data-selected="true"). const firstRow = page.getByTestId('item-row').first(); await firstRow.click(); await expect(firstRow).toHaveAttribute('data-selected', 'true'); // Selection count label updates. await expect(page.getByTestId('selection-bar')).toContainText(/1 selected|1 seleccionad/i); // Cancel exits and clears selection. await page.getByTestId('selection-bar').getByRole('button', { name: /^cancel$|^cancelar$/i }).click(); await expect(page.getByTestId('selection-bar')).not.toBeVisible(); await expect(firstRow).not.toHaveAttribute('data-selected', 'true'); }); test('SEL-02: bulk delete removes selected rows with an Undo toast', async ({ page }) => { await page.goto(SEED_LIST); // Seed a fresh row we can safely delete. const input = page.getByPlaceholder(ADD_ITEM); await expect(input).toBeVisible({ timeout: 10_000 }); const name = `SEL-02-${Date.now()}`; await input.fill(name); await input.press('Enter'); const row = page.getByTestId('item-row').filter({ hasText: name }).first(); await expect(row).toBeVisible({ timeout: 5_000 }); // Enter selection, select only our seeded row, then delete. await page.getByTestId('selection-toggle').click(); await row.click(); await expect(row).toHaveAttribute('data-selected', 'true'); await page .getByTestId('selection-bar') .getByRole('button', { name: /^delete$|^eliminar$/i }) .click(); // Row vanishes from the list; undo toast confirms the batch label. await expect( page.getByTestId('item-row').filter({ hasText: name }) ).toHaveCount(0, { timeout: 5_000 }); await expect(page.getByTestId('undo-toast')).toBeVisible({ timeout: 3_000 }); }); test('SEL-03: mark-checked flips all selected unchecked items to checked', async ({ page }) => { await page.goto(SEED_LIST); const input = page.getByPlaceholder(ADD_ITEM); await expect(input).toBeVisible({ timeout: 10_000 }); const name = `SEL-03-${Date.now()}`; await input.fill(name); await input.press('Enter'); const row = page.getByTestId('item-row').filter({ hasText: name }).first(); await expect(row).toBeVisible({ timeout: 5_000 }); await page.getByTestId('selection-toggle').click(); await row.click(); await page .getByTestId('selection-bar') .getByRole('button', { name: /mark checked|marcar/i }) .click(); // After bulk check the row should render with strikethrough (muted text). await expect( page.getByTestId('item-row').filter({ hasText: name }).locator('.line-through') ).toBeVisible({ timeout: 5_000 }); }); });