test(e2e): check the playback display lock is released while hidden

Review follow-ups for #1724:

- Add an E2E that plays the webm fixture in the unautomated launch,
  records the main process's prevent-display-sleep blockers, and asserts
  the keep-awake lock is taken while visible, released when the window is
  hidden, and taken again when it is shown. The visibility tests alone
  would still pass if the renderer gate or the bridge stopped updating
  powerSaveBlocker.
- Validate CDP replies before dispatch (CodeQL
  js/unvalidated-dynamic-method-call): only a numeric id with a pending
  settle function is called.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-09-29 20:48:56 +02:00
1 parent 560c2c2a4b
commit c980ced90a
2 files changed
+64 -3

No files matched your search

@@ -55,9 +55,18 @@ async function openCdpSocket(url: string): Promise<CdpSocket> {
);
});
socket.addEventListener('message', (event) => {
const message = JSON.parse(String(event.data));
pending.get(message.id)?.(message);
pending.delete(message.id);
const message = JSON.parse(String(event.data)) as Record<
string,
unknown
>;
// Only replies to our own numbered requests settle a promise; events
// and unknown ids are ignored.
const id = message['id'];
if (typeof id !== 'number') return;
const settle = pending.get(id);
if (typeof settle !== 'function') return;
pending.delete(id);
settle(message);
});
return {
send: (method, params = {}) =>
@@ -1,3 +1,5 @@
import { join } from 'node:path';
import { pathToFileURL } from 'node:url';
import { expect, test } from './electron-test-fixtures';
import {
launchUnautomatedElectronApp,
@@ -9,6 +11,10 @@ import {
const isWindowManagerlessCi =
process.platform === 'linux' && !!process.env['CI'];
const videoFixtureUrl = pathToFileURL(
join(__dirname, '../../web-e2e/src/fixtures/playback/episode.webm')
).href;
const visibility = (app: UnautomatedElectronApp) =>
app.evaluateInPage<string>('document.visibilityState');
@@ -92,4 +98,50 @@ test.describe('Main window visibility', () => {
await app.close();
}
});
test('@electron releases the playback display lock while the window is hidden', async ({
dataDir,
}) => {
const app = await launchUnautomatedElectronApp(dataDir);
try {
await waitUntilShown(app);
// Record the display-sleep blockers the keep-awake service holds.
await app.evaluateInMain(`
const blocker = electron.powerSaveBlocker;
const active = (globalThis.__e2eDisplayBlockers = new Set());
const start = blocker.start.bind(blocker);
const stop = blocker.stop.bind(blocker);
blocker.start = (type) => {
const id = start(type);
if (type === 'prevent-display-sleep') active.add(id);
return id;
};
blocker.stop = (id) => {
active.delete(id);
return stop(id);
};
`);
const heldBlockers = () =>
app.evaluateInMain<number>(
'return globalThis.__e2eDisplayBlockers.size;'
);
await app.evaluateInPage(`(() => {
const video = document.createElement('video');
video.muted = true;
video.loop = true;
video.src = ${JSON.stringify(videoFixtureUrl)};
document.body.append(video);
return video.play().then(() => true);
})()`);
await expect.poll(heldBlockers, { timeout: 10_000 }).toBe(1);
await setWindowState(app, 'hide');
await expect.poll(heldBlockers, { timeout: 10_000 }).toBe(0);
await setWindowState(app, 'show');
await expect.poll(heldBlockers, { timeout: 10_000 }).toBe(1);
} finally {
await app.close();
}
});
});