mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
test(web): retain failed foreground activation control
A successful lifecycle resume leaves the diagnostic target hidden. Add an opt-in tab activation observation with explicit visibility and focus assertions so it cannot be mistaken for foreground convergence. Preserve both failed runs and the short timer-sampling limitation; no application or release qualification is claimed. Change-source: pulse-maintainer
This commit is contained in:
@@ -60,3 +60,40 @@ a Playwright page attachment may reintroduce the confounder. Before testing
|
||||
foreground convergence, separately observe return to visible. Installed acceptance
|
||||
still requires the authorised synthetic installation and exact byte identities
|
||||
listed in `alert-recovery-acceptance.md`; neither is supplied by this control.
|
||||
|
||||
## Foreground activation control — 8 September 2026
|
||||
|
||||
`pulse-heavy-run -- node scripts/check-browser-single-session-control.mjs --foreground`
|
||||
adds `Page.bringToFront` after the separate post-resume snapshot, then takes a
|
||||
foreground snapshot after 250ms. Default invocation retains the original
|
||||
freeze/resume-only behaviour. The optional mode requires visible **and** focused
|
||||
state plus timer progress; it does not force focus emulation back on to obtain a
|
||||
passing result. No Playwright page is attached.
|
||||
|
||||
Fresh [CDP documentation](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-bringToFront)
|
||||
describes tab activation separately from lifecycle state. The command's success
|
||||
is not evidence of visibility restoration. On the same Chrome revision and
|
||||
runtime listed above, both the initial implementation and the final optional-mode
|
||||
run exited 1:
|
||||
|
||||
- Forced-focus negative: ticks 5 → 52 → 57; visible/focused throughout, no events.
|
||||
- Unforced positive: freeze and resume at tick 5, hidden/unfocused after resume;
|
||||
after activation, **hidden/focused**, without a visible visibilitychange event.
|
||||
- The first run stayed at tick 5 through the foreground sample; the optional-mode
|
||||
run reached tick 6 only at that final sample. Both failed the earlier
|
||||
post-resume timer-progress assertion before reaching the foreground assertion.
|
||||
|
||||
The 250ms post-resume sample is therefore not a dependable timer-progress bound
|
||||
for this hidden target. Do not interpret that failed assertion as missing resume:
|
||||
ordered freeze/resume events were recorded. Independently, visibility restoration
|
||||
failed in both observed foreground samples. Neither threshold was relaxed and
|
||||
neither failure is cleared by the earlier successful freeze-only control.
|
||||
|
||||
No Pulse fixture was exercised: the prerequisite foreground control is still
|
||||
unestablished. Before applying this arrangement to application convergence,
|
||||
choose and verify an actual visibility transition (potentially a headed browser
|
||||
with owned window activation), retaining the suspension probe and all failed
|
||||
observations. Repeating this activation unchanged, synthetically dispatching a
|
||||
visibility event, or enabling forced focus would not resolve the evidence gap.
|
||||
This diagnostic is not a release gate and proves nothing about installed
|
||||
incident state or destination receipt.
|
||||
|
||||
@@ -6,6 +6,7 @@ import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createRequire } from 'node:module';
|
||||
import { chromium } from '@playwright/test';
|
||||
const checkForeground = process.argv.includes('--foreground');
|
||||
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
const profile = await mkdtemp(join(tmpdir(), 'pulse-lifecycle-'));
|
||||
const child = spawn(chromium.executablePath(), ['--headless', '--no-sandbox',
|
||||
@@ -83,13 +84,26 @@ try {
|
||||
const resume = after.events.find(e => e.type === 'resume');
|
||||
const suspended = Boolean(freeze && resume && freeze.ticks === resume.ticks &&
|
||||
after.events.indexOf(freeze) < after.events.indexOf(resume) && after.ticks > resume.ticks);
|
||||
const result = { focusEnabled, before, after, commands, suspended };
|
||||
// Resume is not foreground activation. Observe the two transitions separately.
|
||||
let foreground;
|
||||
if (checkForeground) {
|
||||
await command('Page.bringToFront', {});
|
||||
await wait(250);
|
||||
foreground = await evaluate(snapshot);
|
||||
}
|
||||
const result = { focusEnabled, before, after, foreground, commands, suspended };
|
||||
results.push(result); console.log(JSON.stringify(result));
|
||||
} finally { await send('Target.closeTarget', { targetId }); }
|
||||
}
|
||||
assert.ok(!results[0].suspended && results[0].after.ticks - results[0].before.ticks >= 20,
|
||||
'Negative control must continue ticking');
|
||||
assert.ok(results[1].suspended, 'Positive control must suspend and resume timers');
|
||||
if (checkForeground) {
|
||||
assert.ok(results[1].foreground.visibility === 'visible' && results[1].foreground.focus,
|
||||
'Positive control must return to visible and focused after tab activation');
|
||||
assert.ok(results[1].foreground.ticks > results[1].after.ticks,
|
||||
'Foreground timer must continue advancing');
|
||||
}
|
||||
} finally {
|
||||
socket?.close();
|
||||
const exited = new Promise(resolve => child.once('exit', resolve));
|
||||
|
||||
Reference in New Issue
Block a user