Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jefflau/jest-fetch-mock
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: musement/jest-fetch-mock
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.

Commits on Jun 14, 2018

  1. added async support

    * promises are accepted as first argument instead of body
    * README and typescript interfaces updated
    lsimone committed Jun 14, 2018
    Copy the full SHA
    c7abcdb View commit details

Commits on Nov 22, 2018

  1. small refactor

    lsimone committed Nov 22, 2018
    Copy the full SHA
    5766a59 View commit details
  2. Copy the full SHA
    a3bd3be View commit details
  3. typescript updated

    lsimone committed Nov 22, 2018
    Copy the full SHA
    dea14d3 View commit details

Commits on Nov 23, 2018

  1. Merge remote-tracking branch 'lsimone/master'

    # Conflicts:
    #	README.md
    #	src/index.d.ts
    #	src/index.js
    lsimone committed Nov 23, 2018
    Copy the full SHA
    756ff58 View commit details
  2. readme example fixed

    lsimone committed Nov 23, 2018
    Copy the full SHA
    7e8f1c9 View commit details
  3. README + normalizeError fixed, tests added

    lsimone committed Nov 23, 2018
    Copy the full SHA
    8828289 View commit details
  4. removed IDE files, added folder to gitignore

    lsimone committed Nov 23, 2018
    Copy the full SHA
    d963d81 View commit details

