Files
ObsiGate/tests/e2e/mobile-toolbar.spec.js
bruno d142049216
CI / lint (push) Successful in 1m59s
CI / security (push) Successful in 1m26s
CI / test (push) Successful in 3m41s
CI / build (push) Successful in 1m21s
CI / e2e (push) Successful in 14m0s
fix: degagement mobile sous la barre de navigation du bas (clearance retargetee .main-body) BUG-073
2026-09-23 23:36:35 -04:00

104 lines
3.9 KiB
JavaScript

/**
* E2E tests for the mobile bottom toolbar clearance (BUG-073).
*
* The fixed bottom bar (#mobile-toolbar, 64px + safe-area) used to cover the
* last pixels of every document/page: the clearance rule targeted the dead
* `.main-layout` selector instead of `.main-body`, so #content-area reached
* behind the bar and the end of the content was unreachable.
*
* 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 / config-mobile.spec.js.
*
* Run:
* npx playwright test tests/e2e/mobile-toolbar.spec.js --project=chromium-mobile
* pwsh scripts/run-e2e-local.ps1 --project=chromium-mobile -g "BUG-073"
* (ObsiGate listening on http://localhost:2029, auth disabled)
*/
import { test, expect } from '@playwright/test';
const MOBILE_MAX_WIDTH = 768;
const LONG_DOC = 'ANALYSE_REVIEW.md';
async function boot(page) {
await page.goto('/');
await page
.waitForSelector('#app:not(.hidden)', { timeout: 15000 })
.catch(() => {});
}
/** Wait for the async markdown render, then confirm the area actually scrolls. */
async function openLongDocument(page) {
await page.evaluate((p) => window.TabManager.open('TestVault', p), LONG_DOC);
await expect(page.locator('#content-area .md-content')).toBeAttached({ timeout: 15000 });
await expect
.poll(
() =>
page.evaluate(() => {
const area = document.getElementById('content-area');
return area.scrollHeight > area.clientHeight;
}),
{ timeout: 15000 },
)
.toBe(true);
}
/** Geometry of #content-area vs the fixed #mobile-toolbar bar. */
async function measure(page) {
return page.evaluate(() => {
const area = document.getElementById('content-area').getBoundingClientRect();
const bar = document.getElementById('mobile-toolbar').getBoundingClientRect();
return { areaBottom: area.bottom, barTop: bar.top, barVisible: bar.height > 0 };
});
}
test.describe('Mobile bottom toolbar clearance (BUG-073)', () => {
test('content area ends above the fixed bottom toolbar', async ({ page, viewport }) => {
test.skip((viewport?.width ?? 0) > MOBILE_MAX_WIDTH, 'Mobile viewport required');
await boot(page);
const toolbar = page.locator('#mobile-toolbar');
await expect(toolbar).toBeVisible();
// Open a long document so the layout is in its real document-view state.
await openLongDocument(page);
await expect(page.locator('#content-area')).toBeVisible();
// The scroll container itself must stop at (or above) the bar — 1px
// tolerance for subpixel rounding.
await expect
.poll(async () => {
const m = await measure(page);
return m.areaBottom - m.barTop;
})
.toBeLessThanOrEqual(1);
});
test('the end of a long document scrolls clear of the toolbar', async ({ page, viewport }) => {
test.skip((viewport?.width ?? 0) > MOBILE_MAX_WIDTH, 'Mobile viewport required');
await boot(page);
await openLongDocument(page);
// Scroll to the very end: the last rendered element must sit above the bar.
await page.evaluate(() => {
const area = document.getElementById('content-area');
area.scrollTop = area.scrollHeight;
});
const result = await page.evaluate(() => {
const area = document.getElementById('content-area');
const barTop = document.getElementById('mobile-toolbar').getBoundingClientRect().top;
// Last element of the rendered document (markdown root or content child).
const root = area.querySelector('.md-content') || area.lastElementChild;
let last = root;
if (root && root.lastElementChild) last = root.lastElementChild;
const lastBottom = last ? last.getBoundingClientRect().bottom : area.getBoundingClientRect().bottom;
return { lastBottom, barTop };
});
expect(result.lastBottom).toBeLessThanOrEqual(result.barTop + 1);
});
});