fix(webrequest): complete rewrite to v4: migrate API to fetch-compatible function and new WebrequestClient, update tests and docs, and bump dependencies
This commit is contained in:
@@ -1,96 +1,88 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import { webrequest, WebrequestClient } from '../ts/index.js';
|
||||
import * as typedserver from '@api.global/typedserver';
|
||||
import { TypedServer } from '@api.global/typedserver';
|
||||
|
||||
let testServer: typedserver.servertools.Server;
|
||||
let testServer: TypedServer;
|
||||
|
||||
// Setup test server
|
||||
tap.test('setup test server for v4 tests', async () => {
|
||||
testServer = new typedserver.servertools.Server({
|
||||
testServer = new TypedServer({
|
||||
cors: false,
|
||||
forceSsl: false,
|
||||
port: 2346,
|
||||
});
|
||||
|
||||
// Route that returns JSON with cache headers
|
||||
testServer.addRoute(
|
||||
'/cached',
|
||||
new typedserver.servertools.Handler('GET', (req, res) => {
|
||||
res.setHeader('Cache-Control', 'max-age=60');
|
||||
res.setHeader('ETag', '"12345"');
|
||||
res.status(200);
|
||||
res.send({ data: 'cached response', timestamp: Date.now() });
|
||||
}),
|
||||
);
|
||||
testServer.addRoute('/cached', 'GET', async (ctx) => {
|
||||
return new Response(JSON.stringify({ data: 'cached response', timestamp: Date.now() }), {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'max-age=60',
|
||||
'ETag': '"12345"',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Route that returns different data each time
|
||||
testServer.addRoute(
|
||||
'/dynamic',
|
||||
new typedserver.servertools.Handler('GET', (req, res) => {
|
||||
res.status(200);
|
||||
res.send({ data: 'dynamic response', timestamp: Date.now() });
|
||||
}),
|
||||
);
|
||||
testServer.addRoute('/dynamic', 'GET', async (ctx) => {
|
||||
return new Response(JSON.stringify({ data: 'dynamic response', timestamp: Date.now() }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
});
|
||||
|
||||
// Route that sometimes fails (for retry testing)
|
||||
let requestCount = 0;
|
||||
testServer.addRoute(
|
||||
'/flaky',
|
||||
new typedserver.servertools.Handler('GET', (req, res) => {
|
||||
requestCount++;
|
||||
if (requestCount < 3) {
|
||||
res.status(500);
|
||||
res.end();
|
||||
} else {
|
||||
res.status(200);
|
||||
res.send({ success: true, attempts: requestCount });
|
||||
}
|
||||
}),
|
||||
);
|
||||
testServer.addRoute('/flaky', 'GET', async (ctx) => {
|
||||
requestCount++;
|
||||
if (requestCount < 3) {
|
||||
return new Response(null, { status: 500 });
|
||||
} else {
|
||||
return new Response(JSON.stringify({ success: true, attempts: requestCount }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Route that always fails with 500 (for fallback testing)
|
||||
testServer.addRoute(
|
||||
'/always-fails',
|
||||
new typedserver.servertools.Handler('GET', (req, res) => {
|
||||
res.status(500);
|
||||
res.end();
|
||||
}),
|
||||
);
|
||||
testServer.addRoute('/always-fails', 'GET', async (ctx) => {
|
||||
return new Response(null, { status: 500 });
|
||||
});
|
||||
|
||||
// Route that takes a long time to respond (for timeout testing)
|
||||
testServer.addRoute(
|
||||
'/slow',
|
||||
new typedserver.servertools.Handler('GET', async (req, res) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
res.status(200);
|
||||
res.send({ data: 'slow response' });
|
||||
}),
|
||||
);
|
||||
testServer.addRoute('/slow', 'GET', async (ctx) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
return new Response(JSON.stringify({ data: 'slow response' }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
});
|
||||
|
||||
// Route that returns 304 when ETag matches
|
||||
testServer.addRoute(
|
||||
'/conditional',
|
||||
new typedserver.servertools.Handler('GET', (req, res) => {
|
||||
const ifNoneMatch = req.headers['if-none-match'];
|
||||
if (ifNoneMatch === '"67890"') {
|
||||
res.status(304);
|
||||
res.end();
|
||||
} else {
|
||||
res.setHeader('ETag', '"67890"');
|
||||
res.status(200);
|
||||
res.send({ data: 'conditional response' });
|
||||
}
|
||||
}),
|
||||
);
|
||||
testServer.addRoute('/conditional', 'GET', async (ctx) => {
|
||||
const ifNoneMatch = ctx.request.headers.get('if-none-match');
|
||||
if (ifNoneMatch === '"67890"') {
|
||||
return new Response(null, { status: 304 });
|
||||
} else {
|
||||
return new Response(JSON.stringify({ data: 'conditional response' }), {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'ETag': '"67890"',
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// POST route for testing
|
||||
testServer.addRoute(
|
||||
'/post',
|
||||
new typedserver.servertools.Handler('POST', (req, res) => {
|
||||
res.status(200);
|
||||
res.send({ received: true });
|
||||
}),
|
||||
);
|
||||
testServer.addRoute('/post', 'POST', async (ctx) => {
|
||||
return new Response(JSON.stringify({ received: true }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
});
|
||||
|
||||
await testServer.start();
|
||||
});
|
||||
@@ -247,8 +239,6 @@ tap.test('should support global interceptors', async () => {
|
||||
|
||||
// Test 11: Request deduplication
|
||||
tap.test('should deduplicate simultaneous requests', async () => {
|
||||
const start = Date.now();
|
||||
|
||||
// Make 3 identical requests simultaneously
|
||||
const [res1, res2, res3] = await Promise.all([
|
||||
webrequest('http://localhost:2346/dynamic', { deduplicate: true }),
|
||||
|
||||
Reference in New Issue
Block a user