Bound upstream and screenshot requests with network deadlines

This commit is contained in:
Matt Isenhower
2026-09-07 12:58:15 -07:00
parent 8a38942e3d
commit a0badb5f39
6 changed files with 71 additions and 8 deletions

45
test/fetch.test.js Normal file
View File

@@ -0,0 +1,45 @@
import { test, mock } from 'node:test';
import assert from 'node:assert/strict';
import { setTimeout as sleep } from 'node:timers/promises';
import { fetchWithTimeout } from '../src/common/fetch.js';
test('aborts a stalled request at its deadline', async () => {
mock.method(globalThis, 'fetch', (input, { signal }) => new Promise((resolve, reject) => {
signal.addEventListener('abort', () => reject(signal.reason), { once: true });
}));
try {
await Promise.all([
assert.rejects(fetchWithTimeout('https://example.test', {}, 5), { name: 'TimeoutError' }),
sleep(20),
]);
} finally {
mock.restoreAll();
}
});
test('keeps the deadline active while reading the response body', async () => {
mock.method(globalThis, 'fetch', async (input, { signal }) => new Response(new ReadableStream({
start(controller) {
signal.addEventListener('abort', () => controller.error(signal.reason), { once: true });
},
})));
try {
const response = await fetchWithTimeout('https://example.test', {}, 5);
await Promise.all([assert.rejects(response.text(), { name: 'TimeoutError' }), sleep(20)]);
} finally {
mock.restoreAll();
}
});
test('preserves caller cancellation', async () => {
let signal;
mock.method(globalThis, 'fetch', async (input, init) => { signal = init.signal; return new Response('ok'); });
try {
const controller = new AbortController;
await fetchWithTimeout('https://example.test', { signal: controller.signal });
controller.abort();
assert.equal(signal.aborted, true);
} finally {
mock.restoreAll();
}
});

View File

@@ -30,8 +30,10 @@ test('asks Browser Rendering for the deployed screenshot page at the default vie
assert.equal(headers.get('authorization'), 'Bearer token');
assert.equal(body.url, 'https://example.test/screenshots.html#/schedules/3600');
assert.deepEqual(body.viewport, { width: 1216, height: 684, deviceScaleFactor: 2 });
assert.deepEqual(body.gotoOptions, { waitUntil: 'networkidle0' });
assert.deepEqual(body.gotoOptions, { waitUntil: 'networkidle0', timeout: 30_000 });
assert.deepEqual(body.screenshotOptions, { type: 'png' });
assert.equal(body.actionTimeout, 30_000);
assert.deepEqual(body.setExtraHTTPHeaders, { 'Cache-Control': 'no-cache' });
assert.deepEqual(result, { image: PNG, type: 'image/png', width: 2432, height: 1368 });
});