test: remove obsolete mobile-swipe-delete.test.ts
The file tested a Fase 2b.5 interaction — full-swipe commits a delete with an undo toast — that Fase 5.10 replaced. Swipes on the list detail view are now a symmetric check/uncheck toggle; delete lives in the double-tap overlay and in selection mode. The two tests were describe.skip'd since Fase 5.10 and the UX they describe doesn't exist anymore. The swipe-toggle gesture that replaced it is still untested at the E2E level because Chromium touch emulation can't drive pointer/touch events into Svelte's component handlers reliably. Adding `playwright install webkit` to CI would unblock a fresh `mobile-swipe-toggle.test.ts` with M-06 swipe-right-check, M-07 swipe-left-uncheck, and M-08 wrong- direction snapback. Noted in plan/fase-5-mobile-ux.md §5.10.b. Verification just test-all → 228 green, 2 skipped (both are the upstream Realtime presence bug in realtime-presence.test.ts; everything else passes). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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 });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user