New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@aryzing/bun-mock-fetch

Package Overview
Dependencies
Maintainers
0
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@aryzing/bun-mock-fetch - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

7

dist/constants.d.ts

@@ -1,5 +0,2 @@

import { type MockOptions } from "./types.js";
/**
* The default value for mock options.
*/
export declare const defaultMockOptions: MockOptions;
import { type MockResponseOptions } from "./types.js";
export declare const defaultMockOptions: MockResponseOptions;
import {} from "./types.js";
/**
* The default value for mock options.
*/
export const defaultMockOptions = {
response: {
data: null,
// @ts-ignore // Not sure why, the Headers type is not recognized.
headers: new Headers(),
status: 200,
},
data: null,
status: 200,
};
//# sourceMappingURL=constants.js.map

@@ -1,9 +0,7 @@

import { type MockOptions } from "./types.js";
import type { MockResponseOptions, RequestMatcher } from "./types.js";
export declare function setIsVerbose(value: boolean): void;
type Minimatch = string;
export type URLMatch = Minimatch | RegExp;
/**
* Mock the fetch method. The most recently defined matching mock will be used.
*/
export declare const mockFetch: (urlMatch: URLMatch, options?: MockOptions) => void;
export declare const mockFetch: (requestMatcher: RequestMatcher, mockResponseOptions?: MockResponseOptions) => void;
/**

@@ -18,2 +16,1 @@ * Clear the fetch mock.

export declare function setIsUsingBuiltInFetchFallback(value: boolean): void;
export {};
import { minimatch } from "minimatch";
import { defaultMockOptions } from "./constants.js";
import {} from "./types.js";
import { makeSimplifiedResponse } from "./utils.js";

@@ -10,10 +9,2 @@ let originalFetch;

}
// | {
// type: "function";
// fn: (
// input: Parameters<typeof fetch>[0],
// init: Parameters<typeof fetch>[1],
// ) => boolean;
// options: MockOptions;
// };
/**

@@ -23,21 +14,36 @@ * The cache for registered mocked requests.

const mockedRequests = [];
// | ((
// input: Parameters<typeof fetch>[0],
// init: Parameters<typeof fetch>[1],
// ) => boolean);
/**
* Mock the fetch method. The most recently defined matching mock will be used.
*/
export const mockFetch = (urlMatch, options = defaultMockOptions) => {
if (urlMatch instanceof RegExp) {
mockedRequests.unshift({ type: "regexp", regexp: urlMatch, options });
export const mockFetch = (requestMatcher, mockResponseOptions = defaultMockOptions) => {
if (requestMatcher instanceof RegExp) {
mockedRequests.unshift({
type: "regexp",
regexp: requestMatcher,
mockResponseOptions,
});
}
else if (typeof urlMatch === "string") {
mockedRequests.unshift({ type: "minimatch", minimatch: urlMatch, options });
else if (typeof requestMatcher === "string") {
mockedRequests.unshift({
type: "stringLiteralOrMinimatch",
value: requestMatcher,
mockResponseOptions,
});
}
// else if (typeof urlMatch === "function") {
// mockedRequests.unshift({ type: "function", fn: urlMatch, options });
// }
else if (typeof requestMatcher === "function") {
mockedRequests.unshift({
type: "function",
fn: requestMatcher,
mockResponseOptions,
});
}
else if (typeof requestMatcher === "object") {
mockedRequests.unshift({
type: "detailed",
matcher: requestMatcher,
mockResponseOptions,
});
}
else {
throw new Error("Invalid URL match type");
throw new Error("Invalid matcher.");
}

@@ -72,52 +78,45 @@ if (!originalFetch) {

/**
* A mocked fetch method.
* The mocked fetch method.
*/
const mockedFetch = async (input, init) => {
const path = input instanceof Request ? input.url : input.toString();
const requestUrl = input instanceof Request ? input.url : input.toString();
if (isVerbose)
console.debug("[BMF]: Mocked fetch called with path:", path);
console.debug("[BMF]: Mocked fetch called with path:", requestUrl);
for (const mockedRequest of mockedRequests) {
switch (mockedRequest.type) {
case "regexp": {
// Match path
if (!mockedRequest.regexp.test(path))
if (!mockedRequest.regexp.test(requestUrl))
continue;
// Match method
const optionsMethod = mockedRequest.options.method;
const requestMethod = (init && init.method) || "GET";
if (optionsMethod &&
optionsMethod.toLowerCase() !== requestMethod.toLowerCase())
return makeSimplifiedResponse(requestUrl, mockedRequest.mockResponseOptions);
}
case "stringLiteralOrMinimatch": {
if (requestUrl !== mockedRequest.value &&
!minimatch(requestUrl, mockedRequest.value))
continue;
// Match headers
const optionsHeaders = mockedRequest.options.headers;
if (optionsHeaders) {
const inputHeaders = input instanceof Request ? input.headers : new Headers();
const initHeaders = new Headers(init?.headers);
const requestHeaders = new Headers([...inputHeaders, ...initHeaders]);
const headersMatch = [...Object.entries(optionsHeaders)].every(([optionHeaderName, optionHeaderValue]) => {
const requestHeaderValue = requestHeaders.get(optionHeaderName);
return requestHeaderValue === optionHeaderValue;
});
if (!headersMatch)
return makeSimplifiedResponse(requestUrl, mockedRequest.mockResponseOptions);
}
case "function": {
if (!mockedRequest.fn(input, init))
continue;
return makeSimplifiedResponse(requestUrl, mockedRequest.mockResponseOptions);
}
case "detailed": {
const { matcher, mockResponseOptions } = mockedRequest;
const { url, method, headers } = matcher;
if (typeof url === "string") {
if (url !== requestUrl && !minimatch(requestUrl, url))
continue;
}
return makeSimplifiedResponse(path, mockedRequest.options);
}
case "minimatch": {
// Match path
if (!minimatch(path, mockedRequest.minimatch))
else if (url instanceof RegExp) {
if (!url.test(requestUrl))
continue;
}
if (method &&
method.toLowerCase() !== (init?.method || "GET").toLowerCase())
continue;
// Match method
const optionsMethod = mockedRequest.options.method;
const requestMethod = (init && init.method) || "GET";
if (optionsMethod &&
optionsMethod.toLowerCase() !== requestMethod.toLowerCase())
continue;
// Match headers
const optionsHeaders = mockedRequest.options.headers;
if (optionsHeaders) {
if (headers) {
const inputHeaders = input instanceof Request ? input.headers : new Headers();
const initHeaders = new Headers(init?.headers);
const requestHeaders = new Headers([...inputHeaders, ...initHeaders]);
const headersMatch = [...Object.entries(optionsHeaders)].every(([optionHeaderName, optionHeaderValue]) => {
const headersMatch = [...Object.entries(headers)].every(([optionHeaderName, optionHeaderValue]) => {
const requestHeaderValue = requestHeaders.get(optionHeaderName);

@@ -129,3 +128,3 @@ return requestHeaderValue === optionHeaderValue;

}
return makeSimplifiedResponse(path, mockedRequest.options);
return makeSimplifiedResponse(requestUrl, mockResponseOptions);
}

@@ -135,12 +134,15 @@ }

if (isVerbose)
console.debug("[BMF]: No matching mock found for path:", path);
console.debug("[BMF]: No matching mock found for request:", requestUrl);
if (isUsingBuiltInFetchFallback) {
if (isVerbose)
console.debug("[BMF]: Using built-in fetch for path:", path);
console.debug("[BMF]: Using built-in fetch for request:", requestUrl);
return originalFetch(input, init);
}
if (isVerbose)
console.debug("[BMF]: Rejecting with 404 for path:", path);
return Promise.reject(makeSimplifiedResponse(path, { response: { status: 404 } }));
console.debug("[BMF]: Responding with 404:", requestUrl);
return Promise.resolve(makeSimplifiedResponse(requestUrl, {
status: 404,
data: `{"bun-mock-fetch":"No matching mocks."}`,
}));
};
//# sourceMappingURL=mock.js.map

@@ -1,18 +0,12 @@

/**
* The options for a mocked request. Partial implementation of RequestInit with
* the addition of "data" property which value will be returned from the mock.
*/
export type MockOptions = {
export type Glob = string;
export type DetailedMatcher = {
url?: string | Glob | RegExp;
method?: string;
headers?: Record<string, string>;
method?: Request["method"];
response?: MockResponse;
};
/**
* The response for a mocked request. Partial implementation of Response with
* the addition of "data" property which value will be returned from the mock.
*/
export interface MockResponse {
data?: any;
export type RequestMatcher = string | Glob | RegExp | ((input: Parameters<typeof fetch>[0], init: Parameters<typeof fetch>[1]) => boolean) | DetailedMatcher;
export type MockResponseOptions = {
data?: unknown;
status?: number;
headers?: Record<string, string>;
}
};

@@ -1,10 +0,3 @@

import { type MockOptions } from "./types.js";
import { type MockResponseOptions } from "./types.js";
export type SimplifiedResponse = Omit<Response, "type" | "body" | "arrayBuffer" | "blob" | "formData" | "clone">;
/**
* Returns an object similar to Response class.
* @param status - The HTTP status code of the response.
* @param url - The URL of the request.
* @param options - The options for the mocked request.
* @returns An object similar to Response class.
*/
export declare function makeSimplifiedResponse(url: string, options?: MockOptions): SimplifiedResponse;
export declare function makeSimplifiedResponse(url: string, options?: MockResponseOptions): SimplifiedResponse;
import { defaultMockOptions as defaultMockOptions } from "./constants.js";
import {} from "./types.js";
/**
* Returns an object similar to Response class.
* @param status - The HTTP status code of the response.
* @param url - The URL of the request.
* @param options - The options for the mocked request.
* @returns An object similar to Response class.
*/
export function makeSimplifiedResponse(url, options = defaultMockOptions) {
const responseHeaders = new Headers(options.response?.headers);
const status = options.response?.status ?? 200;
const responseHeaders = new Headers(options.headers);
const status = options.status ?? 200;
const ok = status >= 200 && status < 300;
const body = options.response?.data;
const body = options.data;
return {

@@ -21,3 +14,3 @@ ok,

headers: responseHeaders,
text: () => Promise.resolve(body),
text: () => Promise.resolve(`${body}`),
json: () => Promise.resolve(body),

@@ -24,0 +17,0 @@ redirected: false,

{
"name": "@aryzing/bun-mock-fetch",
"version": "0.1.0",
"version": "0.2.0",
"author": "Eduard Bardají Puig <@aryzing>",

@@ -5,0 +5,0 @@ "type": "module",

@@ -9,6 +9,12 @@ # `@aryzing/bun-mock-fetch`

Example usage:
Basic usage:
```typescript
// Returns 200 OK by default
mockFetch(requestMatcher, optionalMockResponseOptions);
```
Request matcher examples:
```typescript
// Simple string matching
mockFetch("https://example.com");

@@ -22,11 +28,14 @@

mockFetch("https://example.com/foo/**", {
// Must have these headers.
headers: { "x-example-header": "example-value" },
// Must use this method.
method: "GET",
response: {
data: JSON.stringify({ foo: "bar" }),
headers: { "Content-Type": "application/json" },
status: 200,
// Using a function
mockFetch((input, init) => input.url === "https://example.com");
// Using a detailed matcher object. All properties are optional.
mockFetch({
// Must match this string, glob, or regex
url: "https://example.com",
// Must match this method (case-insensitive).
method: "POST",
// Must include these headers (case-insensitive) and match their values.
headers: {
"Content-Type": "application/json",
},

@@ -36,2 +45,15 @@ });

Response options example:
```typescript
mockFetch(/.*example.*/, {
// The expected resolved value of Response.json() or Response.text().
data: "Hello, world!",
status: 200,
headers: {
"Content-Type": "text/plain",
},
});
```
Example in tests,

@@ -63,3 +85,3 @@

The `mockFetch` method may be called several times to define multiple mocks. Requests will at be matched at most against one mock, with later mocks take precendece over earlier mocks.
Each call to `mockFetch` defines a new mock. At most one mock is used,, with each mock taking precendece over previously defined mocks.

@@ -66,0 +88,0 @@ By default, requests that aren't matched against any mock definitions are forwarded to the native built-in fetch. This behavior can be modified using `setIsUsingBuiltInFetchFallback()`.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc