import { test, expect } from '@playwright/test'; test.describe('Plan Editor Drag & Drop Vibration', () => { test.beforeEach(async ({ page }) => { // Mock navigator.vibrate await page.addInitScript(() => { try { Object.defineProperty(navigator, 'vibrate', { value: (pattern) => { console.log(`Vibration triggered: ${pattern}`); window.dispatchEvent(new CustomEvent('vibration-triggered', { detail: pattern })); return true; }, writable: true, configurable: true, }); } catch (e) { console.error('Failed to mock vibrate', e); } }); await page.goto('/'); // Create a new user const uniqueId = Date.now().toString(); const email = `dragvibetest${uniqueId}@example.com`; await page.fill('input[type="email"]', email); await page.fill('input[type="password"]', 'password123'); await page.click('button:has-text("Sign Up")'); await page.waitForURL('**/dashboard'); if (await page.getByPlaceholder('Enter your name').isVisible()) { await page.getByPlaceholder('Enter your name').fill('Vibe Tester'); await page.getByRole('button', { name: 'Complete Profile' }).click(); } }); test('should trigger vibration on drag start', async ({ page }) => { // Navigate to Plans await page.getByRole('button', { name: 'Plans' }).click(); // Create Plan await page.getByLabel('Create Plan').click(); await page.getByLabel('Plan Name').fill('Vibration Plan'); // Add Exercises await page.getByRole('button', { name: 'Add Exercise' }).click(); await page.getByRole('button', { name: 'Create New Exercise' }).click(); await page.getByLabel('Exercise Name').fill('Exercise 1'); await page.getByRole('button', { name: 'Save Exercise' }).click(); await page.getByRole('button', { name: 'Add Exercise' }).click(); await page.getByRole('button', { name: 'Create New Exercise' }).click(); await page.getByLabel('Exercise Name').fill('Exercise 2'); await page.getByRole('button', { name: 'Save Exercise' }).click(); // Listen for vibration event with timeout let vibrationDetected = false; page.on('console', msg => { if (msg.text().includes('Vibration triggered') || msg.text().includes('handlePointerDown')) { console.log('Browser Console:', msg.text()); } if (msg.text().includes('Vibration triggered')) vibrationDetected = true; }); // Drag const dragHandle = page.locator('.cursor-grab').first(); const dragDest = page.locator('.cursor-grab').nth(1); // Drag using manual pointer control simulating TOUCH via evaluate const box = await dragHandle.boundingBox(); if (box) { // Dispatch directly in browser to ensure React synthetic event system picks it up await dragHandle.evaluate((el) => { const event = new PointerEvent('pointerdown', { bubbles: true, cancelable: true, pointerType: 'touch', clientX: 0, clientY: 0, isPrimary: true }); el.dispatchEvent(event); }); // Wait for usage await page.waitForTimeout(500); // Dispatch pointerup await dragHandle.evaluate((el) => { const event = new PointerEvent('pointerup', { bubbles: true, cancelable: true, pointerType: 'touch', isPrimary: true }); el.dispatchEvent(event); }); } // Check flag expect(vibrationDetected).toBeTruthy(); }); });