73 lines
2.3 KiB
TypeScript
73 lines
2.3 KiB
TypeScript
import { afterEach, test } from 'node:test';
|
|||
|
|
import assert from 'node:assert/strict';
|
||
|
|
import { canCopyImage, copyImageFromUrl, toPngBlob } from './copyImage';
|
||
|
|
|
||
|
|
const g = globalThis as Record<string, unknown>;
|
||
|
|
const saved = {
|
||
|
|
ClipboardItem: Object.getOwnPropertyDescriptor(g, 'ClipboardItem'),
|
||
|
|
navigator: Object.getOwnPropertyDescriptor(g, 'navigator'),
|
||
|
|
fetch: Object.getOwnPropertyDescriptor(g, 'fetch'),
|
||
|
|
};
|
||
|
|
const stub = (key: keyof typeof saved, value: unknown) =>
|
||
|
|
Object.defineProperty(g, key, { value, configurable: true, writable: true });
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
(Object.keys(saved) as (keyof typeof saved)[]).forEach((key) => {
|
||
|
|
const desc = saved[key];
|
||
|
|
if (desc) Object.defineProperty(g, key, desc);
|
||
|
|
else delete g[key];
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
class FakeClipboardItem {
|
||
|
|
constructor(public data: Record<string, Promise<Blob>>) {}
|
||
|
|
}
|
||
|
|
|
||
|
|
test('canCopyImage is false without ClipboardItem', () => {
|
||
|
|
stub('ClipboardItem', undefined);
|
||
|
|
assert.equal(canCopyImage(), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('canCopyImage is true with ClipboardItem and clipboard.write', () => {
|
||
|
|
stub('ClipboardItem', FakeClipboardItem);
|
||
|
|
stub('navigator', { clipboard: { write: async () => undefined } });
|
||
|
|
assert.equal(canCopyImage(), true);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('toPngBlob passes a PNG through untouched', async () => {
|
||
|
|
const png = new Blob(['x'], { type: 'image/png' });
|
||
|
|
assert.equal(await toPngBlob(png), png);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('copyImageFromUrl writes a single image/png item', async () => {
|
||
|
|
const png = new Blob(['x'], { type: 'image/png' });
|
||
|
|
stub('fetch', async () => ({ ok: true, blob: async () => png }));
|
||
|
|
stub('ClipboardItem', FakeClipboardItem);
|
||
|
|
const written: FakeClipboardItem[][] = [];
|
||
|
|
stub('navigator', {
|
||
|
|
clipboard: {
|
||
|
|
write: async (items: FakeClipboardItem[]) => {
|
||
|
|
written.push(items);
|
||
|
|
},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
await copyImageFromUrl('blob:x');
|
||
|
|
assert.equal(written.length, 1);
|
||
|
|
assert.deepEqual(Object.keys(written[0][0].data), ['image/png']);
|
||
|
|
assert.equal(await written[0][0].data['image/png'], png);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('copyImageFromUrl rejects when the fetch fails', async () => {
|
||
|
|
stub('fetch', async () => ({ ok: false, status: 404 }));
|
||
|
|
stub('ClipboardItem', FakeClipboardItem);
|
||
|
|
stub('navigator', {
|
||
|
|
clipboard: {
|
||
|
|
write: async (items: FakeClipboardItem[]) => {
|
||
|
|
await items[0].data['image/png'];
|
||
|
|
},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
await assert.rejects(copyImageFromUrl('blob:x'), /404/);
|
||
|
|
});
|