123 lines
4.0 KiB
JavaScript
123 lines
4.0 KiB
JavaScript
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');
|
|
});
|