Skip to content

Commit

Permalink
Merge pull request #714 from wheresrhys/rhys/core-docs
Browse files Browse the repository at this point in the history
Rhys/core docs
  • Loading branch information
wheresrhys authored Jul 20, 2024
2 parents 1a53004 + c742b39 commit 67133b0
Show file tree
Hide file tree
Showing 43 changed files with 828 additions and 117 deletions.
93 changes: 93 additions & 0 deletions docs/docs/@fetch-mock/core/CallHistory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
sidebar_position: 4
---

# Call history

`fetchMock.callHistory` is an object used to record the history of all calls handled by `fetchMock.fetchHandler`.

## CallLog schema

Calls are recorded, and returned, in a standard format with the following properties:

- `{string} url` - The url being fetched
- `{NormalizedRequestOptions} options` - The options passed in to the fetch (may be derived from a `Request` if one was used)
- `{Request} [request]` - The `Request` passed to fetch, if one was used
- `{Route} [route]` - The route used to handle the request
- `{Response} [response]` - The `Response` returned to the user
- `{Promise<any>[]} pendingPromises` - An internal structure used by the `.flush()` method documented below

## Filtering

Most of `fetchMock.callHistory`'s methods take two arguments — `(filter, options)` — which allow `fetch` calls to be extracted and examined.

### filter

Filter calls to `fetch` using one of the following criteria:

#### undefined

Retrieve all calls made to `fetch`

#### true / "matched"

Retrieve all calls to `fetch` matched by some route defined by `fetch-mock`. The string `'matched'` can be used instead of `true` to make tests more readable

#### false / "unmatched"

Retrieve all calls to `fetch` not matched by some route defined by `fetch-mock`, i.e. calls that are handled by `.catch()`. The string `'unmatched'` can be used instead of `false` to make tests more readable

#### name

`{String}`

Retrieve all calls to `fetch` matched by a particular named route.

#### matcher

