Files
pulse/scripts/check-browser-lifecycle-control.mjs
T
pulse-triage[bot] 4caca9c12e test(web): retain failing browser suspension control diagnostic
The previous fresh-session focus intervention did not suspend timers. Preserve a bounded true-to-false comparison and its adverse result so acknowledged CDP commands cannot be mistaken for lifecycle or Pulse recovery proof. This diagnostic is deliberately outside CI and release qualification.

Change-source: pulse-maintainer
2026-09-08 07:00:33 +01:00

62 lines
2.9 KiB
JavaScript

// Diagnostic only: proves a blank-page suspension control, not Pulse recovery.
// Run through pulse-heavy-run -- node scripts/check-browser-lifecycle-control.mjs
import assert from 'node:assert/strict';
import { createRequire } from 'node:module';
import { chromium } from '@playwright/test';
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const browser = await chromium.launch({ headless: true });
try {
const require = createRequire(import.meta.url);
console.log(JSON.stringify({ browser: browser.version(),
playwright: require('@playwright/test/package.json').version,
node: process.version, platform: process.platform, arch: process.arch }));
const results = [];
// Preselected comparison; independent contexts prevent carry-over.
for (const transition of [false, true]) {
const context = await browser.newContext();
try {
const page = await context.newPage();
await page.evaluate(() => {
window.probe = { ticks: 0, events: [] };
setInterval(() => window.probe.ticks++, 50);
for (const type of ['freeze', 'resume', 'visibilitychange']) {
document.addEventListener(type, () => window.probe.events.push({
type, ticks: window.probe.ticks, visibility: document.visibilityState,
}));
}
});
const session = await context.newCDPSession(page);
const commands = [];
const send = async (method, params) => {
commands.push({ method, params, response: await session.send(method, params) });
};
if (transition) await send('Emulation.setFocusEmulationEnabled', { enabled: true });
await send('Emulation.setFocusEmulationEnabled', { enabled: false });
await wait(250);
const before = await page.evaluate(() => ({ ...window.probe,
visibility: document.visibilityState, focus: document.hasFocus() }));
await send('Page.setWebLifecycleState', { state: 'frozen' });
// Do not evaluate the page while frozen. Wait on the host instead.
await wait(2100);
await send('Page.setWebLifecycleState', { state: 'active' });
await wait(250);
const after = await page.evaluate(() => ({ ...window.probe,
visibility: document.visibilityState, focus: document.hasFocus() }));
const freeze = after.events.find((event) => event.type === 'freeze');
const resume = after.events.find((event) => event.type === 'resume');
const valid = Boolean(freeze && resume && freeze.ticks === resume.ticks &&
after.events.indexOf(freeze) < after.events.indexOf(resume) &&
after.ticks > resume.ticks);
const result = { transition, before, after, commands, valid };
results.push(result);
console.log(JSON.stringify(result));
} finally {
await context.close();
}
}
assert.ok(results[1].valid, 'true-to-false intervention did not establish suspension');
} finally {
await browser.close();
}