
Security News
US Government Forces Anthropic to Pull Claude Fable Days After Launch
Anthropic says the directive cited national security concerns over a narrow jailbreak, but offered no specific technical details.
Mock fetch() with native Request / Response API. Works with globalThis, service worker, @mswjs/interceptors, and custom contexts
Mock fetch() with native Request / Response API. Works with globalThis, service worker, @mswjs/interceptors, and custom contexts.
🐿️ Jump to Callback, Delay, Redirect, Times, Restore, Context, Options, Q&A, or Contributing Guide.
Start with onfetch, pass the same params as constructing a Request object. Then reply as constructing a Response object.
import onfetch from 'onfetch';
onfetch('/simple').reply('path');
// Or
onfetch('/post', { method: 'POST' })
.reply('received');
// Or
onfetch('/down')
.reply(null, { status: 500 });
Works with node-fetch, whatwg-fetch, cross-fetch, whatever, and mainly, modern browsers.
In Node, in addition to setting up global fetch, you also need to set up global Headers, Request, and Response.
How onfetch uses your params to match a Request.
To keep this simple and efficient, we don't and won't support body matching. You will have to put your own processing code into a reply callback when needed.
Rules without a positive times match no request.
A string matches the request's URL if all the following checks pass:
onfetch('/string').persist();
fetch('/string'); // match
fetch('/string?query'); // match
fetch('/string#hash'); // match
onfetch('/string?specify-query').persist();
fetch('/string'); // not match
fetch('/string?other-query'); // not match
fetch('/string?specify-query'); // match
fetch('/string?specify-query#hash'); // match
The use of persist() allows the above onfetch rules to match an unlimited number of times.
The second param, a RequestInit object, matches the Request, when all the checks in the following steps pass:
headers, body, window and the rest parts from the RequestInit object.headers has a match in the request's headers.Request.onfetch('', {
method: 'GET',
headers: {
'Content-Type': 'text/plain',
},
}).persist();
// not match
fetch('', { method: 'GET' });
// not match
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
});
// match
fetch('', {
cache: 'no-cache',
method: 'GET',
headers: {
'Accept': 'text/html',
'Content-Type': 'text/plain',
},
});
Other than using strings, you can also pass a RegExp as the first arg to test the request's URL.
// Match URLs that ends with '.foo'.
onfetch(/\.foo$/).reply('bar');
Put it in consideration that RegExp here test against the entire URL string, which means, if this onfetch rule needn't care about the query string nor the hash, write it like:
// Use regexp that
// allows any trailing query string and hash.
onfetch(/^[^?#]*\.foo([?#]|$)/).reply('bar');
You can also use the brand new URLPattern in the first arg.
const pattern = new URLPattern('http{s}?://*.example.com/books/:id');
onfetch(pattern);
In fact, the first arg accepts any object that has a test method that takes the URL string and returns a boolean value indicating the match result.
You can also pass a Request object as the first arg, to match the request in a manner similar with the RequestInit matcher.
Other than reply as constructing a Response, you can also pass a callback function to form the response.
Your callback will receive two params, the first one points to the Request object, the second one gives you both the original and the mocked fetch.
Remember to return a Response, BodyInit, null, or a Promise that resolves to one of them.
onfetch('').reply((request, fetchers) => {
const example = request.headers.get('One');
if (example === 'original') {
return fetchers.original(request);
}
if (example === 'mocked') {
return fetchers.mocked('/mocked');
}
return 'default-response';
});
A syntactic sugar for sending requests via the original fetch.
import onfetch, { passThrough } from 'onfetch';
onfetch('/use-original').reply(passThrough);
// Delay 200ms before reply.
onfetch('').delay(200).reply('');
The order of delay and reply does not affect the result.
// Same effect.
onfetch('').reply('').delay(200);
The delay duration accumulates.
// Delay 400ms before reply.
onfetch('').delay(200).delay(300).delay(-100).reply('');
Use a Response object that has a redirect status to redirect requests. You can use Response.redirect to construct a such object.
// Redirect to '/bar'.
onfetch('/foo').reply(Response.redirect('/bar'));
// `/bar` respond with `redirected`.
onfetch('/bar').reply('redirected');
// Logs 'redirected'
fetch('/foo').then((res) => res.text()).then(console.log);
Request with redirect set to a value other than follow will fail the fetch with a TypeError.Response only has the correct redirected and url properties defined on the response object itself. Reading them via the prototype will give you incorrect values.You can specify the number of times to apply the onfetch rule via the times function. It accepts an integer as the number of applications of the rule.
// Apply this rule 5 times.
onfetch('/foo').times(5).reply('bar');
You may have multiple rules matching a request at the same time, but only the first rule will apply.
By default, an onfetch rule only applies once. When the times ran out, it bypasses the match.
onfetch('/foo').reply('alpha');
onfetch('/foo').reply('beta');
// Logs 'alpha'
fetch('/foo').then((res) => res.text()).then(console.log);
// Logs 'beta'
fetch('/foo').then((res) => res.text()).then(console.log);
You can specify the times at any time as long as you store the reference of the onfetch rule somewhere.
const onFoo = onfetch('/foo').reply('bar');
fetch('/foo'); // match
// Once again.
onFoo.once();
fetch('/foo'); // match
Note that when all the onfetch rules do not match a request, that request goes to options.defaultRule.
The times(n) doesn't accumulate. It overrides.
const onFoo = onfetch('/foo').twice().once().reply('bar');
fetch('/foo'); // match
fetch('/foo'); // fallback to `defaultRule`
once()A syntactic sugar for rule.times(1).
twice()Syntactic sugar for rule.times(2).
thrice()Sugar for rule.times(3).
persist()For rule.times(Infinity).
restore deactivates onfetch to stop intercepting HTTP calls. Note that it does not clear any intercept rules.
onfetch.restore();
const first = onfetch('/same').reply('first');
onfetch('/same').reply('second');
onfetch.remove(first);
// Logs 'second'
fetch('/foo').then((res) => res.text()).then(console.log);
onfetch.cleanAll();
To (re-)activate onfetch to start intercepting HTTP calls, you can use activate().
onfetch activates itself when you first import it.
onfetch.restore();
// After some code.
onfetch.activate();
In the default mode, onfetch intercepts calls to the fetch() method on globalThis.
To switch back from another mode to this, run:
await onfetch.useDefault();
Service Worker API only works in browsers.
With the help of Service Worker API, you can now mock all the resources your page requires, including those don't go with XMLHttpRequest nor fetch (e.g., CSS files).
// In the main browsing context.
import onfetch from 'onfetch';
await onfetch.useServiceWorker();
onfetch('/script.js').reply('console.log(\'mocked!\')');
const script = document.createElement('script');
script.src = '/script.js';
// Logs 'mocked!'
document.head.append(script);
To enable this feature, import onfetch/sw in your service worker.
// In the service worker.
import 'onfetch/sw';
To switch back to the standard mode in the client side, call onfetch.useDefault().
To disable onfetch/sw in the worker side, store its default import value beforehand, and call its restore method.
// In the service worker.
import onfetchWorker from 'onfetch/sw';
self.addEventListener('message', async ({ data }) => {
// To re-activate, call `.activate()`.
if (data?.example) await onfetchWorker.restore();
// ...
});
@mswjs/interceptors is a HTTP/HTTPS/XHR/fetch request interception library that can intercept most of the requests in Node.js.
With the help of @mswjs/interceptors, we can mock almost all the resources our Node tests requires. To install, run:
npm i @mswjs/interceptors --save-dev
Then somewhere in your test cases, call useMSWInterceptors.
// Switch to @mswjs/interceptors mode.
await onfetch.useMSWInterceptors();
Auto Advanced mode uses either service worker mode or msw interceptors mode depending on whether the env supports the Service Worker API.
// Switch to service worker mode, if the env supports it.
// Otherwise, switch to @mswjs/interceptors mode.
await onfetch.useAutoAdvanced();
onfetch works by replacing the fetch property of a given "context" with a mocked one. By default, this context refers to globalThis. The service worker mode and msw interceptors mode integrates with onfetch by transmitting requests to the fetch() method of an object and passing this object to onfetch as the "context". By doing so onfetch can intercept the requests.
You can write a custom context like:
class SimpleContext {
fetch = async () => new Response('original');
}
const context = new SimpleContext();
Then use onfetch.adopt() to let onfetch use this context.
await onfetch.adopt(context);
Now, all the accesses to the context's fetch() method get intercepted.
onfetch('/basic').reply('mocked');
onfetch('/bypass').reply(passThrough);
// Logs 'mocked'
context.fetch('/basic')
.then((res) => res.text())
.then(console.log);
// Logs 'original'
context.fetch('/bypass')
.then((res) => res.text())
.then(console.log);
In default mode:
Configurable via onfetch.config.
The rule used when all onfetch rules failed to match a request. You can form a rule by constructing a InterceptRule object, which accepts the same params as onfetch.
import onfetch, { InterceptRule } from 'onfetch';
onfetch.config({
defaultRule: new InterceptRule('').reply('default'),
});
Defaults to:
new InterceptRule('').reply((req) => {
throw new Error(`No onfetch rule matches this request to '${req.url}'`);
})
Constructor for abort errors. It should extend from Error and its instance should have the name property set to AbortError.
import onfetch from 'onfetch';
onfetch.config({
AbortError: PutItHere,
});
In Browsers, defaults to:
DOMException.bind(null, 'The user aborted a request.', 'AbortError');
In Node, defaults to:
class AbortError extends Error {
name = 'AbortError';
constructor() {
super('The user aborted a request.');
}
}
Set this to true to bypass onfetch redirection.
import onfetch from 'onfetch';
onfetch.config({
bypassRedirect: true, // or false
});
In advanced modes, this defaults to true, as the browser / upstream package will handle the redirections on its own (see request flow). So we can overcome some redirect limitations.
Checkout our Q&A Discussions for your answers. 👍
Checkout our Contributing Guide please. 👍
FAQs
Mock fetch() with native Request / Response API. Works with globalThis, service worker, @mswjs/interceptors, and custom contexts
The npm package onfetch receives a total of 7 weekly downloads. As such, onfetch popularity was classified as not popular.
We found that onfetch demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Anthropic says the directive cited national security concerns over a narrow jailbreak, but offered no specific technical details.

Security News
A network of 152 Chrome live wallpaper extensions hid ad tracking and made extension-driven traffic look like Google search clicks.

Company News
Socket’s first CISO brings deep experience securing high-growth SaaS companies as open source supply chain threats accelerate.