Deno mock fetch implementation to be used
in testing. This module allows one to intercept calls to the global fetch
API
and control the behaviour accordingly.
- Intercept calls to the global
fetch
API - Intercept multiple types of requests at once, based on:
- Request Origin
- Request Path
- Request Query string
- Request Body
- Request Headers
- Intercept request indefinitely
- Intercept request a finite number of times
- Simulate a request time delay
- Support for falling back to calling a real API for defined hostnames
- All global
fetch
API inputs are supported - Advanced methods for matching requests:
string
RegExp
Function
- Throw custom error support
- Set default headers
- Auto-generated headers:
content-length
Set up a basic fetch
interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
// Intercept `GET https://example.com/hello`
.intercept("https://example.com/hello", { method: "GET" })
// Respond with status `200` and text `hello`
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
By default, subsequent calls to the same URL will reject with a
MockNotMatchedError
:
// Rejects with MockNotMatchedError
await fetch("https://example.com/hello");
This behaviour can be changed as demonstrated in the examples.
I want to:
- Intercept a request containing a Query String
- Intercept a request indefinitely
- Intercept a request a set number of times
- Intercept a request with a delay
- Default to calling the original URL if a mock is not matched
- Default to calling specified URLs if a mock is not matched
- Deactivate calling original URLs
- Activate fetch interceptions
- Deactivate fetch interceptions
- Check if fetch interceptions are active
- Close and clean up the Mock Fetch instance
- Get the number of times requests have been intercepted
- View registered mock metadata
- Intercept a request based on method RegExp
- Intercept a request based on method Function
- Intercept a request based on URL RegExp
- Intercept a request based on URL Function
- Intercept a request based on body
- Intercept a request based on headers object
- Intercept a request based on headers instance
- Intercept a request based on headers array
- Intercept a request based on headers function
- Throw a custom error upon fetch call
- Set default headers
- Autogenerate
content-length
header - Intercept requests alongside superdeno
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello?foo=bar", { method: "GET" })
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello?foo=bar");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor, using the persist
method on the MockScope
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", { method: "GET" })
.response("hello", { status: 200 })
.persist();
Call the matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Call the matching URL again:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor, using the times
method on the MockScope
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", { method: "GET" })
.response("hello", { status: 200 })
// Will intercept matching requests twice
.times(2);
Call the matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Call the matching URL again:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Call the matching URL a final time:
// Rejects with MockNotMatchedError
await fetch("https://example.com/hello");
Set up the interceptor, using the delay
method on the MockScope
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", { method: "GET" })
.response("hello", { status: 200 })
// Delay 1000ms before returning the response
.delay(1000);
Call the matching URL:
const response = await fetch("https://example.com/hello");
// 1000ms later...
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Sometimes, one might want to default to calling the original URL if a mock is
not matched. This can be done with the activateNetConnect
method on the
MockFetch
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch.activateNetConnect();
mockFetch
.intercept("https://example.com/hello", { method: "GET" })
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Call the same URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // Some html from the actual endpoint
In addition, one might want to default to calling the original URL for certain
hostnames if a mock is not matched. This can be done by passing matchers to the
activateNetConnect
method on the MockFetch
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
// Allow calls to `example.com` upon an unmatched request.
// This can be called multiple to times to register multiple hostnames
mockFetch.activateNetConnect("example.com");
Call a non-matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // Some html from the actual endpoint
Call another non-matching URL:
const response = await fetch("https://another-example.com/hello");
// Rejects with MockNotMatchedError
await fetch("https://example.com/hello");
Deactivate calling original URLs by calling the deactivateNetConnect
on the
MockFetch
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch.activateNetConnect();
// Do work...
mockFetch.deactivateNetConnect();
Activate fetch interceptions by calling the activate
method on the MockFetch
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch.activate();
Deactivate fetch interceptions by calling the deactivate
method on the
MockFetch
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch.deactivate();
Check if fetch interceptions are active by checking the value of the
isMockActive
field on the MockFetch
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
console.log(mockFetch.isMockActive); // true
Close and clean up the Mock Fetch instance by calling the close
method on the
MockFetch
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch.close();
Get the number of times requests have been intercepted by checking the value of
the calls
field on the MockFetch
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
console.log(mockFetch.calls); // 0
mockFetch
.intercept("https://example.com/hello?foo=bar", { method: "GET" })
.response("hello", { status: 200 });
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
console.log(mockFetch.calls); // 1
View registered mock scope metadata by checking the value of the metadata
field on the MockScope
instance.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
console.log(mockFetch.calls); // 0
const mockScope = mockFetch
.intercept("https://example.com/hello?foo=bar", { method: "GET" })
.response("hello", { status: 200 });
console.log(mockScope.metadata); // MockRequest
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", { method: /GET/ })
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", {
method: (input) => input === "GET",
})
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept(new RegExp("https\\:\\/\\/example\\.com\\/hello\\?foo\\=bar"))
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello?foo=bar");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept((input) => input === "https://example.com/hello?foo=bar")
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello?foo=bar");
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", {
method: "POST",
body: "hello",
})
.response("there", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello", {
method: "POST",
body: "hello",
});
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "there"
Note, the following body types are also supported:
string
RegExp
(input: string) => boolean
Blob
ArrayBufferLike
FormData
URLSearchParams
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", {
headers: {
hello: "there",
foo: /bar/,
hey: (input: string) => input === "ho",
},
})
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello", {
headers: new Headers({
hello: "there",
foo: "bar",
hey: "ho",
}),
});
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", {
headers: new Headers({
hello: "there",
another: "one",
}),
})
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello", {
headers: new Headers({
hello: "there",
another: "one",
}),
});
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", {
headers: [
["hello", "there"],
["foo", /bar/],
["hey", (input: string) => input === "ho"],
],
})
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello", {
headers: new Headers({
hello: "there",
foo: "bar",
hey: "ho",
}),
});
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept("https://example.com/hello", {
headers: (headers) => headers.get("hello") === "there",
})
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello", {
headers: new Headers({
hello: "there",
}),
});
const text = await response.text();
console.log(response.status); // 200
console.log(text); // "hello"
Set up the interceptor and defined an error using the following documentation as a guide.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch
.intercept((input) => input === "https://example.com/hello")
.throwError(new TypeError("Network error"));
Call the matching URL:
await fetch("https://example.com/hello"); // Throws the defined error: new TypeError("Network error")
Set up the interceptor.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
const mockInterceptor = mockFetch
.intercept("https://example.com/hello")
.defaultResponseHeaders({ foo: "bar" })
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(response.headers); // { "content-type", "text/plain;charset=UTF-8", foo: "bar" }
console.log(text); // "hello"
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
const mockInterceptor = mockFetch
.intercept("https://example.com/hello")
.responseContentLength()
.response("hello", { status: 200 });
Call the matching URL:
const response = await fetch("https://example.com/hello");
const text = await response.text();
console.log(response.status); // 200
console.log(response.headers); // { "content-type", "text/plain;charset=UTF-8", "content-length": "5" }
console.log(text); // "hello"
To work alongside superdeno, one must setup calls to 127.0.0.1
before
continuing.
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
import { superdeno } from "https://deno.land/x/superdeno/mod.ts";
import { opine } from "https://deno.land/x/opine@1.9.1/mod.ts";
const app = opine();
app.get("/user", (req, res) => {
res.setStatus(200).json({ name: "Deno" });
});
// Setup mock before calling superdeno
const mockFetch = new MockFetch();
mockFetch.activateNetConnect("127.0.0.1");
superdeno(app)
.get("/user")
.expect("Content-Type", /json/)
.expect("Content-Length", "15")
.expect(200)
.end((err, res) => {
if (err) throw err;
});
To browse API documentation:
- Go to https://deno.land/x/deno_mock_fetch.
- Click "View Documentation".
Contributions, issues and feature requests are very welcome. If you are using this package and fixed a bug for yourself, please consider submitting a PR!
Further details can be found in the Contributing guide.
The following limitations are known:
The following with throw an InvalidArgumentError
:
import { MockFetch } from "https://deno.land/x/deno_mock_fetch@1.0.1/mod.ts";
const mockFetch = new MockFetch();
mockFetch.intercept("https://example.com/hello", {
method: "POST",
body: new ReadableStream(),
});
// Throws an `InvalidArgumentError`
Trailers are currently not supported for the following reasons:
- Not returned in Deno fetch responses
- Limited support and documentation
This module is 100% free and open-source, under the MIT license.
This modules has been inspired by the following: