DUNGEONS-34: keep host screen awake while streaming
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
122
frontend/scripts/test-wake-lock.mjs
Normal file
122
frontend/scripts/test-wake-lock.mjs
Normal file
@@ -0,0 +1,122 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createScreenWakeLock } from '../utils/screenWakeLock.ts';
|
||||
|
||||
const settle = () => new Promise(resolve => setImmediate(resolve));
|
||||
class Lock extends EventTarget {
|
||||
released = false;
|
||||
async release() {
|
||||
this.released = true;
|
||||
this.dispatchEvent(new Event('release'));
|
||||
}
|
||||
}
|
||||
function fixture(request) {
|
||||
const locks = [];
|
||||
const state = { visible: true, status: undefined, calls: 0 };
|
||||
const controller = createScreenWakeLock({
|
||||
visible: () => state.visible,
|
||||
status: value => { state.status = value; },
|
||||
request: request === null ? undefined : async () => {
|
||||
state.calls++;
|
||||
if (request) return request();
|
||||
const lock = new Lock();
|
||||
locks.push(lock);
|
||||
return lock;
|
||||
},
|
||||
});
|
||||
return { controller, locks, state };
|
||||
}
|
||||
test('only holds a lock when enabled and hosting; stop releases it', async () => {
|
||||
const { controller, locks, state } = fixture();
|
||||
controller.update(false);
|
||||
assert.equal(state.calls, 0);
|
||||
controller.update(true);
|
||||
controller.refresh();
|
||||
await settle();
|
||||
assert.equal(state.calls, 1);
|
||||
assert.equal(state.status, 'active');
|
||||
controller.update(false);
|
||||
assert.equal(locks[0].released, true);
|
||||
assert.equal(state.status, 'off');
|
||||
});
|
||||
test('releases when hidden and reacquires on return while still hosting', async () => {
|
||||
const { controller, locks, state } = fixture();
|
||||
controller.update(true);
|
||||
await settle();
|
||||
state.visible = false;
|
||||
controller.refresh();
|
||||
assert.equal(locks[0].released, true);
|
||||
assert.equal(state.status, 'waiting');
|
||||
state.visible = true;
|
||||
controller.refresh();
|
||||
await settle();
|
||||
assert.equal(state.calls, 2);
|
||||
assert.equal(state.status, 'active');
|
||||
controller.dispose();
|
||||
assert.equal(locks[1].released, true);
|
||||
});
|
||||
for (const action of ['stop', 'dispose']) {
|
||||
test(`late acquisition is released after ${action}`, async () => {
|
||||
let resolve;
|
||||
const lock = new Lock();
|
||||
const { controller, state } = fixture(() => new Promise(done => { resolve = done; }));
|
||||
controller.update(true);
|
||||
if (action === 'stop') controller.update(false); else controller.dispose();
|
||||
resolve(lock);
|
||||
await settle();
|
||||
assert.equal(lock.released, true);
|
||||
assert.equal(state.calls, 1);
|
||||
assert.notEqual(state.status, 'active');
|
||||
});
|
||||
}
|
||||
test('off/on during acquisition discards stale lock and acquires only one new lock', async () => {
|
||||
const resolvers = [];
|
||||
const { controller, state } = fixture(() => new Promise(done => resolvers.push(done)));
|
||||
controller.update(true);
|
||||
controller.update(false);
|
||||
controller.update(true);
|
||||
const old = new Lock();
|
||||
resolvers.shift()(old);
|
||||
await settle();
|
||||
assert.equal(old.released, true);
|
||||
assert.equal(state.calls, 2);
|
||||
const current = new Lock();
|
||||
resolvers.shift()(current);
|
||||
await settle();
|
||||
assert.equal(state.status, 'active');
|
||||
controller.dispose();
|
||||
assert.equal(current.released, true);
|
||||
});
|
||||
test('denial leaves streaming alone and can be retried without an automatic loop', async () => {
|
||||
let denied = true;
|
||||
const { controller, state } = fixture(async () => {
|
||||
if (denied) throw new Error('NotAllowedError');
|
||||
return new Lock();
|
||||
});
|
||||
controller.update(true);
|
||||
await settle();
|
||||
assert.equal(state.status, 'unavailable');
|
||||
assert.equal(state.calls, 1);
|
||||
denied = false;
|
||||
controller.refresh();
|
||||
await settle();
|
||||
assert.equal(state.status, 'active');
|
||||
controller.dispose();
|
||||
});
|
||||
test('system revocation reports loss without repeatedly requesting another lock', async () => {
|
||||
const { controller, state, locks } = fixture();
|
||||
controller.update(true);
|
||||
await settle();
|
||||
await locks[0].release();
|
||||
await settle();
|
||||
assert.equal(state.status, 'unavailable');
|
||||
assert.equal(state.calls, 1);
|
||||
controller.dispose();
|
||||
});
|
||||
test('unsupported browser is reported without throwing', () => {
|
||||
const { controller, state } = fixture(null);
|
||||
controller.update(true);
|
||||
assert.equal(state.status, 'unsupported');
|
||||
controller.update(false);
|
||||
assert.equal(state.status, 'off');
|
||||
});
|
||||
Reference in New Issue
Block a user