`{String|RegExp|function|Object}`
Any matcher compatible with the [route api](#api-mockingmock_matcher) can be passed in to filter the calls arbitrarily.

### options

`{Object}`

An options object compatible with the [route api](#api-mockingmock_options) to be used to filter the list of calls further.

## Methods

`fetchMock.callHistory` exposes the following methods.

### .recordCall(callLog)

For internal use.

### .calls(filter, options)

Returns an array of all calls matching the given `filter` and `options`. Each call is returned as a `CallLog`.

### .called(filter, options)

Returns a Boolean indicating whether any calls to `fetch` matched the given `filter` and `options`

### .lastCall(filter, options)

Returns the `CallLog` for the last call to `fetch` matching the given `filter` and `options`.

### fetchMock.done(routeNames)

_Note that this function is exposed on the `fetchMock` object, not on `fetchMock.callHistory`_

TODO, should callHistory just have access to `routes`... yes probably as these docs are horrible

Returns a Boolean indicating whether `fetch` was called the expected number of times (or has been called at least once if `repeat` is not defined for the route). It does not take into account whether the `fetches` completed successfully.

A single name or an array of names can be passed in the `routeNames` parameter to check only certain routes. If no routeNames are passed it runs over all routes.

### .flush(waitForResponseMethods)

Returns a `Promise` that resolves once all fetches handled by fetch-mock have resolved

Useful for testing code that uses `fetch` but where the returned promise cannot be accessed from your tests.

If `waitForBody` is `true`, the promise will wait for all body parsing methods (`res.json()`, `res.text()`, etc.) to resolve too.
52 changes: 52 additions & 0 deletions docs/docs/@fetch-mock/core/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
sidebar_position: 6
---

# Configuration

On any `fetch-mock` instance, set configuration options directly on the `fetchMock.config` object. e.g.

```js
const fetchMock = require('fetch-mock');
fetchMock.config.sendAsJson = false;
```

## Available options

Options marked with a `` can also be overridden for individual calls to `.mock(matcher, response, options)` by setting as properties on the `options` parameter

### sendAsJson<sup>†</sup>

`{Boolean}` default: `true`

Always convert objects passed to `.mock()` to JSON strings before building reponses. Can be useful to set to `false` globally if e.g. dealing with a lot of `ArrayBuffer`s. When `true` the `Content-Type: application/json` header will also be set on each response.

### includeContentLength<sup>†</sup>

`{Boolean}` default: `true`

Sets a `Content-Length` header on each response.

### matchPartialBody

`{Boolean}` default: `false`

Match calls that only partially match a specified body json. Uses the [is-subset](https://www.npmjs.com/package/is-subset) library under the hood, which implements behaviour the same as jest's [.objectContaining()](https://jestjs.io/docs/en/expect#expectobjectcontainingobject) method.

### Custom fetch implementations

`fetch`, `Headers`, `Request`, `Response` can all be set on the configuration object, allowing fetch-mock to mock any implementation of `fetch`, e.g. `node-fetch`. e.g.

```js

import { default as fetch, Headers, Request, Response } from 'node-fetch';

import fetchMock from 'fetch-mock';

fetchMock.config = Object.assign(fetchMock.config, {
Request,
Response,
Headers,
fetch,
});
```
14 changes: 14 additions & 0 deletions docs/docs/@fetch-mock/core/fetchHandler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
sidebar_position: 1
sidebar_label: .fetchHandler
---

# fetchHandler

`fetchMock.fetchHandler(url, requestInit)`

A mock implementation of `fetch`.

By default it will error. In order to return responses `.route()`, `.catch()` and other convenience methods of `fetchMock` must first be used to add routes to its internal router.

All calls made using `fetchMock.fetchHandler` are recorded in `fetchMock.callHistory`.
14 changes: 14 additions & 0 deletions docs/docs/@fetch-mock/core/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
sidebar_label: '@fetch-mock/core'
sidebar_position: 1
---

# @fetch-mock/core

This library implements three main features

1. A function, `fetchHandler`, that can be used as a drop in replacement for fetch.
2. A set of chainable API methods for adding routes to `fetchHandler`, which alter how it handles different requests.
3. Some low level APIs for accessing the call history of `fetchHandler` (these are not intended for direct use by the developer, but expose enough information for other libraries, such as `@fetch-mock/jest`, to provide more user friendly APIs built on top of this low level functionality).

`@fetch-mock/core` is not intended for direct use in tests. It **DOES NOT** actually replace your `fetch` implementation with `fetchHandler`; this is left to wrapper libraries such as `@fetch-mock/jest`. This is because different testing frameworks have different opinions about this behaviour, and this core library deliberately avoids making decisions likely to clash with other tools in your testing toolchain, so that the `fetchHandler` implementation is more portable.
139 changes: 139 additions & 0 deletions docs/docs/@fetch-mock/core/more-routing-methods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
sidebar_position: 3
sidebar_label: More routing methods
---

# More routing methods

These methods allow defining routes for common use cases while avoiding writing hard to read configuration objects. Unless noted otherwise, each of the methods below have the same signature as `.route()`

## .catch()

`.catch(response)`

Specifies how to respond to calls to `fetch` that don't match any routes.

It accepts any [response](#api-mockingmock_response) compatible with `.route()`. If no argument is passed, then every unmatched call will receive a `200` response.

## .sticky()

Shorthand for `mock()` which creates a route that persists even when `restore()`, `reset()` or `resetbehavior()` are called;

This method is particularly useful for setting up fixtures that must remain in place for all tests, e.g.

```js
fetchMock.sticky(/config-hub.com/, require('./fixtures/start-up-config.json'));
```

## .once()

Shorthand for `mock()` which creates a route that can only mock a single request. (see `repeat` option above)

## .any()

`.any(response, options)`

Shorthand for `mock()` which creates a route that will return a response to any fetch request.

## .anyOnce(response, options)

`.anyOnce(response, options)`

Creates a route that responds to any single request

## .get(), .post(), .put(), .delete(), .head(), .patch()

Shorthands for `mock()` that create routes that only respond to requests using a particular http method.

If you use some other method a lot you can easily define your own shorthands e.g.

```javascript
fetchMock.purge = function (matcher, response, options) {
return this.mock(
matcher,
response,
Object.assign({}, options, { method: 'PURGE' }),
);
};
```

## .getOnce(), .postOnce(), .putOnce(), .deleteOnce(), .headOnce(), .patchOnce()

Creates a route that only responds to a single request using a particular http method

## .getAny(), .postAny(), .putAny(), .deleteAny(), .headAny(), .patchAny()

`.___Any(response, options)`

Creates a route that responds to any requests using a particular http method.

## .getAnyOnce(), .postAnyOnce(), .putAnyOnce(), .deleteAnyOnce(), .headAnyOnce(), .patchAnyOnce()

`.___AnyOnce(response, options)`

Creates a route that responds to any single request using a particular http method.

## .addMatcher(options)

Allows adding your own, reusable custom matchers to fetch-mock, for example a matcher for interacting with GraphQL queries, or an `isAuthorized` matcher that encapsulates the exact authorization conditions for the API you are mocking, and only requires a `true` or `false` to be input

### Options

#### name

`{String}`

The name of your matcher. This will be the name of the property used to hold any input to your matcher. e.g. `graphqlVariables`

#### usesBody

`{Boolean}`

If your matcher requires access to the body of the request set this to true; because body can, in some cases, only be accessed by fetch-mock asynchronously, you will need to provide this hint in order to make sure the correct code paths are followed.

#### matcher

`{Function}`

A function which takes a route definition object as input, and returns a function of the signature `(url, options, request) => Boolean`. See the examples below for more detail. The function is passed the fetchMock instance as a second parameter in case you need to access any config.

##### Examples

###### Authorization

```js
fetchMock
.addMatcher({
name: 'isAuthorized',
matcher:
({ isAuthorized }) =>
(url, options) => {
const actuallyIsAuthorized = options.headers && options.headers.auth;
return isAuthorized ? actuallyIsAuthorized : !actuallyIsAuthorized;
},
})
.mock({ isAuthorized: true }, 200)
.mock({ isAuthorized: false }, 401);
```

###### GraphQL

```js
fetchMock
.addMatcher({
name: 'graphqlVariables',
matcher: ({graphqlVariables}) => (url, options) => {
if (!/\/graphql$/.test(url)) {
return false;
}
const body = JSON.parse(options.body)
return body.variables && Object.keys(body.variables).length === Object.keys(body.graphqlVariables).length && Object.entries(graphqlVariables).every(([key, val]) => body.variables[key] === val)
}
})
.mock({graphqlVariables: {owner: 'wheresrhys'}}, {data: {account: {
name: 'wheresrhys',
repos: [ ... ]
}}})
```

One intent behind this functionality is to allow companies or publishers of particular toolsets to provide packages that extend fetch-mock to provide a more user friendly experience for developers using fetch to interact with their APIs. The GraphQL use case is a good example of this - the things which a developer might want to match on are buried in the request body, and written in a non-javascript query language. Please get in touch if you'd like to collaborate on writing such a package.
47 changes: 47 additions & 0 deletions docs/docs/@fetch-mock/core/resetting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
sidebar_position: 5
---

# Resetting

The methods below can be used to restore some or all of fetchMock's behaviour toits default state.

## .removeRoutes(options)

This method removes some or all of the routes that have been added to fetch mock. It accepts the following options.

### names

An array of named routes to remove. If no value is passed then all routes compatible with the other options passed are removed.

### includeSticky

A boolean indicating whether or not to remove sticky routes.

### includeFallback

A boolean indicating whether or not to remove the fallback route (added using `.catch()`)

## .clearHistory()

Clears all data recorded for `fetch`'s calls.

## .createInstance()

Can be used to create a standalone instance of fetch mock that is completely independent of other instances.

In older environments - where `fetch` was not a global and test files often ran in a shared process - this was very useful for increasing parallelisation. But in more modern setups - global `fetch` and isolated processes per test file - it's less relevant.

It can however be used as an alternative to `fetchMock.removeRoutes().clearHistory()` by creating a completely new fetchMock instance and swapping this for the previously used one.

It can also be used to "fork" a previous instance as routes are cloned from one instance to another. However call history is always reset for new instances.

```js
fetchMock.route('http://my.site', 200);
fetchMock.fetchHandler('http://my.site');

const newFM = fetchMock.createInstance();

newFM.routes.routes; // Array[1]
newFM.callHistory.calls(); // Array[0]
```
5 changes: 5 additions & 0 deletions docs/docs/@fetch-mock/core/route/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"position": 2.5,
"collapsible": false,
"collapsed": false,
}
Loading

0 comments on commit 67133b0

Please sign in to comment.