feat: refonte mobile de la section Configurations #114
This commit is contained in:
@@ -1,15 +1,18 @@
|
||||
/**
|
||||
* E2E tests for the Configurations modal on mobile (BUG-071).
|
||||
* E2E tests for the Configurations modal on mobile (BUG-071 + #114).
|
||||
*
|
||||
* Runs only under the `chromium-mobile` Playwright project (viewport ≤ 768px);
|
||||
* skipped on the desktop project that the CI job executes — same convention
|
||||
* as mobile-editor.spec.js.
|
||||
*
|
||||
* Covered:
|
||||
* - the TOC hamburger (#config-hamburger) is visible and reveals #config-nav,
|
||||
* which is hidden by default on mobile;
|
||||
* - the TOC hamburger (#config-hamburger) is visible and reveals #config-nav
|
||||
* as a left slide-over drawer (fixed positioning), hidden by default;
|
||||
* - the drawer has a close button (#config-toc-close) and a dimming backdrop
|
||||
* (tap outside closes the drawer, not the whole modal);
|
||||
* - picking a TOC entry scrolls to the section, marks the link active and
|
||||
* collapses the nav;
|
||||
* collapses the drawer;
|
||||
* - the modal is full-screen (100dvh) and interactive controls are ≥44px;
|
||||
* - the modal content does not overflow horizontally at 393px.
|
||||
*
|
||||
* Run:
|
||||
@@ -20,6 +23,7 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const MOBILE_MAX_WIDTH = 768;
|
||||
const MIN_TOUCH_TARGET = 44;
|
||||
|
||||
async function boot(page) {
|
||||
await page.goto('/');
|
||||
@@ -33,8 +37,8 @@ async function openConfigModal(page) {
|
||||
await expect(page.locator('#config-modal.active')).toBeVisible();
|
||||
}
|
||||
|
||||
test.describe('Configurations modal on mobile (BUG-071)', () => {
|
||||
test('hamburger reveals the table of contents', async ({ page, viewport }) => {
|
||||
test.describe('Configurations modal on mobile (BUG-071 + #114)', () => {
|
||||
test('hamburger reveals the TOC as a fixed drawer', async ({ page, viewport }) => {
|
||||
test.skip((viewport?.width ?? 0) > MOBILE_MAX_WIDTH, 'Mobile viewport required');
|
||||
await boot(page);
|
||||
await openConfigModal(page);
|
||||
@@ -45,9 +49,39 @@ test.describe('Configurations modal on mobile (BUG-071)', () => {
|
||||
|
||||
await page.locator('#config-hamburger').click();
|
||||
await expect(page.locator('#config-nav')).toBeVisible();
|
||||
|
||||
// #114: the drawer is a fixed slide-over, not an inline top block.
|
||||
const position = await page.locator('#config-nav').evaluate(
|
||||
(el) => window.getComputedStyle(el).position,
|
||||
);
|
||||
expect(position).toBe('fixed');
|
||||
|
||||
// The modal carries the drawer-open class (backdrop contract).
|
||||
await expect(page.locator('#config-modal')).toHaveClass(/config-toc-open/);
|
||||
});
|
||||
|
||||
test('picking a section scrolls to it and collapses the nav', async ({ page, viewport }) => {
|
||||
test('close button and backdrop dismiss the drawer, not the modal', async ({ page, viewport }) => {
|
||||
test.skip((viewport?.width ?? 0) > MOBILE_MAX_WIDTH, 'Mobile viewport required');
|
||||
await boot(page);
|
||||
await openConfigModal(page);
|
||||
|
||||
// Close button inside the drawer header.
|
||||
await page.locator('#config-hamburger').click();
|
||||
await expect(page.locator('#config-toc-close')).toBeVisible();
|
||||
await page.locator('#config-toc-close').click();
|
||||
await expect(page.locator('#config-nav')).toBeHidden();
|
||||
await expect(page.locator('#config-modal.active')).toBeVisible();
|
||||
|
||||
// Backdrop tap closes the drawer first; the modal stays open.
|
||||
// Click near the right edge of the modal (outside the left drawer).
|
||||
await page.locator('#config-hamburger').click();
|
||||
await expect(page.locator('#config-nav')).toBeVisible();
|
||||
await page.locator('#config-modal').click({ position: { x: (viewport?.width ?? 393) - 8, y: 200 } });
|
||||
await expect(page.locator('#config-nav')).toBeHidden();
|
||||
await expect(page.locator('#config-modal.active')).toBeVisible();
|
||||
});
|
||||
|
||||
test('picking a section scrolls to it and collapses the drawer', async ({ page, viewport }) => {
|
||||
test.skip((viewport?.width ?? 0) > MOBILE_MAX_WIDTH, 'Mobile viewport required');
|
||||
await boot(page);
|
||||
await openConfigModal(page);
|
||||
@@ -57,7 +91,7 @@ test.describe('Configurations modal on mobile (BUG-071)', () => {
|
||||
await expect(link).toBeVisible();
|
||||
await link.click();
|
||||
|
||||
// Nav collapses on mobile after selection…
|
||||
// Drawer collapses on mobile after selection…
|
||||
await expect(page.locator('#config-nav')).toBeHidden();
|
||||
// …the link is marked active…
|
||||
await expect(link).toHaveClass(/active/);
|
||||
@@ -76,6 +110,37 @@ test.describe('Configurations modal on mobile (BUG-071)', () => {
|
||||
.toBeLessThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('modal is full-screen and key controls meet the 44px touch target', async ({ page, viewport }) => {
|
||||
test.skip((viewport?.width ?? 0) > MOBILE_MAX_WIDTH, 'Mobile viewport required');
|
||||
await boot(page);
|
||||
await openConfigModal(page);
|
||||
|
||||
// Full-screen: the modal container fills the viewport.
|
||||
const container = page.locator('#config-modal .editor-container');
|
||||
const box = await container.boundingBox();
|
||||
expect(box).not.toBeNull();
|
||||
expect(box.width).toBeGreaterThanOrEqual((viewport?.width ?? 0) - 2);
|
||||
expect(box.height).toBeGreaterThanOrEqual((viewport?.height ?? 0) - 2);
|
||||
|
||||
// Header controls (hamburger + close) are ≥44px.
|
||||
for (const sel of ['#config-hamburger', '#config-close']) {
|
||||
const b = await page.locator(sel).boundingBox();
|
||||
expect(b, `${sel} has no bounding box`).not.toBeNull();
|
||||
expect(b.height, `${sel} height`).toBeGreaterThanOrEqual(MIN_TOUCH_TARGET);
|
||||
expect(b.width, `${sel} width`).toBeGreaterThanOrEqual(MIN_TOUCH_TARGET);
|
||||
}
|
||||
|
||||
// Backend Save row: buttons are ≥44px tall.
|
||||
await page.locator('#config-hamburger').click();
|
||||
await page.locator('#config-nav a[href="#cfg-backend-settings"]').click();
|
||||
await expect(page.locator('#config-nav')).toBeHidden();
|
||||
const saveBtn = page.locator('#cfg-save-backend');
|
||||
await expect(saveBtn).toBeVisible();
|
||||
const saveBox = await saveBtn.boundingBox();
|
||||
expect(saveBox).not.toBeNull();
|
||||
expect(saveBox.height).toBeGreaterThanOrEqual(MIN_TOUCH_TARGET);
|
||||
});
|
||||
|
||||
test('no horizontal overflow at 393px', async ({ page, viewport }) => {
|
||||
test.skip((viewport?.width ?? 0) > MOBILE_MAX_WIDTH, 'Mobile viewport required');
|
||||
await boot(page);
|
||||
|
||||
Reference in New Issue
Block a user