mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-06-10 06:21:41 +00:00
Compare commits
2 Commits
master
...
fix/issue-1343
| Author | SHA1 | Date | |
|---|---|---|---|
| db85e59fe2 | |||
| 92165c13e5 |
@@ -251,6 +251,7 @@ jobs:
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-nav-fluid-1055-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-nav-priority-1102-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-nav-priority-1311-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-nav-stats-1343-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-nav-more-floor-1139-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-bottom-nav-1061-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-gestures-1062-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
|
||||
+5
-1
@@ -1633,8 +1633,12 @@ button.ch-item:hover .ch-icon-btn { opacity: 1; }
|
||||
|
||||
/* === Responsive — Tablet (≤900px) === */
|
||||
@media (max-width: 900px) {
|
||||
/* nav-stats hidden in the (min-width:768) and (max-width:1100) band
|
||||
below — see #1343. Keeping the rule here too is harmless but
|
||||
misleading: it implies 900px is the breakpoint when in reality
|
||||
the JS applyNavPriority assumes (and the 1100px block enforces)
|
||||
the hide-band extends up to 1100px. */
|
||||
.panel-right { width: 320px; min-width: 320px; }
|
||||
.nav-stats { display: none; }
|
||||
.brand-logo { height: 32px; width: 112px; }
|
||||
.nav-link { padding: 14px 8px; font-size: 13px; }
|
||||
.map-controls { width: 180px; font-size: 12px; }
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env node
|
||||
/* Issue #1343 — nav-stats hide-band must match JS overflow assumption.
|
||||
*
|
||||
* applyNavPriority in public/app.js assumes that at viewport <=1100px
|
||||
* the CSS hides .nav-stats so the 5 high-priority links + "More ▾"
|
||||
* actually fit on screen. If the hide band is narrower than 1100px,
|
||||
* the high-priority links silently clip out of view in the gap.
|
||||
*
|
||||
* Cases:
|
||||
* - 800x800 on /#/observers → high-priority links visible, nav-stats hidden
|
||||
* - 960x800 on /#/observers → high-priority links visible, nav-stats hidden
|
||||
* - 1080x800 on /#/observers → high-priority links visible, nav-stats hidden
|
||||
* - 1200x800 on /#/observers → high-priority links visible, nav-stats RE-APPEARS
|
||||
*
|
||||
* A link is "visible" iff: clientWidth > 0 AND its bounding rect is
|
||||
* fully inside the viewport horizontally (left>=0, right<=innerWidth).
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
const BASE = process.env.BASE_URL || 'http://localhost:13581';
|
||||
const HIGH_PRIORITY_HREFS = ['#/home', '#/packets', '#/map', '#/live', '#/nodes'];
|
||||
|
||||
const CASES = [
|
||||
{ w: 800, h: 800, navStatsHidden: true, label: '800px — narrow desktop' },
|
||||
{ w: 960, h: 800, navStatsHidden: true, label: '960px — operator-reported' },
|
||||
{ w: 1080, h: 800, navStatsHidden: true, label: '1080px — narrow desktop' },
|
||||
{ w: 1200, h: 800, navStatsHidden: false, label: '1200px — wide desktop' },
|
||||
];
|
||||
|
||||
async function main() {
|
||||
let browser;
|
||||
let failures = 0;
|
||||
try {
|
||||
browser = await chromium.launch({
|
||||
headless: true,
|
||||
executablePath: process.env.CHROMIUM_PATH || undefined,
|
||||
args: ['--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'],
|
||||
});
|
||||
for (const c of CASES) {
|
||||
const ctx = await browser.newContext({ viewport: { width: c.w, height: c.h } });
|
||||
const page = await ctx.newPage();
|
||||
await page.goto(`${BASE}/#/observers`, { waitUntil: 'domcontentloaded', timeout: 15000 });
|
||||
// Wait for nav to be rendered (top-nav appears as part of SPA shell)
|
||||
await page.waitForSelector('.top-nav .nav-links', { timeout: 10000 });
|
||||
// Allow nav-priority pass + font ready callback to settle
|
||||
await page.waitForTimeout(400);
|
||||
|
||||
const result = await page.evaluate((hrefs) => {
|
||||
const navStats = document.querySelector('.nav-stats');
|
||||
const navStatsW = navStats ? navStats.clientWidth : 0;
|
||||
const innerW = window.innerWidth;
|
||||
const links = hrefs.map((href) => {
|
||||
const a = document.querySelector(`.nav-links a[href="${href}"]`);
|
||||
if (!a) return { href, present: false, w: 0, left: null, right: null };
|
||||
const r = a.getBoundingClientRect();
|
||||
return {
|
||||
href,
|
||||
present: true,
|
||||
w: a.clientWidth,
|
||||
left: r.left,
|
||||
right: r.right,
|
||||
inView: r.left >= 0 && r.right <= innerW && a.clientWidth > 0,
|
||||
};
|
||||
});
|
||||
return { navStatsW, innerW, links };
|
||||
}, HIGH_PRIORITY_HREFS);
|
||||
|
||||
const navStatsOk = c.navStatsHidden
|
||||
? result.navStatsW === 0
|
||||
: result.navStatsW > 0;
|
||||
const allLinksVisible = result.links.every((l) => l.present && l.inView);
|
||||
|
||||
const status = navStatsOk && allLinksVisible ? 'PASS' : 'FAIL';
|
||||
if (status === 'FAIL') failures++;
|
||||
console.log(`[${status}] ${c.label} — innerW=${result.innerW} navStatsW=${result.navStatsW}`);
|
||||
for (const l of result.links) {
|
||||
console.log(` ${l.href}: w=${l.w} left=${l.left} right=${l.right} inView=${l.inView}`);
|
||||
}
|
||||
// Hard assertion so CI failure carries an explicit error trace
|
||||
try {
|
||||
assert.strictEqual(navStatsOk, true,
|
||||
`${c.label}: expected nav-stats ${c.navStatsHidden ? 'hidden (clientWidth=0)' : 'visible (clientWidth>0)'}, got clientWidth=${result.navStatsW}`);
|
||||
assert.strictEqual(allLinksVisible, true,
|
||||
`${c.label}: expected all 5 high-priority links visible in viewport, got ${result.links.filter(l => !l.inView).map(l => l.href).join(',')} clipped`);
|
||||
} catch (err) {
|
||||
console.error(` ASSERT: ${err.message}`);
|
||||
}
|
||||
await ctx.close();
|
||||
}
|
||||
} finally {
|
||||
if (browser) await browser.close();
|
||||
}
|
||||
// Final assertion — fail the process loudly with a stack
|
||||
assert.strictEqual(failures, 0, `${failures} viewport case(s) failed`);
|
||||
console.log('\nAll viewport cases passed');
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user