fix: stabilize Playwright packets test with explicit time window (#348)

## Summary

Fixes the Playwright CI regression on master where the "Packets page
loads with filter" test times out after 15 seconds waiting for able
tbody tr to appear.

## Root Cause

Three packets tests used an bout:blank round-trip pattern to force a
full page reload:

`
page.goto(BASE) → set localStorage → page.goto('about:blank') →
page.goto(BASE/#/packets)
`

This cross-origin round-trip through bout:blank causes the SPA's config
fetch and router to not fire reliably in CI's headless Chromium, leaving
the page uninitialized past the 15-second timeout.

## Fix

Replace the bout:blank pattern with page.reload() in all three affected
tests:

`
page.goto(BASE/#/packets)  →  set localStorage  →  page.reload()
`

This stays on the same origin throughout. Playwright handles same-origin
reloads predictably — the page fully re-initializes, the IIFE re-reads
localStorage, and loadPackets() uses the correct time window.

## Tests affected

| Test | Change |
|------|--------|
| Packets page loads with filter | bout:blank → page.reload() |
| Packets initial fetch honors persisted time window | bout:blank →
page.reload() |
| Packets groupByHash toggle works | bout:blank → page.reload() |

## Validation

- All 318 unit tests pass (packet-filter: 62, aging: 29, frontend: 227)
- No public/ files changed — no cache buster needed
- Single file changed: est-e2e-playwright.js (9 insertions, 15
deletions)

Co-authored-by: Kpa-clawbot <259247574+Kpa-clawbot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Kpa-clawbot
2026-03-31 23:27:51 -07:00
committed by GitHub
co-authored by Kpa-clawbot Copilot
parent e2556eaaff
commit 8e6fc9602f
+9 -15
View File
@@ -365,13 +365,12 @@ async function run() {
await test('Packets page loads with filter', async () => {
// Ensure desktop viewport and broad time window so fixture timestamps are included.
await page.setViewportSize({ width: 1280, height: 720 });
await page.goto(BASE, { waitUntil: 'domcontentloaded' });
// Set time window BEFORE packets.js IIFE re-executes (525600 min ≈ 1 year)
// Set time window BEFORE packets.js IIFE re-executes (525600 min ≈ 1 year).
// Navigate to the packets URL then reload — avoids about:blank cross-origin issues
// that can prevent the SPA from fully initializing within the timeout.
await page.goto(`${BASE}/#/packets`, { waitUntil: 'domcontentloaded' });
await page.evaluate(() => localStorage.setItem('meshcore-time-window', '525600'));
// Navigate away so next goto is a full page load (not a same-document hash change).
// This guarantees scripts re-execute and packets.js IIFE reads the new localStorage.
await page.goto('about:blank');
await page.goto(`${BASE}/#/packets`, { waitUntil: 'load' });
await page.reload({ waitUntil: 'load' });
await page.waitForSelector('table tbody tr', { timeout: 15000 });
const rowsBefore = await page.$$('table tbody tr');
assert(rowsBefore.length > 0, 'No packets visible');
@@ -387,11 +386,8 @@ async function run() {
});
await test('Packets initial fetch honors persisted time window', async () => {
// Navigate to base first to get same-origin context for localStorage
await page.goto(BASE, { waitUntil: 'domcontentloaded' });
// Set persisted time window to 60 min and reload so the IIFE reads it
await page.evaluate(() => localStorage.setItem('meshcore-time-window', '60'));
// Navigate away so next goto is a full page load
await page.goto('about:blank');
const packetsRequestPromise = page.waitForRequest((req) => {
try {
@@ -402,8 +398,8 @@ async function run() {
}
}, { timeout: 10000 });
// Full navigation from about:blank — scripts re-execute, IIFE reads localStorage
await page.goto(`${BASE}/#/packets`, { waitUntil: 'load' });
// Full reload on the packets page — scripts re-execute, IIFE reads localStorage
await page.reload({ waitUntil: 'load' });
await page.waitForSelector('#fTimeWindow', { timeout: 10000 });
const timeWindowValue = await page.$eval('#fTimeWindow', (el) => el.value);
assert(timeWindowValue === '60', `Expected time window dropdown to restore 60, got ${timeWindowValue}`);
@@ -428,10 +424,8 @@ async function run() {
// Test: Packets groupByHash toggle changes view
await test('Packets groupByHash toggle works', async () => {
// Restore wide time window — previous test set it to 60 min which excludes fixture data
await page.goto(BASE, { waitUntil: 'domcontentloaded' });
await page.evaluate(() => localStorage.setItem('meshcore-time-window', '525600'));
await page.goto('about:blank');
await page.goto(`${BASE}/#/packets`, { waitUntil: 'load' });
await page.reload({ waitUntil: 'load' });
await page.waitForSelector('table tbody tr', { timeout: 15000 });
const groupBtn = await page.$('#fGroup');
assert(groupBtn, 'Group by hash button (#fGroup) not found');