Files
OpenScript/tests/fetch.test.js

143 lines
4.4 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { runScriptFetch } from '../src/utils/fetch.js';
import { wrapScriptCode } from '../src/utils/userScripts.js';
test('runScriptFetch performs background fetch and serializes response', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url, options) => new Response(JSON.stringify({ hello: 'world' }), {
status: 200,
statusText: 'OK',
headers: { 'content-type': 'application/json', 'x-custom': 'val' },
});
try {
const result = await runScriptFetch('https://api.example.com/test', { method: 'GET' });
assert.equal(result.status, 200);
assert.equal(result.statusText, 'OK');
assert.ok(result.headers.some(([k, v]) => k === 'content-type' && v === 'application/json'));
assert.ok(result.body instanceof ArrayBuffer);
const decoded = JSON.parse(new TextDecoder().decode(result.body));
assert.deepEqual(decoded, { hello: 'world' });
} finally {
globalThis.fetch = originalFetch;
}
});
test('runScriptFetch handles null-body statuses', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => new Response(null, { status: 204, statusText: 'No Content' });
try {
const result = await runScriptFetch('https://api.example.com/empty');
assert.equal(result.status, 204);
assert.equal(result.body, null);
} finally {
globalThis.fetch = originalFetch;
}
});
test('runScriptFetch forwards errors on network failure', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => { throw new Error('Failed to fetch'); };
try {
await assert.rejects(() => runScriptFetch('https://broken.example.com'), /Failed to fetch/);
} finally {
globalThis.fetch = originalFetch;
}
});
test('OpenScript.fetch runtime wrapper reconstructs a native Response', async () => {
const originalChrome = globalThis.chrome;
const mockPayload = {
status: 200,
statusText: 'OK',
headers: [['content-type', 'application/json'], ['x-powered-by', 'openscript']],
url: 'https://api.example.com/redirected',
body: new TextEncoder().encode(JSON.stringify({ success: true })).buffer,
};
globalThis.chrome = {
runtime: {
sendMessage: async msg => {
if (msg.type === 'OPEN_SCRIPT_FETCH') {
assert.equal(msg.url, 'https://api.example.com/data');
assert.equal(msg.options.headers['authorization'], 'Bearer 123');
return { ok: true, ...mockPayload };
}
return { ok: false, error: 'unknown' };
},
},
};
let resolveDone;
const donePromise = new Promise(resolve => { resolveDone = resolve; });
globalThis.__resolve_done = resolveDone;
const scriptCode = `
const res = await OpenScript.fetch('https://api.example.com/data', {
headers: new Headers({ authorization: 'Bearer 123' }),
});
globalThis.__resolve_done({
ok: res.ok,
status: res.status,
statusText: res.statusText,
url: res.url,
header: res.headers.get('x-powered-by'),
data: await res.json(),
});
`;
try {
const wrapped = wrapScriptCode(scriptCode);
const fn = new Function(wrapped);
fn();
const result = await donePromise;
assert.deepEqual(result, {
ok: true,
status: 200,
statusText: 'OK',
url: 'https://api.example.com/redirected',
header: 'openscript',
data: { success: true },
});
} finally {
delete globalThis.__resolve_done;
globalThis.chrome = originalChrome;
}
});
test('OpenScript.fetch throws TypeError when request fails', async () => {
const originalChrome = globalThis.chrome;
globalThis.chrome = {
runtime: {
sendMessage: async () => ({ ok: false, error: 'Network error' }),
},
};
let resolveDone;
const donePromise = new Promise(resolve => { resolveDone = resolve; });
globalThis.__resolve_done = resolveDone;
const scriptCode = `
try {
await OpenScript.fetch('https://broken.example.com');
} catch (err) {
globalThis.__resolve_done({ name: err.name, message: err.message });
}
`;
try {
const wrapped = wrapScriptCode(scriptCode);
const fn = new Function(wrapped);
fn();
const err = await donePromise;
assert.equal(err.name, 'TypeError');
assert.equal(err.message, 'Network error');
} finally {
delete globalThis.__resolve_done;
globalThis.chrome = originalChrome;
}
});