Files
noVNC/tests/test.clipboard.js
Tobias f5a4eedcea Add permissions-exclusive async clipboard
Clipboard permissions must be supported, with states "granted" or
"prompt" for both write and read.
2025-10-21 16:21:55 +02:00

122 lines
3.5 KiB
JavaScript

import AsyncClipboard from '../core/clipboard.js';
describe('Async Clipboard', function () {
"use strict";
let targetMock;
let clipboard;
beforeEach(function () {
sinon.stub(navigator, "clipboard").value({
writeText: sinon.stub().resolves(),
readText: sinon.stub().resolves(),
});
sinon.stub(navigator, "permissions").value({
query: sinon.stub(),
});
targetMock = document.createElement("canvas");
clipboard = new AsyncClipboard(targetMock);
});
afterEach(function () {
sinon.restore();
targetMock = null;
clipboard = null;
});
function stubClipboardPermissions(state) {
navigator.permissions.query
.withArgs({ name: 'clipboard-write', allowWithoutGesture: true })
.resolves({ state: state });
navigator.permissions.query
.withArgs({ name: 'clipboard-read', allowWithoutGesture: false })
.resolves({ state: state });
}
function nextTick() {
return new Promise(resolve => setTimeout(resolve, 0));
}
it('grab() adds listener if permissions granted', async function () {
stubClipboardPermissions('granted');
const addListenerSpy = sinon.spy(targetMock, 'addEventListener');
clipboard.grab();
await nextTick();
expect(addListenerSpy.calledWith('focus')).to.be.true;
});
it('grab() does not add listener if permissions denied', async function () {
stubClipboardPermissions('denied');
const addListenerSpy = sinon.spy(targetMock, 'addEventListener');
clipboard.grab();
await nextTick();
expect(addListenerSpy.calledWith('focus')).to.be.false;
});
it('focus event triggers onpaste() if permissions granted', async function () {
stubClipboardPermissions('granted');
const text = 'hello clipboard world';
navigator.clipboard.readText.resolves(text);
const spyPromise = new Promise(resolve => clipboard.onpaste = resolve);
clipboard.grab();
await nextTick();
targetMock.dispatchEvent(new Event('focus'));
const res = await spyPromise;
expect(res).to.equal(text);
});
it('focus event does not trigger onpaste() if permissions denied', async function () {
stubClipboardPermissions('denied');
const text = 'should not read';
navigator.clipboard.readText.resolves(text);
clipboard.onpaste = sinon.spy();
clipboard.grab();
await nextTick();
targetMock.dispatchEvent(new Event('focus'));
expect(clipboard.onpaste.called).to.be.false;
});
it('writeClipboard() calls navigator.clipboard.writeText() if permissions granted', async function () {
stubClipboardPermissions('granted');
clipboard._isAvailable = true;
const text = 'writing to clipboard';
const result = clipboard.writeClipboard(text);
expect(navigator.clipboard.writeText.calledWith(text)).to.be.true;
expect(result).to.be.true;
});
it('writeClipboard() does not call navigator.clipboard.writeText() if permissions denied', async function () {
stubClipboardPermissions('denied');
clipboard._isAvailable = false;
const text = 'should not write';
const result = clipboard.writeClipboard(text);
expect(navigator.clipboard.writeText.called).to.be.false;
expect(result).to.be.false;
});
});