mirror of
https://github.com/novnc/noVNC.git
synced 2026-05-26 07:08:06 +00:00
Add tests for the wakelock feature.
Add tests to for both the `rfb` side (calling into the new wakelock code), and the new wakelock class (which tracks the desired state and how to get there).
This commit is contained in:
@@ -37,6 +37,7 @@ module.exports = (config) => {
|
|||||||
{ pattern: 'node_modules/sinon-chai/**', included: false },
|
{ pattern: 'node_modules/sinon-chai/**', included: false },
|
||||||
// modules to test
|
// modules to test
|
||||||
{ pattern: 'app/localization.js', included: false, type: 'module' },
|
{ pattern: 'app/localization.js', included: false, type: 'module' },
|
||||||
|
{ pattern: 'app/wakelock.js', included: false, type: 'module' },
|
||||||
{ pattern: 'app/webutil.js', included: false, type: 'module' },
|
{ pattern: 'app/webutil.js', included: false, type: 'module' },
|
||||||
{ pattern: 'core/**/*.js', included: false, type: 'module' },
|
{ pattern: 'core/**/*.js', included: false, type: 'module' },
|
||||||
{ pattern: 'vendor/pako/**/*.js', included: false, type: 'module' },
|
{ pattern: 'vendor/pako/**/*.js', included: false, type: 'module' },
|
||||||
|
|||||||
197
tests/test.wakelock.js
Normal file
197
tests/test.wakelock.js
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/* jshint expr: true */
|
||||||
|
|
||||||
|
import WakeLockManager from '../app/wakelock.js';
|
||||||
|
|
||||||
|
class FakeWakeLockSentinal extends EventTarget {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.released = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async release() {
|
||||||
|
if (this.released) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.released = true;
|
||||||
|
this.dispatchEvent(new Event("release"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForStateTransition(wakelockManager, newState) {
|
||||||
|
const {promise, resolve} = Promise.withResolvers();
|
||||||
|
|
||||||
|
const eventListener = (event) => {
|
||||||
|
if (event.newState !== newState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wakelockManager.removeEventListener("testOnlyStateChange", eventListener);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
wakelockManager.addEventListener("testOnlyStateChange", eventListener);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('WakeLockManager', function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let wakelockRequest;
|
||||||
|
beforeEach(function () {
|
||||||
|
wakelockRequest = sinon.stub(navigator.wakeLock, 'request');
|
||||||
|
});
|
||||||
|
afterEach(function () {
|
||||||
|
wakelockRequest.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can acquire and release lock', async function () {
|
||||||
|
let wakeLockSentinal = new FakeWakeLockSentinal();
|
||||||
|
wakelockRequest.onFirstCall().resolves(wakeLockSentinal);
|
||||||
|
|
||||||
|
let wlm = new WakeLockManager();
|
||||||
|
expect(wakelockRequest).to.not.have.been.called;
|
||||||
|
|
||||||
|
let done = waitForStateTransition(wlm, 'acquired');
|
||||||
|
wlm.acquire();
|
||||||
|
await done;
|
||||||
|
expect(wakelockRequest).to.have.been.calledOnce;
|
||||||
|
expect(wakeLockSentinal.released).to.be.false;
|
||||||
|
|
||||||
|
done = waitForStateTransition(wlm, 'released');
|
||||||
|
wlm.release();
|
||||||
|
await done;
|
||||||
|
expect(wakelockRequest).to.have.been.calledOnce;
|
||||||
|
expect(wakeLockSentinal.released).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can release without holding wakelock', async function () {
|
||||||
|
let wlm = new WakeLockManager();
|
||||||
|
wlm.release();
|
||||||
|
expect(wakelockRequest).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can release while waiting for wakelock', async function () {
|
||||||
|
let wakeLockSentinal = new FakeWakeLockSentinal();
|
||||||
|
let {promise, resolve} = Promise.withResolvers();
|
||||||
|
|
||||||
|
wakelockRequest.onFirstCall().returns(promise);
|
||||||
|
|
||||||
|
let wlm = new WakeLockManager();
|
||||||
|
expect(wakelockRequest).to.not.have.been.called;
|
||||||
|
|
||||||
|
let seenAcquiring = waitForStateTransition(wlm, 'acquiring');
|
||||||
|
let seenReleasing = waitForStateTransition(wlm, 'releasing');
|
||||||
|
let seenReleased = waitForStateTransition(wlm, 'released');
|
||||||
|
|
||||||
|
wlm.acquire();
|
||||||
|
await seenAcquiring;
|
||||||
|
expect(wakelockRequest).to.have.been.calledOnce;
|
||||||
|
|
||||||
|
// We can call acquire multiple times, while waiting for the promise
|
||||||
|
// to resolve.
|
||||||
|
wlm.acquire();
|
||||||
|
// It should not request a second wakelock.
|
||||||
|
expect(wakelockRequest).to.have.been.calledOnce;
|
||||||
|
|
||||||
|
wlm.release();
|
||||||
|
await seenReleasing;
|
||||||
|
|
||||||
|
expect(wakeLockSentinal.released).to.be.false;
|
||||||
|
|
||||||
|
// Now return the wake lock, we should immediately release it.
|
||||||
|
resolve(wakeLockSentinal);
|
||||||
|
await seenReleased;
|
||||||
|
expect(wakeLockSentinal.released).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles visibility loss', async function () {
|
||||||
|
let documentHidden = sinon.stub(document, 'hidden');
|
||||||
|
let documentVisibility = sinon.stub(document, 'visibilityState');
|
||||||
|
afterEach(function () {
|
||||||
|
documentHidden.restore();
|
||||||
|
documentVisibility.restore();
|
||||||
|
});
|
||||||
|
documentHidden.value(false);
|
||||||
|
documentVisibility.value('visible');
|
||||||
|
|
||||||
|
let wakeLockSentinal1 = new FakeWakeLockSentinal();
|
||||||
|
let wakeLockSentinal2 = new FakeWakeLockSentinal();
|
||||||
|
wakelockRequest.onFirstCall().resolves(wakeLockSentinal1);
|
||||||
|
wakelockRequest.onSecondCall().resolves(wakeLockSentinal2);
|
||||||
|
|
||||||
|
let wlm = new WakeLockManager();
|
||||||
|
let seenAcquired = waitForStateTransition(wlm, 'acquired');
|
||||||
|
let seenAwaitingVisible = waitForStateTransition(wlm, 'awaiting_visible');
|
||||||
|
|
||||||
|
wlm.acquire();
|
||||||
|
await seenAcquired;
|
||||||
|
expect(wakelockRequest).to.have.been.calledOnce;
|
||||||
|
|
||||||
|
// Fake a visibility change.
|
||||||
|
documentHidden.value(true);
|
||||||
|
documentVisibility.value('hidden');
|
||||||
|
wakeLockSentinal1.release();
|
||||||
|
|
||||||
|
await seenAwaitingVisible;
|
||||||
|
seenAcquired = waitForStateTransition(wlm, 'acquired');
|
||||||
|
|
||||||
|
// Fake a visibility change back
|
||||||
|
documentHidden.value(false);
|
||||||
|
documentVisibility.value('visible');
|
||||||
|
document.dispatchEvent(new Event('visibilitychange'));
|
||||||
|
await seenAcquired;
|
||||||
|
|
||||||
|
expect(wakelockRequest).to.have.been.calledTwice;
|
||||||
|
expect(wakeLockSentinal2.released).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can start hidden', async function () {
|
||||||
|
let documentHidden = sinon.stub(document, 'hidden');
|
||||||
|
let documentVisibility = sinon.stub(document, 'visibilityState');
|
||||||
|
afterEach(function () {
|
||||||
|
documentHidden.restore();
|
||||||
|
documentVisibility.restore();
|
||||||
|
});
|
||||||
|
documentHidden.value(true);
|
||||||
|
documentVisibility.value('hidden');
|
||||||
|
|
||||||
|
let wakeLockSentinal = new FakeWakeLockSentinal();
|
||||||
|
wakelockRequest.onFirstCall().resolves(wakeLockSentinal);
|
||||||
|
|
||||||
|
let wlm = new WakeLockManager();
|
||||||
|
let seenAwaitingVisible = waitForStateTransition(wlm, 'awaiting_visible');
|
||||||
|
let seenAcquired = waitForStateTransition(wlm, 'acquired');
|
||||||
|
|
||||||
|
wlm.acquire();
|
||||||
|
await seenAwaitingVisible;
|
||||||
|
expect(wakelockRequest).to.not.have.been.called;
|
||||||
|
|
||||||
|
// Fake a visibility change.
|
||||||
|
documentHidden.value(false);
|
||||||
|
documentVisibility.value('visible');
|
||||||
|
document.dispatchEvent(new Event('visibilitychange'));
|
||||||
|
await seenAcquired;
|
||||||
|
|
||||||
|
expect(wakelockRequest).to.have.been.calledOnce;
|
||||||
|
expect(wakeLockSentinal.released).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles acquire errors', async function () {
|
||||||
|
wakelockRequest.onFirstCall().rejects('WakeLockError');
|
||||||
|
let wakeLockSentinal = new FakeWakeLockSentinal();
|
||||||
|
wakelockRequest.onSecondCall().resolves(wakeLockSentinal);
|
||||||
|
|
||||||
|
let wlm = new WakeLockManager();
|
||||||
|
|
||||||
|
let seenError = waitForStateTransition(wlm, 'error');
|
||||||
|
wlm.acquire();
|
||||||
|
await seenError;
|
||||||
|
expect(wakelockRequest).to.have.been.calledOnce;
|
||||||
|
|
||||||
|
// Even though we saw an error previously, it will retry when
|
||||||
|
// requested.
|
||||||
|
let seenAcquired = waitForStateTransition(wlm, 'acquired');
|
||||||
|
wlm.acquire();
|
||||||
|
await seenAcquired;
|
||||||
|
expect(wakelockRequest).to.have.been.calledTwice;
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user