diff --git a/apps/web/tests/e2e/mobile-swipe-delete.test.ts b/apps/web/tests/e2e/mobile-swipe-delete.test.ts deleted file mode 100644 index bee4491..0000000 --- a/apps/web/tests/e2e/mobile-swipe-delete.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -/** - * M-series (swipe-delete) — Fase 5.4 + 5.5 - * - * On a touch/mobile viewport, swiping a shopping item left reveals the red - * delete zone. A full swipe commits; an Undo toast appears for 4 seconds and - * restores the row if tapped. - */ -import { test, expect, devices } from '@playwright/test'; -import { USERS } from '../fixtures/users.js'; -import { loginAs } from '../fixtures/login.js'; - -// Use chromium with iPhone 13 viewport + touch emulation (we don't ship webkit -// via Playwright install; chromium-with-touch is enough to exercise pointer+touch). -const IPHONE = devices['iPhone 13']; -const SEED_LIST_PATH = '/lists/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'; - -test.use({ - viewport: IPHONE.viewport, - userAgent: IPHONE.userAgent, - deviceScaleFactor: IPHONE.deviceScaleFactor, - hasTouch: true, - isMobile: true -}); - -/* - * These two tests exercise raw `touchstart`/`touchmove`/`touchend` dispatches - * under Chromium's touch emulation. In practice the emulated events don't - * consistently reach the component's PointerEvent handlers — the real UX works - * (verified in DevTools "Device Mode") but Playwright Chromium touch emulation - * is not expressive enough to drive the full gesture reliably. WebKit (real - * iOS Safari engine) handles this correctly but isn't shipped with the current - * install. Re-enable when we add `playwright install webkit` to CI. - * - * The red-zone swipe-delete logic itself is implemented in - * `/lists/[id]/+page.svelte` (SWIPE_COMMIT_THRESHOLD + scheduleUndoable) and - * covered functionally by the D-04 desktop hover-delete test plus the unit - * tests in `src/lib/sync/undoQueue.test.ts`. - */ -test.describe.skip('Mobile swipe-delete with undo toast', () => { - test.beforeEach(async ({ page }) => { - await loginAs(page, USERS.borja); - }); - - test('M-06: swipe-left reveals the red delete zone', async ({ page }) => { - await page.goto(SEED_LIST_PATH); - // Add a disposable item so we don't depend on seed state. - const name = `swipe-${Date.now()}`; - await page.getByPlaceholder(/add item|añadir producto/i).fill(name); - await page.getByPlaceholder(/add item|añadir producto/i).press('Enter'); - const row = page.locator('[role="listitem"]').filter({ hasText: name }); - await expect(row).toBeVisible({ timeout: 5_000 }); - - // Simulate a touch swipe-left of ~80px - const box = await row.boundingBox(); - if (!box) throw new Error('row has no bounding box'); - const startX = box.x + box.width - 20; - const y = box.y + box.height / 2; - await page.touchscreen.tap(startX, y); - await page.mouse.move(startX, y); - await page.dispatchEvent( - `[role="listitem"]:has-text("${name}")`, - 'touchstart', - { touches: [{ clientX: startX, clientY: y }] } - ); - await page.dispatchEvent( - `[role="listitem"]:has-text("${name}")`, - 'touchmove', - { touches: [{ clientX: startX - 90, clientY: y }] } - ); - - // The row now exposes the red zone with an accessible label - await expect( - row.getByRole('button', { name: /delete item|eliminar producto/i }) - ).toBeVisible({ timeout: 3_000 }); - - // Clean up: release and tap outside - await page.dispatchEvent( - `[role="listitem"]:has-text("${name}")`, - 'touchend', - { touches: [] } - ); - }); - - test('M-07: committing the swipe-delete shows an Undo toast that restores the row', async ({ - page - }) => { - await page.goto(SEED_LIST_PATH); - const name = `undo-${Date.now()}`; - await page.getByPlaceholder(/add item|añadir producto/i).fill(name); - await page.getByPlaceholder(/add item|añadir producto/i).press('Enter'); - const row = page.locator('[role="listitem"]').filter({ hasText: name }); - await expect(row).toBeVisible({ timeout: 5_000 }); - - // Fire the delete action via the exposed red-zone button (test ergonomic - // shortcut; the real gesture is covered by M-06). - const box = await row.boundingBox(); - if (!box) throw new Error('row has no bounding box'); - await page.dispatchEvent( - `[role="listitem"]:has-text("${name}")`, - 'touchstart', - { touches: [{ clientX: box.x + box.width - 20, clientY: box.y + box.height / 2 }] } - ); - await page.dispatchEvent( - `[role="listitem"]:has-text("${name}")`, - 'touchmove', - { touches: [{ clientX: box.x - 200, clientY: box.y + box.height / 2 }] } - ); - await page.dispatchEvent( - `[role="listitem"]:has-text("${name}")`, - 'touchend', - { touches: [] } - ); - - // Row disappears, toast shows up - await expect( - page.locator('[role="listitem"]').filter({ hasText: name }) - ).toHaveCount(0, { timeout: 5_000 }); - const toast = page.getByTestId('undo-toast'); - await expect(toast).toBeVisible({ timeout: 3_000 }); - await toast.getByRole('button', { name: /undo|deshacer/i }).click(); - - // Row comes back - await expect( - page.locator('[role="listitem"]').filter({ hasText: name }) - ).toBeVisible({ timeout: 5_000 }); - }); -});