import { test, expect } from '@playwright/test'; import { createNewDoc } from './helpers'; test.describe('Mobile — Docs Editor', () => { test.beforeEach(async ({ page }) => { await createNewDoc(page); }); test('editor is visible and fills viewport width', async ({ page }) => { const editor = page.locator('.tiptap'); await expect(editor).toBeVisible(); const viewport = page.viewportSize()!; const box = await editor.boundingBox(); // Editor should use most of the viewport width expect(box!.width).toBeGreaterThan(viewport.width * 0.8); }); test('toolbar buttons meet minimum touch target size', async ({ page }) => { const viewport = page.viewportSize()!; if (viewport.width > 768) test.skip(); const buttons = page.locator('.tb-btn:visible'); const count = await buttons.count(); expect(count).toBeGreaterThan(0); for (let i = 0; i < Math.min(count, 5); i++) { const box = await buttons.nth(i).boundingBox(); if (box) { expect(box.width).toBeGreaterThanOrEqual(42); // 44 target, 2px tolerance expect(box.height).toBeGreaterThanOrEqual(42); } } }); test('non-essential toolbar items hidden on mobile', async ({ page }) => { const viewport = page.viewportSize()!; if (viewport.width > 768) test.skip(); const hiddenItems = page.locator('.toolbar-mobile-hide'); const count = await hiddenItems.count(); for (let i = 0; i < count; i++) { await expect(hiddenItems.nth(i)).not.toBeVisible(); } }); test('can type and see text in editor', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('Mobile typing test'); await expect(editor).toContainText('Mobile typing test'); }); test('topbar does not overflow horizontally', async ({ page }) => { const viewport = page.viewportSize()!; const topbar = page.locator('.app-topbar'); const box = await topbar.boundingBox(); if (box) { expect(box.width).toBeLessThanOrEqual(viewport.width + 1); } }); test('document title input is accessible', async ({ page }) => { const titleInput = page.locator('.doc-title-input'); await expect(titleInput).toBeVisible(); await titleInput.fill('My Mobile Doc'); await expect(titleInput).toHaveValue('My Mobile Doc'); }); test('word count visible in footer', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('one two three'); await expect(page.locator('#word-count')).toContainText('3 words', { timeout: 5000 }); }); test('command palette opens and is usable', async ({ page }) => { const viewport = page.viewportSize()!; await page.keyboard.press('Meta+k'); const palette = page.locator('.cmd-palette'); await expect(palette).toBeVisible({ timeout: 3000 }); // Palette should fit within viewport const box = await palette.boundingBox(); if (box) { expect(box.right).toBeLessThanOrEqual(viewport.width + 5); expect(box.bottom).toBeLessThanOrEqual(viewport.height + 5); } // Dismiss await page.keyboard.press('Escape'); await expect(palette).not.toBeVisible(); }); test('modals are full-screen on phones', async ({ page }) => { const viewport = page.viewportSize()!; if (viewport.width > 480) test.skip(); // Open share dialog as a test modal await page.click('#btn-share'); const dialog = page.locator('#share-dialog'); await expect(dialog).toBeVisible({ timeout: 3000 }); const box = await dialog.boundingBox(); if (box) { // Should be approximately full-width on phones expect(box.width).toBeGreaterThan(viewport.width * 0.9); } await page.click('#share-dialog-close'); }); });