Commits on May 8, 2019

  1. added timeout tests

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    24c264c View commit details
  2. 2.0.0

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    b3ea257 View commit details
  3. Update readme with function example

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    240c537 View commit details
  4. 2.0.1

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    3f5aa2f View commit details
  5. update link

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    03d9c22 View commit details
  6. Update link

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    ea0bb59 View commit details
  7. Update readme

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    b72838f View commit details
  8. Improved TS support (#99)

    dsebastien authored and loris committed May 8, 2019
    Copy the full SHA
    ca4bfa1 View commit details
  9. 2.1.0

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    07c85aa View commit details
  10. Update README.md

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    4f4a74e View commit details
  11. Updated Jest and Jest Types (#106)

    * Updated Jest and Jest Types - adjusted breaking change of generic signature of MockInstance
    
    * Revert update of dependencies and adjusted types
    janhartmann authored and loris committed May 8, 2019
    Copy the full SHA
    9bfa9ce View commit details
  12. 2.1.1

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    665b614 View commit details
  13. Copy the full SHA
    cbf43e9 View commit details
  14. 2.1.2

    jefflau authored and loris committed May 8, 2019
    Copy the full SHA
    c766c8f View commit details
Showing with 1,480 additions and 550 deletions.
  1. +1 −1 .npmignore
  2. +79 −7 README.md
  3. +10 −4 package.json
  4. +0 −24 src/index.d.ts
  5. +15 −21 src/index.js
  6. +82 −0 tests/test.js
  7. +12 −0 tsconfig.json
  8. +1 −0 tslint.json
  9. +46 −0 types/index.d.ts
  10. +59 −0 types/test.ts
  11. +21 −0 types/tsconfig.json
  12. +1,154 −493 yarn.lock
2 changes: 1 addition & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
tests
yarn.lock
yarn.lock
86 changes: 79 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Jest Fetch Mock

Fetch is the new way to do HTTP requests in the browser, and it can be used in other environments such as React Native. Jest Fetch Mock allows you to easily mock your `fetch` calls and return the response you need to fake the HTTP requests. It's easy to setup and you don't need a library like `nock` to get going and it uses Jest's built-in support for mocking under the surface. This means that any of the `jest.fn()` methods are also available. For more information on the jest mock API, check their docs [here](https://facebook.github.io/jest/docs/en/mock-functions.html)
Fetch is the canonical way to do HTTP requests in the browser, and it can be used in other environments such as React Native. Jest Fetch Mock allows you to easily mock your `fetch` calls and return the response you need to fake the HTTP requests. It's easy to setup and you don't need a library like `nock` to get going and it uses Jest's built-in support for mocking under the surface. This means that any of the `jest.fn()` methods are also available. For more information on the jest mock API, check their docs [here](https://facebook.github.io/jest/docs/en/mock-functions.html)

It currently supports the mocking with the [`cross-fetch`](https://www.npmjs.com/package/cross-fetch) polyfill, so it supports Node.js and any browser-like runtime.

@@ -18,6 +18,7 @@ It currently supports the mocking with the [`cross-fetch`](https://www.npmjs.com
- [Mocking multiple fetches with `fetch.mockResponses`](#mocking-multiple-fetches-with-fetchmockresponses)
- [Reset mocks between tests with `fetch.resetMocks`](#reset-mocks-between-tests-with-fetchresetmocks)
- [Using `fetch.mock` to inspect the mock state of each fetch call](#using-fetchmock-to-inspect-the-mock-state-of-each-fetch-call)
- [Using functions to mock slow servers](#using-functions-to-mock-slow-servers)

## Usage

@@ -47,6 +48,37 @@ Add the setupFile to your jest config in `package.json`:
}
```

### TypeScript guide

If you are using TypeScript, then you can follow the instructions below instead.

```
$ npm install --save-dev jest-fetch-mock
```

Create a `setupJest.ts` file to setup the mock :

```ts
import {GlobalWithFetchMock} from "jest-fetch-mock";

const customGlobal: GlobalWithFetchMock = global as GlobalWithFetchMock;
customGlobal.fetch = require('jest-fetch-mock');
customGlobal.fetchMock = customGlobal.fetch;
```

Add the setupFile to your jest config in `package.json`:

```JSON
"jest": {
"automock": false,
"setupFiles": [
"./setupJest.ts"
]
}
```

With this done, you'll have `fetch` and `fetchMock` available on the global scope. Fetch will be used as usual by your code and you'll use `fetchMock` in your tests.

### Using with Create-React-App

If you are using [Create-React-App](https://github.com/facebookincubator/create-react-app) (CRA), the code for `setupTest.js` above should be placed into `src/setupTests.js` in the root of your project. CRA automatically uses this filename by convention in the Jest configuration it generates. Similarly, changing to your `package.json` is not required as CRA handles this when generating your Jest configuration.
@@ -65,13 +97,30 @@ If you are using [Create-React-App](https://github.com/facebookincubator/create-

### Mock Responses

- `fetch.mockResponse(body, init): fetch` - Mock all fetch calls
- `fetch.mockResponseOnce(body, init): fetch` - Mock each fetch call independently
- `fetch.once(body, init): fetch` - Alias for mockResponseOnce
- `fetch.mockResponse(bodyOrFunction, init): fetch` - Mock all fetch calls
- `fetch.mockResponseOnce(bodyOrFunction, init): fetch` - Mock each fetch call independently
- `fetch.once(bodyOrFunction, init): fetch` - Alias for mockResponseOnce
- `fetch.mockResponses(...responses): fetch` - Mock multiple fetch calls independently
- Each argument is an array taking `[body, init]`
- `fetch.mockReject(error): fetch` - Mock all fetch calls, letting them fail directly
- `fetch.mockRejectOnce(error): fetch` - Let the next fetch call fail directly
- Each argument is an array taking `[bodyOrFunction, init]`
- `fetch.mockReject(errorOrFunction): fetch` - Mock all fetch calls, letting them fail directly
- `fetch.mockRejectOnce(errorOrFunction): fetch` - Let the next fetch call fail directly

### Functions

Instead of passing body, it is also possible to pass a function that returns a promise.
The promise should resolve with an object containing body and init props

i.e:

```
fetch.mockResponse(() => callMyApi().then(res => ({body: res}))
```

The same goes for rejects:

```
fetch.mockReject(() => doMyAsyncJob().then(res => Promise.reject(res.errorToRaise)))
```

### Mock utilities

@@ -468,3 +517,26 @@ describe('testing api', () => {
})
})
```

### Using functions to mock slow servers

By default you will want to have your fetch mock return immediately. However if you have some custom logic that needs to tests for slower servers, you can do this by passing it a function and returning a promise when your function resolves

```js
// api.test.js
import { request } from './api'

describe('testing timeouts', () => {
it('resolves with function and timeout', async () => {
fetch.mockResponseOnce(
() => new Promise(resolve => setTimeout(() => resolve({ body: 'ok' }), 100))
)
try {
const response = await request()
expect(response).toEqual('ok')
} catch (e) {
throw e
}
})
})
```
14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"name": "jest-fetch-mock",
"version": "1.7.5",
"version": "2.1.2",
"description": "fetch mock for jest",
"main": "src/index.js",
"types": "src/index.d.ts",
"types": "types",
"scripts": {
"test": "jest"
"test": "jest && npm run tsc && npm run dtslint",
"dtslint": "dtslint types",
"tsc": "tsc"
},
"repository": {
"type": "git",
@@ -27,11 +29,15 @@
"promise-polyfill": "^7.1.1"
},
"devDependencies": {
"@types/jest": "^23.3.14",
"@types/node": "^10.12.10",
"babel-core": "^6.26.3",
"babel-jest": "^23.4.2",
"babel-preset-env": "^1.7.0",
"dtslint": "^0.3.0",
"jest": "^23.5.0",
"regenerator-runtime": "^0.12.1"
"regenerator-runtime": "^0.12.1",
"typescript": "^3.2.1"
},
"prettier": {
"semi": false,
24 changes: 0 additions & 24 deletions src/index.d.ts

This file was deleted.

36 changes: 15 additions & 21 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -36,40 +36,34 @@ function ResponseWrapper(body, init) {
return new ActualResponse(body, init)
}

const isFn = unknown => typeof unknown === 'function'

const normalizeResponse = (bodyOrFunction, init) => () => isFn(bodyOrFunction) ?
bodyOrFunction().then(({body, init}) => new ResponseWrapper(body, init)) :
Promise.resolve(new ResponseWrapper(bodyOrFunction, init))

const normalizeError = errorOrFunction => isFn(errorOrFunction) ?
errorOrFunction :
() => Promise.reject(errorOrFunction)

const fetch = jest.fn()
fetch.Headers = Headers
fetch.Response = ResponseWrapper
fetch.Request = Request
fetch.mockResponse = (body, init) => {
return fetch.mockImplementation(() =>
Promise.resolve(new ResponseWrapper(body, init))
)
}
fetch.mockResponse = (bodyOrFunction, init) => fetch.mockImplementation(normalizeResponse(bodyOrFunction, init))

fetch.mockReject = error => {
return fetch.mockImplementation(() => Promise.reject(error))
}
fetch.mockReject = errorOrFunction => fetch.mockImplementation(normalizeError(errorOrFunction))

const mockResponseOnce = (body, init) => {
return fetch.mockImplementationOnce(() =>
Promise.resolve(new ResponseWrapper(body, init))
)
}
const mockResponseOnce = (bodyOrFunction, init) => fetch.mockImplementationOnce(normalizeResponse(bodyOrFunction, init))

fetch.mockResponseOnce = mockResponseOnce

fetch.once = mockResponseOnce

fetch.mockRejectOnce = error => {
return fetch.mockImplementationOnce(() => Promise.reject(error))
}
fetch.mockRejectOnce = errorOrFunction => fetch.mockImplementationOnce(normalizeError(errorOrFunction))

fetch.mockResponses = (...responses) => {
responses.forEach(([body, init]) => {
fetch.mockImplementationOnce(() =>
Promise.resolve(new ResponseWrapper(body, init))
)
})
responses.forEach(([bodyOrFunction, init]) => fetch.mockImplementationOnce(normalizeResponse(bodyOrFunction, init)))
return fetch
}

82 changes: 82 additions & 0 deletions tests/test.js
Original file line number Diff line number Diff line change
@@ -181,4 +181,86 @@ describe('request', () => {
done()
})
})

it('resolves with function', done => {
fetch.mockResponseOnce(() => Promise.resolve({body: 'ok'}))

request()
.then(response => {
expect(response).toEqual('ok')
done()
})
.catch(done.fail)
})

it('rejects with function', done => {
const errorData = {
error:
'Uh oh, something has gone wrong. Please tweet us @randomapi about the issue. Thank you.'
}
fetch.mockRejectOnce(() => Promise.reject(JSON.stringify(errorData)))

request()
.then(done.fail)
.catch(error => {
expect(error.message).toBe(errorData.error)
done()
})
})

it('resolves with function', async () => {
fetch.mockResponseOnce(() => Promise.resolve({ body: 'ok' }))

try {
const response = await request()
expect(response).toEqual('ok')
} catch (e) {
throw e
}
})

it('resolves with function and timeout', async () => {
fetch.mockResponseOnce(
() => new Promise(resolve => setTimeout(() => resolve({ body: 'ok' }))),
100
)
try {
const response = await request()
expect(response).toEqual('ok')
} catch (e) {
throw e
}
})

it('rejects with function', async () => {
const errorData = {
error:
'Uh oh, something has gone wrong. Please tweet us @randomapi about the issue. Thank you.'
}
fetch.mockRejectOnce(() => Promise.reject(JSON.stringify(errorData)))
try {
await request()
} catch (error) {
expect(error.message).toBe(errorData.error)
}
})

it('rejects with function and timeout', async () => {
const errorData = {
error:
'Uh oh, something has gone wrong. Please tweet us @randomapi about the issue. Thank you.'
}
fetch.mockRejectOnce(
() =>
new Promise((_, reject) =>
setTimeout(() => reject(JSON.stringify(errorData)))
),
100
)
try {
await request()
} catch (error) {
expect(error.message).toBe(errorData.error)
}
})
})
12 changes: 12 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "./types/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "./types",
"paths": {
"jest-fetch-mock": [
"./"
]
}
}
}
1 change: 1 addition & 0 deletions tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }
46 changes: 46 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// TypeScript Version: 2.3
import Global = NodeJS.Global;
import "jest";

declare global {
const fetchMock: FetchMock;
namespace NodeJS {
interface Global {
fetch: FetchMock;
}
}
}

export interface GlobalWithFetchMock extends Global {
fetchMock: FetchMock;
fetch: FetchMock;
}

export interface FetchMock extends jest.MockInstance<any, any[]> {
(input?: string | Request, init?: RequestInit): Promise<Response>;

mockResponse(body: BodyOrFunction, init?: MockParams): FetchMock;
mockResponseOnce(body: BodyOrFunction, init?: MockParams): FetchMock;
once(body: BodyOrFunction, init?: MockParams): FetchMock;
mockResponses(...responses: Array<(BodyOrFunction | [BodyOrFunction, MockParams])>): FetchMock;
mockReject(error?: ErrorOrFunction): FetchMock;
mockRejectOnce(error?: ErrorOrFunction): FetchMock;
resetMocks(): void;
}

// reference: https://github.github.io/fetch/#Response
export interface MockParams {
status?: number;
statusText?: string;
headers?: string[][] | { [key: string]: string }; // HeadersInit
url?: string;
}

export interface MockResponseInit extends MockParams {
body?: string;
}

export type BodyOrFunction = string | MockResponseInitFunction;
export type ErrorOrFunction = Error | MockResponseInitFunction;

export type MockResponseInitFunction = () => Promise<MockResponseInit>;
Loading