mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-10-08 06:37:34 +00:00
Moves 290 root test-*.js into tests/unit (177, listed in test-all.sh) and tests/e2e (113, classified in scripts/non-unit-tests.json), per #1981 and PR-D of #1385. Root goes from 348 entries to 48. test-all.sh and test-fixtures/ stay put. The inventory guard now fails if a test reappears in the root or sits in the wrong folder.
Verified independently of the diff: the invoked sets are unchanged (test-all.sh 177 before and after, deploy.yml 96 before and after, both identical as sets), and a full local run of test-all.sh on master and on the branch produced 4702 output lines each whose only differences are absolute paths, stack-trace line numbers shifted by the REPO_ROOT line, the inventory wording and two perf ratios. The guard was mutation-checked: a test back in the root, a unit suite in tests/e2e, and a suite dropped from test-all.sh each make it exit 1. CI run 35246304316 ran 97 suites from tests/e2e and is green.
Follow-up 9335c51d finished the instruction files: no bare root test command is left in AGENTS.md, the squad charters, .github or docs, and every tests/ path they name resolves.
Merged by the interim maintainer without a second human reviewer: CI and the local runs above are the independent checks.
Known and deliberately out of scope: 18 of the 113 files in tests/e2e are invoked by no runner at all, and one of them cannot run anywhere because it requires jsdom, which is not a declared dependency. Tracked separately.
124 lines
5.2 KiB
JavaScript
124 lines
5.2 KiB
JavaScript
/**
|
|
* E2E (#1236): Map page mobile layout.
|
|
*
|
|
* At 375x800 viewport the /#/map page must:
|
|
* - Collapsed map controls: leaflet map canvas width must equal the viewport
|
|
* width (within 1px tolerance). No silent gutter on the right.
|
|
* - Expanded map controls: the panel must either fit within viewport OR
|
|
* have a sticky element at the top of the scroll container AND
|
|
* `overflow-y: auto` so the scroll affordance is real.
|
|
*
|
|
* Desktop guard (≥768px): map controls panel layout must remain absolute
|
|
* (position: absolute), not stretched full width.
|
|
*
|
|
* Run: BASE_URL=http://localhost:13581 node test-issue-1236-map-mobile-e2e.js
|
|
*/
|
|
'use strict';
|
|
const { chromium } = require('playwright');
|
|
|
|
const BASE = process.env.BASE_URL || 'http://localhost:13581';
|
|
|
|
let passed = 0, failed = 0;
|
|
async function step(name, fn) {
|
|
try { await fn(); passed++; console.log(' \u2713 ' + name); }
|
|
catch (e) { failed++; console.error(' \u2717 ' + name + ': ' + e.message); }
|
|
}
|
|
function assert(c, m) { if (!c) throw new Error(m || 'assertion failed'); }
|
|
|
|
async function run() {
|
|
const launchOpts = { args: ['--no-sandbox'] };
|
|
if (process.env.CHROMIUM_PATH) launchOpts.executablePath = process.env.CHROMIUM_PATH;
|
|
const browser = await chromium.launch(launchOpts);
|
|
|
|
// === Mobile: 375x800 ===
|
|
const ctx = await browser.newContext({ viewport: { width: 375, height: 800 } });
|
|
const page = await ctx.newPage();
|
|
|
|
await page.goto(BASE + '/#/map', { waitUntil: 'load', timeout: 60000 });
|
|
await page.waitForSelector('#leaflet-map', { timeout: 10000 });
|
|
await page.waitForSelector('#mapControls', { state: 'attached', timeout: 10000 });
|
|
await page.waitForTimeout(500);
|
|
|
|
await step('mobile collapsed: leaflet-map width fills viewport (no right gutter)', async () => {
|
|
// Ensure controls panel is collapsed (default on mobile per map.js)
|
|
const data = await page.evaluate(() => {
|
|
const panel = document.getElementById('mapControls');
|
|
const btn = document.getElementById('mapControlsToggle');
|
|
if (panel && !panel.classList.contains('collapsed')) btn && btn.click();
|
|
const lm = document.getElementById('leaflet-map');
|
|
return {
|
|
mapW: lm ? Math.round(lm.getBoundingClientRect().width) : null,
|
|
mapLeft: lm ? Math.round(lm.getBoundingClientRect().left) : null,
|
|
vw: window.innerWidth,
|
|
};
|
|
});
|
|
assert(data.mapW !== null, 'leaflet-map not found');
|
|
// Map must start at left edge and span to right edge (allow 1px rounding).
|
|
assert(data.mapLeft <= 1,
|
|
'leaflet-map must start at viewport left, got left=' + data.mapLeft);
|
|
assert(data.mapW >= data.vw - 1,
|
|
'leaflet-map width must equal viewport (' + data.vw + 'px), got ' + data.mapW + 'px');
|
|
});
|
|
|
|
await step('mobile expanded: panel has sticky header AND overflow-y auto', async () => {
|
|
const data = await page.evaluate(() => {
|
|
const panel = document.getElementById('mapControls');
|
|
const btn = document.getElementById('mapControlsToggle');
|
|
if (panel.classList.contains('collapsed')) btn && btn.click();
|
|
const cs = getComputedStyle(panel);
|
|
const h3 = panel.querySelector('h3');
|
|
const hcs = h3 ? getComputedStyle(h3) : null;
|
|
return {
|
|
overflowY: cs.overflowY,
|
|
h3Position: hcs ? hcs.position : null,
|
|
scrollGutter: cs.scrollbarGutter || '',
|
|
scrollH: panel.scrollHeight,
|
|
clientH: panel.clientHeight,
|
|
isScrollable: panel.scrollHeight > panel.clientHeight + 1,
|
|
};
|
|
});
|
|
// Require explicit sticky header + scrollable overflow regardless of
|
|
// whether content currently overflows (so future content additions are
|
|
// covered too).
|
|
assert(data.h3Position === 'sticky',
|
|
'panel h3 must be position:sticky (scroll affordance), got ' + data.h3Position);
|
|
assert(data.overflowY === 'auto' || data.overflowY === 'scroll',
|
|
'panel overflow-y must be auto/scroll, got ' + data.overflowY);
|
|
});
|
|
|
|
await ctx.close();
|
|
|
|
// === Desktop: 1280x800 — guard against regression ===
|
|
const ctx2 = await browser.newContext({ viewport: { width: 1280, height: 800 } });
|
|
const p2 = await ctx2.newPage();
|
|
await p2.goto(BASE + '/#/map', { waitUntil: 'load', timeout: 60000 });
|
|
await p2.waitForSelector('#mapControls', { state: 'attached', timeout: 10000 });
|
|
await p2.waitForTimeout(300);
|
|
|
|
await step('desktop (1280px): map controls panel position is absolute', async () => {
|
|
const data = await p2.evaluate(() => {
|
|
const panel = document.getElementById('mapControls');
|
|
const cs = getComputedStyle(panel);
|
|
const rect = panel.getBoundingClientRect();
|
|
return {
|
|
position: cs.position,
|
|
width: Math.round(rect.width),
|
|
vw: window.innerWidth,
|
|
};
|
|
});
|
|
assert(data.position === 'absolute',
|
|
'desktop panel must be position:absolute, got ' + data.position);
|
|
// Should be modest width (not full viewport)
|
|
assert(data.width < data.vw * 0.5,
|
|
'desktop panel must be <50% viewport width, got ' + data.width + '/' + data.vw);
|
|
});
|
|
|
|
await browser.close();
|
|
|
|
console.log('\n' + passed + '/' + (passed + failed) + ' tests passed' +
|
|
(failed ? ', ' + failed + ' failed' : ''));
|
|
process.exit(failed > 0 ? 1 : 0);
|
|
}
|
|
|
|
run().catch(err => { console.error('Fatal:', err); process.exit(1); });
|