├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── LICENSE ├── Makefile ├── README.md ├── __tests__ ├── jest-built-ins.spec.js ├── jest-extensions-delete.spec.js ├── jest-extensions-get.spec.js ├── jest-extensions-head.spec.js ├── jest-extensions-patch.spec.js ├── jest-extensions-post.spec.js ├── jest-extensions-put.spec.js ├── jest-extensions.spec.js └── regressions.spec.js ├── browser.js ├── index.d.ts ├── jest-extensions.js ├── jestify.js ├── package-lock.json ├── package.json ├── server.js └── tea.yaml /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.0 2 | references: 3 | triggerable-by-tag: &triggerable-by-tag 4 | # For a tag push unaffected by any filters, CircleCI skips the job 5 | # https://circleci.com/docs/2.0/workflows/#git-tag-job-execution 6 | filters: 7 | tags: 8 | only: /.*/ 9 | container: &container 10 | docker: 11 | - image: circleci/node:12 12 | 13 | jobs: 14 | checkout_code: 15 | <<: *container 16 | steps: 17 | - checkout 18 | - restore_cache: 19 | key: npm-cache-{{ checksum "package-lock.json" }} 20 | - run: if [ ! -d "node_modules" ]; then npm ci; fi 21 | - save_cache: 22 | key: npm-cache-{{ checksum "package-lock.json" }} 23 | paths: 24 | - node_modules 25 | 26 | lint: 27 | <<: *container 28 | steps: 29 | - checkout 30 | - restore_cache: 31 | key: npm-cache-{{ checksum "package-lock.json" }} 32 | - run: make lint-ci 33 | 34 | jest25: 35 | <<: *container 36 | steps: 37 | - checkout 38 | - restore_cache: 39 | key: npm-cache-{{ checksum "package-lock.json" }} 40 | - run: npm i jest@25 41 | - run: make test 42 | 43 | jest26: 44 | <<: *container 45 | steps: 46 | - checkout 47 | - restore_cache: 48 | key: npm-cache-{{ checksum "package-lock.json" }} 49 | - run: npm i jest@26 50 | - run: make test 51 | 52 | deploy: 53 | <<: *container 54 | steps: 55 | - checkout 56 | - restore_cache: 57 | key: npm-cache-{{ checksum "package-lock.json" }} 58 | - run: 'echo "//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}" > ${HOME}/.npmrc' 59 | - run: npm version --no-git-tag-version ${CIRCLE_TAG} 60 | - run: npm publish --access public 61 | 62 | workflows: 63 | version: 2 64 | checkout_and_test: 65 | jobs: 66 | - checkout_code: *triggerable-by-tag 67 | - lint: 68 | <<: *triggerable-by-tag 69 | requires: 70 | - checkout_code 71 | - jest25: 72 | <<: *triggerable-by-tag 73 | requires: 74 | - checkout_code 75 | - jest26: 76 | <<: *triggerable-by-tag 77 | requires: 78 | - checkout_code 79 | - deploy: 80 | context: wheresrhys-npm-publish 81 | requires: 82 | - jest25 83 | - jest26 84 | - lint 85 | filters: 86 | branches: 87 | ignore: /.*/ 88 | tags: 89 | only: /^v?\d+\.\d+\.\d+(?:-(beta|alpha)\.\d+)?$/ 90 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/fixtures/* 2 | dist/* 3 | coverage/* 4 | es5/* 5 | .nyc_output/ 6 | docs/js 7 | docs/_site 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['origami-component', 'plugin:prettier/recommended'], 3 | "env": { 4 | "browser": true, 5 | "mocha": true, 6 | "node": true 7 | }, 8 | "parserOptions": { 9 | "ecmaVersion": 2018 10 | }, 11 | "globals": { 12 | "expect": true 13 | }, 14 | rules: { 15 | 'guard-for-in': 0 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | 3 | # tooling artefacts 4 | /docs/.sass-cache/ 5 | .eslintcache 6 | npm-debug.log 7 | 8 | # test artifacts 9 | coverage/ 10 | /test/fixtures/built-sw.js 11 | .nyc_output 12 | 13 | # built files 14 | /es5 15 | /esm 16 | /cjs 17 | /docs/_site/ 18 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Rhys Evans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export PATH := $(PATH):./node_modules/.bin 2 | 3 | .PHONY: test 4 | 5 | test: 6 | jest 7 | 8 | lint-ci: 9 | eslint . 10 | prettier *.md 11 | 12 | lint: 13 | eslint --cache --fix . 14 | prettier --write *.md 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | **Deprecated - Use https://www.npmjs.com/package/@fetch-mock/jest instead. This upgrade guide will help upgrade the underlying fetch-mock instance https://www.wheresrhys.co.uk/fetch-mock/docs/Usage/upgrade-guide** 3 | 4 | # fetch-mock-jest 5 | 6 | Wrapper around [fetch-mock](http://www.wheresrhys.co.uk/fetch-mock) - a comprehensive, isomorphic mock for the [fetch api](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) - which provides an interface that is more idiomatic when working in [jest](https://jestjs.io). 7 | 8 | The example at the bottom of this readme demonstrates the intuitive API, but shows off only a fraction of fetch-mock's functionality. Features include: 9 | 10 | - mocks most of the fetch API spec, even advanced behaviours such as streaming and aborting 11 | - declarative matching for most aspects of a http request, including url, headers, body and query parameters 12 | - shorthands for the most commonly used features, such as matching a http method or matching one fetch only 13 | - support for delaying responses, or using your own async functions to define custom race conditions 14 | - can be used as a spy to observe real network requests 15 | - isomorphic, and supports either a global fetch instance or a locally required instanceg 16 | 17 | # Requirements 18 | 19 | fetch-mock-jest requires the following to run: 20 | 21 | - [Node.js](https://Node.js.org/) 8+ for full feature operation 22 | - [Node.js](https://Node.js.org/) 0.12+ with [limitations](http://www.wheresrhys.co.uk/fetch-mock/installation) 23 | - [npm](https://www.npmjs.com/package/npm) (normally comes with Node.js) 24 | - [jest](https://www.npmjs.com/package/jest) 25+ (may work with earlier versions, but untested) 25 | - Either 26 | - [node-fetch](https://www.npmjs.com/package/node-fetch) when testing in Node.js. To allow users a choice over which version to use, `node-fetch` is not included as a dependency of `fetch-mock`. 27 | - A browser that supports the `fetch` API either natively or via a [polyfill/ponyfill](https://ponyfoo.com/articles/polyfills-or-ponyfills) 28 | 29 | # Installation 30 | 31 | `npm install -D fetch-mock-jest` 32 | 33 | ## global fetch 34 | 35 | `const fetchMock = require('fetch-mock-jest')` 36 | 37 | ## node-fetch 38 | 39 | ``` 40 | jest.mock('node-fetch', () => require('fetch-mock-jest').sandbox()) 41 | const fetchMock = require('node-fetch') 42 | ``` 43 | 44 | # API 45 | 46 | ## Setting up mocks 47 | 48 | Please refer to the [fetch-mock documentation](http://wheresrhys.co.uk/fetch-mock) and [cheatsheet](https://github.com/wheresrhys/fetch-mock/blob/master/docs/cheatsheet.md) 49 | 50 | All jest methods for configuring mock functions are disabled as fetch-mock's own methods should always be used 51 | 52 | ## Inspecting mocks 53 | 54 | All the built in jest function inspection assertions can be used, e.g. `expect(fetchMock).toHaveBeenCalledWith('http://example.com')`. 55 | 56 | `fetchMock.mock.calls` and `fetchMock.mock.results` are also exposed, giving access to manually inspect the calls. 57 | 58 | The following custom jest expectation methods, proxying through to `fetch-mock`'s inspection methods are also available. They can all be prefixed with the `.not` helper for negative assertions. 59 | 60 | - `expect(fetchMock).toHaveFetched(filter, options)` 61 | - `expect(fetchMock).toHaveLastFetched(filter, options)` 62 | - `expect(fetchMock).toHaveNthFetched(n, filter, options)` 63 | - `expect(fetchMock).toHaveFetchedTimes(n, filter, options)` 64 | - `expect(fetchMock).toBeDone(filter)` 65 | 66 | ### Notes 67 | 68 | - `filter` and `options` are the same as those used by [`fetch-mock`'s inspection methods](http://www.wheresrhys.co.uk/fetch-mock/#api-inspectionfundamentals) 69 | - The obove methods can have `Fetched` replaced by any of the following verbs to scope to a particular method: + Got + Posted + Put + Deleted + FetchedHead + Patched 70 | 71 | e.g. `expect(fetchMock).toHaveLastPatched(filter, options)` 72 | 73 | ## Tearing down mocks 74 | 75 | `fetchMock.mockClear()` can be used to reset the call history 76 | 77 | `fetchMock.mockReset()` can be used to remove all configured mocks 78 | 79 | Please report any bugs in resetting mocks on the [issues board](https://github.com/wheresrhys/fetch-mock-jest/issues) 80 | 81 | # Example 82 | 83 | ```js 84 | const fetchMock = require('fetch-mock-jest'); 85 | const userManager = require('../src/user-manager'); 86 | 87 | test(async () => { 88 | const users = [{ name: 'bob' }]; 89 | fetchMock 90 | .get('http://example.com/users', users) 91 | .post('http://example.com/user', (url, options) => { 92 | if (typeof options.body.name === 'string') { 93 | users.push(options.body); 94 | return 202; 95 | } 96 | return 400; 97 | }) 98 | .patch( 99 | { 100 | url: 'http://example.com/user' 101 | }, 102 | 405 103 | ); 104 | 105 | expect(await userManager.getAll()).toEqual([{ name: 'bob' }]); 106 | expect(fetchMock).toHaveLastFetched('http://example.com/users 107 | get'); 108 | await userManager.create({ name: true }); 109 | expect(fetchMock).toHaveLastFetched( 110 | { 111 | url: 'http://example.com/user', 112 | body: { name: true } 113 | }, 114 | 'post' 115 | ); 116 | expect(await userManager.getAll()).toEqual([{ name: 'bob' }]); 117 | fetchMock.mockClear(); 118 | await userManager.create({ name: 'sarah' }); 119 | expect(fetchMock).toHaveLastFetched( 120 | { 121 | url: 'http://example.com/user', 122 | body: { name: 'sarah' } 123 | }, 124 | 'post' 125 | ); 126 | expect(await userManager.getAll()).toEqual([ 127 | { name: 'bob' }, 128 | { name: 'sarah' } 129 | ]); 130 | fetchMock.mockReset(); 131 | }); 132 | ``` 133 | -------------------------------------------------------------------------------- /__tests__/jest-built-ins.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest, beforeAll, afterAll */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | describe('jest built-ins', () => { 5 | describe('exposing mock internals', () => { 6 | beforeAll(() => { 7 | fetch.mock('http://example.com', 200).mock('http://example2.com', 201); 8 | fetch('http://example.com', { 9 | headers: { 10 | test: 'header', 11 | }, 12 | }); 13 | fetch('http://example2.com', { 14 | headers: { 15 | test: 'header2', 16 | }, 17 | }); 18 | }); 19 | 20 | afterAll(() => fetch.reset()); 21 | it('exposes `calls` property', () => { 22 | expect(fetch.mock.calls).toBeDefined(); 23 | expect(fetch.mock.calls.length).toBe(2); 24 | expect(fetch.mock.calls).toMatchObject([ 25 | [ 26 | 'http://example.com', 27 | { 28 | headers: { 29 | test: 'header', 30 | }, 31 | }, 32 | ], 33 | [ 34 | 'http://example2.com', 35 | { 36 | headers: { 37 | test: 'header2', 38 | }, 39 | }, 40 | ], 41 | ]); 42 | }); 43 | it('exposes `results` property', async () => { 44 | expect(fetch.mock.results).toBeDefined(); 45 | expect(fetch.mock.results.length).toEqual(2); 46 | expect(await fetch.mock.results[0].value).toMatchObject({ 47 | status: 200, 48 | }); 49 | expect(await fetch.mock.results[1].value).toMatchObject({ 50 | status: 201, 51 | }); 52 | }); 53 | }); 54 | 55 | describe('clearing', () => { 56 | beforeEach(() => { 57 | fetch.mock('http://example.com', 200).mock('http://example2.com', 201); 58 | fetch('http://example.com', { 59 | headers: { 60 | test: 'header', 61 | }, 62 | }); 63 | fetch('http://example2.com', { 64 | headers: { 65 | test: 'header2', 66 | }, 67 | }); 68 | }); 69 | 70 | afterEach(() => fetch.reset()); 71 | it('mockClear', () => { 72 | expect(fetch.mockClear).toBeDefined(); 73 | fetch.mockClear(); 74 | expect(fetch.mock.calls.length).toEqual(0); 75 | expect(fetch._calls.length).toEqual(0); 76 | expect(fetch.routes.length).toEqual(2); 77 | }); 78 | it('mockReset', () => { 79 | expect(fetch.mockReset).toBeDefined(); 80 | fetch.mockReset(); 81 | expect(fetch.mock.calls.length).toEqual(0); 82 | expect(fetch._calls.length).toEqual(0); 83 | expect(fetch.routes.length).toEqual(0); 84 | }); 85 | it('mockRestore', () => { 86 | expect(() => fetch.mockRestore()).toThrow( 87 | "mockRestore not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 88 | ); 89 | }); 90 | it('mockImplementation', () => { 91 | expect(() => fetch.mockImplementation()).toThrow( 92 | "mockImplementation not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 93 | ); 94 | }); 95 | it('mockImplementationOnce', () => { 96 | expect(() => fetch.mockImplementationOnce()).toThrow( 97 | "mockImplementationOnce not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 98 | ); 99 | }); 100 | it('mockName', () => { 101 | expect(() => fetch.mockName()).toThrow( 102 | "mockName not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 103 | ); 104 | }); 105 | it('mockReturnThis', () => { 106 | expect(() => fetch.mockReturnThis()).toThrow( 107 | "mockReturnThis not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 108 | ); 109 | }); 110 | it('mockReturnValue', () => { 111 | expect(() => fetch.mockReturnValue()).toThrow( 112 | "mockReturnValue not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 113 | ); 114 | }); 115 | it('mockReturnValueOnce', () => { 116 | expect(() => fetch.mockReturnValueOnce()).toThrow( 117 | "mockReturnValueOnce not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 118 | ); 119 | }); 120 | it('mockResolvedValue', () => { 121 | expect(() => fetch.mockResolvedValue()).toThrow( 122 | "mockResolvedValue not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 123 | ); 124 | }); 125 | it('mockResolvedValueOnce', () => { 126 | expect(() => fetch.mockResolvedValueOnce()).toThrow( 127 | "mockResolvedValueOnce not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 128 | ); 129 | }); 130 | it('mockRejectedValue', () => { 131 | expect(() => fetch.mockRejectedValue()).toThrow( 132 | "mockRejectedValue not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 133 | ); 134 | }); 135 | it('mockRejectedValueOnce', () => { 136 | expect(() => fetch.mockRejectedValueOnce()).toThrow( 137 | "mockRejectedValueOnce not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 138 | ); 139 | }); 140 | }); 141 | describe('native jest mock function inspectors', () => { 142 | it('.toHaveBeenCalled()', () => { 143 | expect(() => expect(fetch).toHaveBeenCalled()).not.toThrow(); 144 | }); 145 | // Just want to get the fix out for calling fetch methods 146 | // These will all work as the basic mechanism is fixed, but 147 | // no time to set up all th etest cases now 148 | it.skip('.toHaveBeenCalledTimes(number)', () => { 149 | expect(() => expect(fetch).toHaveBeenCalledTimes(1)).not.toThrow(); 150 | }); 151 | it.skip('.toHaveBeenCalledWith(arg1, arg2, ...)', () => { 152 | expect(() => expect(fetch).toHaveBeenCalledWith(1)).not.toThrow(); 153 | }); 154 | it.skip('.toHaveBeenLastCalledWith(arg1, arg2, ...)', () => { 155 | expect(() => expect(fetch).toHaveBeenLastCalledWith(1)).not.toThrow(); 156 | }); 157 | it.skip('.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)', () => { 158 | expect(() => expect(fetch).toHaveBeenNthCalledWith(1, 1)).not.toThrow(); 159 | }); 160 | it.skip('.toHaveReturned()', () => { 161 | expect(() => expect(fetch).toHaveReturned()).not.toThrow(); 162 | }); 163 | it.skip('.toHaveReturnedTimes(number)', () => { 164 | expect(() => expect(fetch).toHaveReturnedTimes(1)).not.toThrow(); 165 | }); 166 | it.skip('.toHaveReturnedWith(value)', () => { 167 | expect(() => expect(fetch).toHaveReturnedWith(1)).not.toThrow(); 168 | }); 169 | it.skip('.toHaveLastReturnedWith(value)', () => { 170 | expect(() => expect(fetch).toHaveLastReturnedWith(1)).not.toThrow(); 171 | }); 172 | it.skip('.toHaveNthReturnedWith(nthCall, value)', () => { 173 | expect(() => expect(fetch).toHaveNthReturnedWith(1, 1)).not.toThrow(); 174 | }); 175 | }); 176 | }); 177 | -------------------------------------------------------------------------------- /__tests__/jest-extensions-delete.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest, beforeAll, afterAll */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | describe('jest extensions - delete', () => { 5 | describe('when no calls', () => { 6 | beforeAll(() => { 7 | fetch.mock('*', 200); 8 | fetch('http://lala'); 9 | }); 10 | afterAll(() => fetch.reset()); 11 | it('toHaveDeleted should be falsy', () => { 12 | expect(fetch).not.toHaveDeleted('http://example.com/path'); 13 | }); 14 | 15 | it('toHaveLastDeleted should be falsy', () => { 16 | expect(fetch).not.toHaveLastDeleted('http://example.com/path'); 17 | }); 18 | 19 | it('toHaveNthDeleted should be falsy', () => { 20 | expect(fetch).not.toHaveNthDeleted(1, 'http://example.com/path'); 21 | }); 22 | 23 | it('toHaveDeletedTimes should be falsy', () => { 24 | expect(fetch).not.toHaveDeletedTimes(1, 'http://example.com/path'); 25 | }); 26 | 27 | it('toBeDone should be falsy', () => { 28 | expect(fetch).not.toBeDone('http://example.com/path'); 29 | }); 30 | }); 31 | describe('toHaveDeleted', () => { 32 | beforeAll(() => { 33 | fetch.mock('*', 200); 34 | fetch('http://example.com/path2', { 35 | method: 'delete', 36 | headers: { 37 | test: 'header', 38 | }, 39 | }); 40 | fetch('http://example.com/path', { 41 | method: 'delete', 42 | headers: { 43 | test: 'header', 44 | }, 45 | }); 46 | }); 47 | afterAll(() => fetch.reset()); 48 | 49 | it('matches with just url', () => { 50 | expect(fetch).toHaveDeleted('http://example.com/path'); 51 | }); 52 | 53 | it('matches with fetch-mock matcher', () => { 54 | expect(fetch).toHaveDeleted('begin:http://example.com/path'); 55 | }); 56 | 57 | it('matches with matcher and options', () => { 58 | expect(fetch).toHaveDeleted('http://example.com/path', { 59 | method: 'delete', 60 | headers: { 61 | test: 'header', 62 | }, 63 | }); 64 | }); 65 | 66 | it("doesn't match if matcher but not options is correct", () => { 67 | expect(fetch).not.toHaveDeleted('http://example.com/path', { 68 | method: 'delete', 69 | headers: { 70 | test: 'not-header', 71 | }, 72 | }); 73 | }); 74 | 75 | it("doesn't match if options but not matcher is correct", () => { 76 | expect(fetch).not.toHaveDeleted('http://example-no.com/path', { 77 | method: 'delete', 78 | headers: { 79 | test: 'header', 80 | }, 81 | }); 82 | }); 83 | }); 84 | describe('toHaveLastDeleted', () => { 85 | beforeAll(() => { 86 | fetch.mock('*', 200); 87 | fetch('http://example.com/path', { 88 | method: 'delete', 89 | headers: { 90 | test: 'header', 91 | }, 92 | }); 93 | }); 94 | afterAll(() => fetch.reset()); 95 | 96 | it('matches with just url', () => { 97 | expect(fetch).toHaveLastDeleted('http://example.com/path'); 98 | }); 99 | 100 | it('matches with fetch-mock matcher', () => { 101 | expect(fetch).toHaveLastDeleted('begin:http://example.com/path'); 102 | }); 103 | 104 | it('matches with matcher and options', () => { 105 | expect(fetch).toHaveLastDeleted('http://example.com/path', { 106 | method: 'delete', 107 | headers: { 108 | test: 'header', 109 | }, 110 | }); 111 | }); 112 | 113 | it("doesn't match if matcher but not options is correct", () => { 114 | expect(fetch).not.toHaveLastDeleted('http://example.com/path', { 115 | method: 'delete', 116 | headers: { 117 | test: 'not-header', 118 | }, 119 | }); 120 | }); 121 | 122 | it("doesn't match if options but not matcher is correct", () => { 123 | expect(fetch).not.toHaveLastDeleted('http://example-no.com/path', { 124 | method: 'delete', 125 | headers: { 126 | test: 'header', 127 | }, 128 | }); 129 | }); 130 | }); 131 | 132 | describe('toHaveNthDeleted', () => { 133 | beforeAll(() => { 134 | fetch.mock('*', 200); 135 | fetch('http://example1.com/path', { 136 | method: 'delete', 137 | headers: { 138 | test: 'header', 139 | }, 140 | }); 141 | fetch('http://example2.com/path', { 142 | method: 'delete', 143 | headers: { 144 | test: 'header', 145 | }, 146 | }); 147 | }); 148 | afterAll(() => fetch.reset()); 149 | 150 | it('matches with just url', () => { 151 | expect(fetch).toHaveNthDeleted(2, 'http://example2.com/path'); 152 | }); 153 | 154 | it('matches with fetch-mock matcher', () => { 155 | expect(fetch).toHaveNthDeleted(2, 'begin:http://example2.com/path'); 156 | }); 157 | 158 | it('matches with matcher and options', () => { 159 | expect(fetch).toHaveNthDeleted(2, 'http://example2.com/path', { 160 | method: 'delete', 161 | headers: { 162 | test: 'header', 163 | }, 164 | }); 165 | }); 166 | 167 | it("doesn't match if matcher but not options is correct", () => { 168 | expect(fetch).not.toHaveNthDeleted(2, 'http://example2.com/path', { 169 | method: 'delete', 170 | headers: { 171 | test: 'not-header', 172 | }, 173 | }); 174 | }); 175 | 176 | it("doesn't match if options but not matcher is correct", () => { 177 | expect(fetch).not.toHaveNthDeleted(2, 'http://example-no.com/path', { 178 | method: 'delete', 179 | headers: { 180 | test: 'header', 181 | }, 182 | }); 183 | }); 184 | 185 | it("doesn't match if wrong n", () => { 186 | expect(fetch).not.toHaveNthDeleted(1, 'http://example2.com/path'); 187 | }); 188 | }); 189 | 190 | describe('toHaveDeletedTimes', () => { 191 | beforeAll(() => { 192 | fetch.mock('*', 200); 193 | fetch('http://example.com/path', { 194 | method: 'delete', 195 | headers: { 196 | test: 'header', 197 | }, 198 | }); 199 | fetch('http://example.com/path', { 200 | method: 'delete', 201 | headers: { 202 | test: 'header', 203 | }, 204 | }); 205 | }); 206 | afterAll(() => fetch.reset()); 207 | 208 | it('matches with just url', () => { 209 | expect(fetch).toHaveDeletedTimes(2, 'http://example.com/path'); 210 | }); 211 | 212 | it('matches with fetch-mock matcher', () => { 213 | expect(fetch).toHaveDeletedTimes(2, 'begin:http://example.com/path'); 214 | }); 215 | 216 | it('matches with matcher and options', () => { 217 | expect(fetch).toHaveDeletedTimes(2, 'http://example.com/path', { 218 | method: 'delete', 219 | headers: { 220 | test: 'header', 221 | }, 222 | }); 223 | }); 224 | 225 | it("doesn't match if matcher but not options is correct", () => { 226 | expect(fetch).not.toHaveDeletedTimes(2, 'http://example.com/path', { 227 | method: 'delete', 228 | headers: { 229 | test: 'not-header', 230 | }, 231 | }); 232 | }); 233 | 234 | it("doesn't match if options but not matcher is correct", () => { 235 | expect(fetch).not.toHaveDeletedTimes(2, 'http://example-no.com/path', { 236 | method: 'delete', 237 | headers: { 238 | test: 'header', 239 | }, 240 | }); 241 | }); 242 | 243 | it("doesn't match if too few calls", () => { 244 | expect(fetch).not.toHaveDeletedTimes(1, 'http://example.com/path'); 245 | }); 246 | 247 | it("doesn't match if too many calls", () => { 248 | expect(fetch).not.toHaveDeletedTimes(3, 'http://example.com/path'); 249 | }); 250 | }); 251 | }); 252 | -------------------------------------------------------------------------------- /__tests__/jest-extensions-get.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest, beforeAll, afterAll */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | describe('jest extensions - get', () => { 5 | describe('when no calls', () => { 6 | beforeAll(() => { 7 | fetch.mock('*', 200); 8 | fetch('http://lala', { method: 'post' }); 9 | }); 10 | afterAll(() => fetch.reset()); 11 | it('toHaveGot should be falsy', () => { 12 | expect(fetch).not.toHaveGot('http://example.com/path'); 13 | }); 14 | 15 | it('toHaveLastGot should be falsy', () => { 16 | expect(fetch).not.toHaveLastGot('http://example.com/path'); 17 | }); 18 | 19 | it('toHaveNthGot should be falsy', () => { 20 | expect(fetch).not.toHaveNthGot(1, 'http://example.com/path'); 21 | }); 22 | 23 | it('toHaveGotTimes should be falsy', () => { 24 | expect(fetch).not.toHaveGotTimes(1, 'http://example.com/path'); 25 | }); 26 | 27 | it('toBeDone should be falsy', () => { 28 | expect(fetch).not.toBeDone('http://example.com/path'); 29 | }); 30 | }); 31 | describe('toHaveGot', () => { 32 | beforeAll(() => { 33 | fetch.mock('*', 200); 34 | fetch('http://example.com/path2', { 35 | method: 'get', 36 | headers: { 37 | test: 'header', 38 | }, 39 | }); 40 | fetch('http://example.com/path', { 41 | method: 'get', 42 | headers: { 43 | test: 'header', 44 | }, 45 | }); 46 | }); 47 | afterAll(() => fetch.reset()); 48 | 49 | it('matches with just url', () => { 50 | expect(fetch).toHaveGot('http://example.com/path'); 51 | }); 52 | 53 | it('matches with fetch-mock matcher', () => { 54 | expect(fetch).toHaveGot('begin:http://example.com/path'); 55 | }); 56 | 57 | it('matches with matcher and options', () => { 58 | expect(fetch).toHaveGot('http://example.com/path', { 59 | method: 'get', 60 | headers: { 61 | test: 'header', 62 | }, 63 | }); 64 | }); 65 | 66 | it("doesn't match if matcher but not options is correct", () => { 67 | expect(fetch).not.toHaveGot('http://example.com/path', { 68 | method: 'get', 69 | headers: { 70 | test: 'not-header', 71 | }, 72 | }); 73 | }); 74 | 75 | it("doesn't match if options but not matcher is correct", () => { 76 | expect(fetch).not.toHaveGot('http://example-no.com/path', { 77 | method: 'get', 78 | headers: { 79 | test: 'header', 80 | }, 81 | }); 82 | }); 83 | }); 84 | describe('toHaveLastGot', () => { 85 | beforeAll(() => { 86 | fetch.mock('*', 200); 87 | fetch('http://example.com/path', { 88 | method: 'get', 89 | headers: { 90 | test: 'header', 91 | }, 92 | }); 93 | }); 94 | afterAll(() => fetch.reset()); 95 | 96 | it('matches with just url', () => { 97 | expect(fetch).toHaveLastGot('http://example.com/path'); 98 | }); 99 | 100 | it('matches with fetch-mock matcher', () => { 101 | expect(fetch).toHaveLastGot('begin:http://example.com/path'); 102 | }); 103 | 104 | it('matches with matcher and options', () => { 105 | expect(fetch).toHaveLastGot('http://example.com/path', { 106 | method: 'get', 107 | headers: { 108 | test: 'header', 109 | }, 110 | }); 111 | }); 112 | 113 | it("doesn't match if matcher but not options is correct", () => { 114 | expect(fetch).not.toHaveLastGot('http://example.com/path', { 115 | method: 'get', 116 | headers: { 117 | test: 'not-header', 118 | }, 119 | }); 120 | }); 121 | 122 | it("doesn't match if options but not matcher is correct", () => { 123 | expect(fetch).not.toHaveLastGot('http://example-no.com/path', { 124 | method: 'get', 125 | headers: { 126 | test: 'header', 127 | }, 128 | }); 129 | }); 130 | }); 131 | 132 | describe('toHaveNthGot', () => { 133 | beforeAll(() => { 134 | fetch.mock('*', 200); 135 | fetch('http://example1.com/path', { 136 | method: 'get', 137 | headers: { 138 | test: 'header', 139 | }, 140 | }); 141 | fetch('http://example2.com/path', { 142 | method: 'get', 143 | headers: { 144 | test: 'header', 145 | }, 146 | }); 147 | }); 148 | afterAll(() => fetch.reset()); 149 | 150 | it('matches with just url', () => { 151 | expect(fetch).toHaveNthGot(2, 'http://example2.com/path'); 152 | }); 153 | 154 | it('matches with fetch-mock matcher', () => { 155 | expect(fetch).toHaveNthGot(2, 'begin:http://example2.com/path'); 156 | }); 157 | 158 | it('matches with matcher and options', () => { 159 | expect(fetch).toHaveNthGot(2, 'http://example2.com/path', { 160 | method: 'get', 161 | headers: { 162 | test: 'header', 163 | }, 164 | }); 165 | }); 166 | 167 | it("doesn't match if matcher but not options is correct", () => { 168 | expect(fetch).not.toHaveNthGot(2, 'http://example2.com/path', { 169 | method: 'get', 170 | headers: { 171 | test: 'not-header', 172 | }, 173 | }); 174 | }); 175 | 176 | it("doesn't match if options but not matcher is correct", () => { 177 | expect(fetch).not.toHaveNthGot(2, 'http://example-no.com/path', { 178 | method: 'get', 179 | headers: { 180 | test: 'header', 181 | }, 182 | }); 183 | }); 184 | 185 | it("doesn't match if wrong n", () => { 186 | expect(fetch).not.toHaveNthGot(1, 'http://example2.com/path'); 187 | }); 188 | }); 189 | 190 | describe('toHaveGotTimes', () => { 191 | beforeAll(() => { 192 | fetch.mock('*', 200); 193 | fetch('http://example.com/path', { 194 | method: 'get', 195 | headers: { 196 | test: 'header', 197 | }, 198 | }); 199 | fetch('http://example.com/path', { 200 | method: 'get', 201 | headers: { 202 | test: 'header', 203 | }, 204 | }); 205 | }); 206 | afterAll(() => fetch.reset()); 207 | 208 | it('matches with just url', () => { 209 | expect(fetch).toHaveGotTimes(2, 'http://example.com/path'); 210 | }); 211 | 212 | it('matches with fetch-mock matcher', () => { 213 | expect(fetch).toHaveGotTimes(2, 'begin:http://example.com/path'); 214 | }); 215 | 216 | it('matches with matcher and options', () => { 217 | expect(fetch).toHaveGotTimes(2, 'http://example.com/path', { 218 | method: 'get', 219 | headers: { 220 | test: 'header', 221 | }, 222 | }); 223 | }); 224 | 225 | it("doesn't match if matcher but not options is correct", () => { 226 | expect(fetch).not.toHaveGotTimes(2, 'http://example.com/path', { 227 | method: 'get', 228 | headers: { 229 | test: 'not-header', 230 | }, 231 | }); 232 | }); 233 | 234 | it("doesn't match if options but not matcher is correct", () => { 235 | expect(fetch).not.toHaveGotTimes(2, 'http://example-no.com/path', { 236 | method: 'get', 237 | headers: { 238 | test: 'header', 239 | }, 240 | }); 241 | }); 242 | 243 | it("doesn't match if too few calls", () => { 244 | expect(fetch).not.toHaveGotTimes(1, 'http://example.com/path'); 245 | }); 246 | 247 | it("doesn't match if too many calls", () => { 248 | expect(fetch).not.toHaveGotTimes(3, 'http://example.com/path'); 249 | }); 250 | }); 251 | }); 252 | -------------------------------------------------------------------------------- /__tests__/jest-extensions-head.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest, beforeAll, afterAll */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | describe('jest extensions - head', () => { 5 | describe('when no calls', () => { 6 | beforeAll(() => { 7 | fetch.mock('*', 200); 8 | fetch('http://lala'); 9 | }); 10 | afterAll(() => fetch.reset()); 11 | it('toHaveFetchedHead should be falsy', () => { 12 | expect(fetch).not.toHaveFetchedHead('http://example.com/path'); 13 | }); 14 | 15 | it('toHaveLastFetchedHead should be falsy', () => { 16 | expect(fetch).not.toHaveLastFetchedHead('http://example.com/path'); 17 | }); 18 | 19 | it('toHaveNthFetchedHead should be falsy', () => { 20 | expect(fetch).not.toHaveNthFetchedHead(1, 'http://example.com/path'); 21 | }); 22 | 23 | it('toHaveFetchedHeadTimes should be falsy', () => { 24 | expect(fetch).not.toHaveFetchedHeadTimes(1, 'http://example.com/path'); 25 | }); 26 | 27 | it('toBeDone should be falsy', () => { 28 | expect(fetch).not.toBeDone('http://example.com/path'); 29 | }); 30 | }); 31 | describe('toHaveFetchedHead', () => { 32 | beforeAll(() => { 33 | fetch.mock('*', 200); 34 | fetch('http://example.com/path2', { 35 | method: 'head', 36 | headers: { 37 | test: 'header', 38 | }, 39 | }); 40 | fetch('http://example.com/path', { 41 | method: 'head', 42 | headers: { 43 | test: 'header', 44 | }, 45 | }); 46 | }); 47 | afterAll(() => fetch.reset()); 48 | 49 | it('matches with just url', () => { 50 | expect(fetch).toHaveFetchedHead('http://example.com/path'); 51 | }); 52 | 53 | it('matches with fetch-mock matcher', () => { 54 | expect(fetch).toHaveFetchedHead('begin:http://example.com/path'); 55 | }); 56 | 57 | it('matches with matcher and options', () => { 58 | expect(fetch).toHaveFetchedHead('http://example.com/path', { 59 | method: 'head', 60 | headers: { 61 | test: 'header', 62 | }, 63 | }); 64 | }); 65 | 66 | it("doesn't match if matcher but not options is correct", () => { 67 | expect(fetch).not.toHaveFetchedHead('http://example.com/path', { 68 | method: 'head', 69 | headers: { 70 | test: 'not-header', 71 | }, 72 | }); 73 | }); 74 | 75 | it("doesn't match if options but not matcher is correct", () => { 76 | expect(fetch).not.toHaveFetchedHead('http://example-no.com/path', { 77 | method: 'head', 78 | headers: { 79 | test: 'header', 80 | }, 81 | }); 82 | }); 83 | }); 84 | describe('toHaveLastFetchedHead', () => { 85 | beforeAll(() => { 86 | fetch.mock('*', 200); 87 | fetch('http://example.com/path', { 88 | method: 'head', 89 | headers: { 90 | test: 'header', 91 | }, 92 | }); 93 | }); 94 | afterAll(() => fetch.reset()); 95 | 96 | it('matches with just url', () => { 97 | expect(fetch).toHaveLastFetchedHead('http://example.com/path'); 98 | }); 99 | 100 | it('matches with fetch-mock matcher', () => { 101 | expect(fetch).toHaveLastFetchedHead('begin:http://example.com/path'); 102 | }); 103 | 104 | it('matches with matcher and options', () => { 105 | expect(fetch).toHaveLastFetchedHead('http://example.com/path', { 106 | method: 'head', 107 | headers: { 108 | test: 'header', 109 | }, 110 | }); 111 | }); 112 | 113 | it("doesn't match if matcher but not options is correct", () => { 114 | expect(fetch).not.toHaveLastFetchedHead('http://example.com/path', { 115 | method: 'head', 116 | headers: { 117 | test: 'not-header', 118 | }, 119 | }); 120 | }); 121 | 122 | it("doesn't match if options but not matcher is correct", () => { 123 | expect(fetch).not.toHaveLastFetchedHead('http://example-no.com/path', { 124 | method: 'head', 125 | headers: { 126 | test: 'header', 127 | }, 128 | }); 129 | }); 130 | }); 131 | 132 | describe('toHaveNthFetchedHead', () => { 133 | beforeAll(() => { 134 | fetch.mock('*', 200); 135 | fetch('http://example1.com/path', { 136 | method: 'head', 137 | headers: { 138 | test: 'header', 139 | }, 140 | }); 141 | fetch('http://example2.com/path', { 142 | method: 'head', 143 | headers: { 144 | test: 'header', 145 | }, 146 | }); 147 | }); 148 | afterAll(() => fetch.reset()); 149 | 150 | it('matches with just url', () => { 151 | expect(fetch).toHaveNthFetchedHead(2, 'http://example2.com/path'); 152 | }); 153 | 154 | it('matches with fetch-mock matcher', () => { 155 | expect(fetch).toHaveNthFetchedHead(2, 'begin:http://example2.com/path'); 156 | }); 157 | 158 | it('matches with matcher and options', () => { 159 | expect(fetch).toHaveNthFetchedHead(2, 'http://example2.com/path', { 160 | method: 'head', 161 | headers: { 162 | test: 'header', 163 | }, 164 | }); 165 | }); 166 | 167 | it("doesn't match if matcher but not options is correct", () => { 168 | expect(fetch).not.toHaveNthFetchedHead(2, 'http://example2.com/path', { 169 | method: 'head', 170 | headers: { 171 | test: 'not-header', 172 | }, 173 | }); 174 | }); 175 | 176 | it("doesn't match if options but not matcher is correct", () => { 177 | expect(fetch).not.toHaveNthFetchedHead(2, 'http://example-no.com/path', { 178 | method: 'head', 179 | headers: { 180 | test: 'header', 181 | }, 182 | }); 183 | }); 184 | 185 | it("doesn't match if wrong n", () => { 186 | expect(fetch).not.toHaveNthFetchedHead(1, 'http://example2.com/path'); 187 | }); 188 | }); 189 | 190 | describe('toHaveFetchedHeadTimes', () => { 191 | beforeAll(() => { 192 | fetch.mock('*', 200); 193 | fetch('http://example.com/path', { 194 | method: 'head', 195 | headers: { 196 | test: 'header', 197 | }, 198 | }); 199 | fetch('http://example.com/path', { 200 | method: 'head', 201 | headers: { 202 | test: 'header', 203 | }, 204 | }); 205 | }); 206 | afterAll(() => fetch.reset()); 207 | 208 | it('matches with just url', () => { 209 | expect(fetch).toHaveFetchedHeadTimes(2, 'http://example.com/path'); 210 | }); 211 | 212 | it('matches with fetch-mock matcher', () => { 213 | expect(fetch).toHaveFetchedHeadTimes(2, 'begin:http://example.com/path'); 214 | }); 215 | 216 | it('matches with matcher and options', () => { 217 | expect(fetch).toHaveFetchedHeadTimes(2, 'http://example.com/path', { 218 | method: 'head', 219 | headers: { 220 | test: 'header', 221 | }, 222 | }); 223 | }); 224 | 225 | it("doesn't match if matcher but not options is correct", () => { 226 | expect(fetch).not.toHaveFetchedHeadTimes(2, 'http://example.com/path', { 227 | method: 'head', 228 | headers: { 229 | test: 'not-header', 230 | }, 231 | }); 232 | }); 233 | 234 | it("doesn't match if options but not matcher is correct", () => { 235 | expect(fetch).not.toHaveFetchedHeadTimes( 236 | 2, 237 | 'http://example-no.com/path', 238 | { 239 | method: 'head', 240 | headers: { 241 | test: 'header', 242 | }, 243 | } 244 | ); 245 | }); 246 | 247 | it("doesn't match if too few calls", () => { 248 | expect(fetch).not.toHaveFetchedHeadTimes(1, 'http://example.com/path'); 249 | }); 250 | 251 | it("doesn't match if too many calls", () => { 252 | expect(fetch).not.toHaveFetchedHeadTimes(3, 'http://example.com/path'); 253 | }); 254 | }); 255 | }); 256 | -------------------------------------------------------------------------------- /__tests__/jest-extensions-patch.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest, beforeAll, afterAll */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | describe('jest extensions - patch', () => { 5 | describe('when no calls', () => { 6 | beforeAll(() => { 7 | fetch.mock('*', 200); 8 | fetch('http://lala'); 9 | }); 10 | afterAll(() => fetch.reset()); 11 | it('toHavePatched should be falsy', () => { 12 | expect(fetch).not.toHavePatched('http://example.com/path'); 13 | }); 14 | 15 | it('toHaveLastPatched should be falsy', () => { 16 | expect(fetch).not.toHaveLastPatched('http://example.com/path'); 17 | }); 18 | 19 | it('toHaveNthPatched should be falsy', () => { 20 | expect(fetch).not.toHaveNthPatched(1, 'http://example.com/path'); 21 | }); 22 | 23 | it('toHavePatchedTimes should be falsy', () => { 24 | expect(fetch).not.toHavePatchedTimes(1, 'http://example.com/path'); 25 | }); 26 | 27 | it('toBeDone should be falsy', () => { 28 | expect(fetch).not.toBeDone('http://example.com/path'); 29 | }); 30 | }); 31 | describe('toHavePatched', () => { 32 | beforeAll(() => { 33 | fetch.mock('*', 200); 34 | fetch('http://example.com/path2', { 35 | method: 'patch', 36 | headers: { 37 | test: 'header', 38 | }, 39 | }); 40 | fetch('http://example.com/path', { 41 | method: 'patch', 42 | headers: { 43 | test: 'header', 44 | }, 45 | }); 46 | }); 47 | afterAll(() => fetch.reset()); 48 | 49 | it('matches with just url', () => { 50 | expect(fetch).toHavePatched('http://example.com/path'); 51 | }); 52 | 53 | it('matches with fetch-mock matcher', () => { 54 | expect(fetch).toHavePatched('begin:http://example.com/path'); 55 | }); 56 | 57 | it('matches with matcher and options', () => { 58 | expect(fetch).toHavePatched('http://example.com/path', { 59 | method: 'patch', 60 | headers: { 61 | test: 'header', 62 | }, 63 | }); 64 | }); 65 | 66 | it("doesn't match if matcher but not options is correct", () => { 67 | expect(fetch).not.toHavePatched('http://example.com/path', { 68 | method: 'patch', 69 | headers: { 70 | test: 'not-header', 71 | }, 72 | }); 73 | }); 74 | 75 | it("doesn't match if options but not matcher is correct", () => { 76 | expect(fetch).not.toHavePatched('http://example-no.com/path', { 77 | method: 'patch', 78 | headers: { 79 | test: 'header', 80 | }, 81 | }); 82 | }); 83 | }); 84 | describe('toHaveLastPatched', () => { 85 | beforeAll(() => { 86 | fetch.mock('*', 200); 87 | fetch('http://example.com/path', { 88 | method: 'patch', 89 | headers: { 90 | test: 'header', 91 | }, 92 | }); 93 | }); 94 | afterAll(() => fetch.reset()); 95 | 96 | it('matches with just url', () => { 97 | expect(fetch).toHaveLastPatched('http://example.com/path'); 98 | }); 99 | 100 | it('matches with fetch-mock matcher', () => { 101 | expect(fetch).toHaveLastPatched('begin:http://example.com/path'); 102 | }); 103 | 104 | it('matches with matcher and options', () => { 105 | expect(fetch).toHaveLastPatched('http://example.com/path', { 106 | method: 'patch', 107 | headers: { 108 | test: 'header', 109 | }, 110 | }); 111 | }); 112 | 113 | it("doesn't match if matcher but not options is correct", () => { 114 | expect(fetch).not.toHaveLastPatched('http://example.com/path', { 115 | method: 'patch', 116 | headers: { 117 | test: 'not-header', 118 | }, 119 | }); 120 | }); 121 | 122 | it("doesn't match if options but not matcher is correct", () => { 123 | expect(fetch).not.toHaveLastPatched('http://example-no.com/path', { 124 | method: 'patch', 125 | headers: { 126 | test: 'header', 127 | }, 128 | }); 129 | }); 130 | }); 131 | 132 | describe('toHaveNthPatched', () => { 133 | beforeAll(() => { 134 | fetch.mock('*', 200); 135 | fetch('http://example1.com/path', { 136 | method: 'patch', 137 | headers: { 138 | test: 'header', 139 | }, 140 | }); 141 | fetch('http://example2.com/path', { 142 | method: 'patch', 143 | headers: { 144 | test: 'header', 145 | }, 146 | }); 147 | }); 148 | afterAll(() => fetch.reset()); 149 | 150 | it('matches with just url', () => { 151 | expect(fetch).toHaveNthPatched(2, 'http://example2.com/path'); 152 | }); 153 | 154 | it('matches with fetch-mock matcher', () => { 155 | expect(fetch).toHaveNthPatched(2, 'begin:http://example2.com/path'); 156 | }); 157 | 158 | it('matches with matcher and options', () => { 159 | expect(fetch).toHaveNthPatched(2, 'http://example2.com/path', { 160 | method: 'patch', 161 | headers: { 162 | test: 'header', 163 | }, 164 | }); 165 | }); 166 | 167 | it("doesn't match if matcher but not options is correct", () => { 168 | expect(fetch).not.toHaveNthPatched(2, 'http://example2.com/path', { 169 | method: 'patch', 170 | headers: { 171 | test: 'not-header', 172 | }, 173 | }); 174 | }); 175 | 176 | it("doesn't match if options but not matcher is correct", () => { 177 | expect(fetch).not.toHaveNthPatched(2, 'http://example-no.com/path', { 178 | method: 'patch', 179 | headers: { 180 | test: 'header', 181 | }, 182 | }); 183 | }); 184 | 185 | it("doesn't match if wrong n", () => { 186 | expect(fetch).not.toHaveNthPatched(1, 'http://example2.com/path'); 187 | }); 188 | }); 189 | 190 | describe('toHavePatchedTimes', () => { 191 | beforeAll(() => { 192 | fetch.mock('*', 200); 193 | fetch('http://example.com/path', { 194 | method: 'patch', 195 | headers: { 196 | test: 'header', 197 | }, 198 | }); 199 | fetch('http://example.com/path', { 200 | method: 'patch', 201 | headers: { 202 | test: 'header', 203 | }, 204 | }); 205 | }); 206 | afterAll(() => fetch.reset()); 207 | 208 | it('matches with just url', () => { 209 | expect(fetch).toHavePatchedTimes(2, 'http://example.com/path'); 210 | }); 211 | 212 | it('matches with fetch-mock matcher', () => { 213 | expect(fetch).toHavePatchedTimes(2, 'begin:http://example.com/path'); 214 | }); 215 | 216 | it('matches with matcher and options', () => { 217 | expect(fetch).toHavePatchedTimes(2, 'http://example.com/path', { 218 | method: 'patch', 219 | headers: { 220 | test: 'header', 221 | }, 222 | }); 223 | }); 224 | 225 | it("doesn't match if matcher but not options is correct", () => { 226 | expect(fetch).not.toHavePatchedTimes(2, 'http://example.com/path', { 227 | method: 'patch', 228 | headers: { 229 | test: 'not-header', 230 | }, 231 | }); 232 | }); 233 | 234 | it("doesn't match if options but not matcher is correct", () => { 235 | expect(fetch).not.toHavePatchedTimes(2, 'http://example-no.com/path', { 236 | method: 'patch', 237 | headers: { 238 | test: 'header', 239 | }, 240 | }); 241 | }); 242 | 243 | it("doesn't match if too few calls", () => { 244 | expect(fetch).not.toHavePatchedTimes(1, 'http://example.com/path'); 245 | }); 246 | 247 | it("doesn't match if too many calls", () => { 248 | expect(fetch).not.toHavePatchedTimes(3, 'http://example.com/path'); 249 | }); 250 | }); 251 | }); 252 | -------------------------------------------------------------------------------- /__tests__/jest-extensions-post.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest, beforeAll, afterAll */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | describe('jest extensions - post', () => { 5 | describe('when no calls', () => { 6 | beforeAll(() => { 7 | fetch.mock('*', 200); 8 | fetch('http://lala'); 9 | }); 10 | afterAll(() => fetch.reset()); 11 | it('toHavePosted should be falsy', () => { 12 | expect(fetch).not.toHavePosted('http://example.com/path'); 13 | }); 14 | 15 | it('toHaveLastPosted should be falsy', () => { 16 | expect(fetch).not.toHaveLastPosted('http://example.com/path'); 17 | }); 18 | 19 | it('toHaveNthPosted should be falsy', () => { 20 | expect(fetch).not.toHaveNthPosted(1, 'http://example.com/path'); 21 | }); 22 | 23 | it('toHavePostedTimes should be falsy', () => { 24 | expect(fetch).not.toHavePostedTimes(1, 'http://example.com/path'); 25 | }); 26 | 27 | it('toBeDone should be falsy', () => { 28 | expect(fetch).not.toBeDone('http://example.com/path'); 29 | }); 30 | }); 31 | describe('toHavePosted', () => { 32 | beforeAll(() => { 33 | fetch.mock('*', 200); 34 | fetch('http://example.com/path2', { 35 | method: 'post', 36 | headers: { 37 | test: 'header', 38 | }, 39 | }); 40 | fetch('http://example.com/path', { 41 | method: 'post', 42 | headers: { 43 | test: 'header', 44 | }, 45 | }); 46 | }); 47 | afterAll(() => fetch.reset()); 48 | 49 | it('matches with just url', () => { 50 | expect(fetch).toHavePosted('http://example.com/path'); 51 | }); 52 | 53 | it('matches with fetch-mock matcher', () => { 54 | expect(fetch).toHavePosted('begin:http://example.com/path'); 55 | }); 56 | 57 | it('matches with matcher and options', () => { 58 | expect(fetch).toHavePosted('http://example.com/path', { 59 | method: 'post', 60 | headers: { 61 | test: 'header', 62 | }, 63 | }); 64 | }); 65 | 66 | it("doesn't match if matcher but not options is correct", () => { 67 | expect(fetch).not.toHavePosted('http://example.com/path', { 68 | method: 'post', 69 | headers: { 70 | test: 'not-header', 71 | }, 72 | }); 73 | }); 74 | 75 | it("doesn't match if options but not matcher is correct", () => { 76 | expect(fetch).not.toHavePosted('http://example-no.com/path', { 77 | method: 'post', 78 | headers: { 79 | test: 'header', 80 | }, 81 | }); 82 | }); 83 | }); 84 | describe('toHaveLastPosted', () => { 85 | beforeAll(() => { 86 | fetch.mock('*', 200); 87 | fetch('http://example.com/path', { 88 | method: 'post', 89 | headers: { 90 | test: 'header', 91 | }, 92 | }); 93 | }); 94 | afterAll(() => fetch.reset()); 95 | 96 | it('matches with just url', () => { 97 | expect(fetch).toHaveLastPosted('http://example.com/path'); 98 | }); 99 | 100 | it('matches with fetch-mock matcher', () => { 101 | expect(fetch).toHaveLastPosted('begin:http://example.com/path'); 102 | }); 103 | 104 | it('matches with matcher and options', () => { 105 | expect(fetch).toHaveLastPosted('http://example.com/path', { 106 | method: 'post', 107 | headers: { 108 | test: 'header', 109 | }, 110 | }); 111 | }); 112 | 113 | it("doesn't match if matcher but not options is correct", () => { 114 | expect(fetch).not.toHaveLastPosted('http://example.com/path', { 115 | method: 'post', 116 | headers: { 117 | test: 'not-header', 118 | }, 119 | }); 120 | }); 121 | 122 | it("doesn't match if options but not matcher is correct", () => { 123 | expect(fetch).not.toHaveLastPosted('http://example-no.com/path', { 124 | method: 'post', 125 | headers: { 126 | test: 'header', 127 | }, 128 | }); 129 | }); 130 | }); 131 | 132 | describe('toHaveNthPosted', () => { 133 | beforeAll(() => { 134 | fetch.mock('*', 200); 135 | fetch('http://example1.com/path', { 136 | method: 'post', 137 | headers: { 138 | test: 'header', 139 | }, 140 | }); 141 | fetch('http://example2.com/path', { 142 | method: 'post', 143 | headers: { 144 | test: 'header', 145 | }, 146 | }); 147 | }); 148 | afterAll(() => fetch.reset()); 149 | 150 | it('matches with just url', () => { 151 | expect(fetch).toHaveNthPosted(2, 'http://example2.com/path'); 152 | }); 153 | 154 | it('matches with fetch-mock matcher', () => { 155 | expect(fetch).toHaveNthPosted(2, 'begin:http://example2.com/path'); 156 | }); 157 | 158 | it('matches with matcher and options', () => { 159 | expect(fetch).toHaveNthPosted(2, 'http://example2.com/path', { 160 | method: 'post', 161 | headers: { 162 | test: 'header', 163 | }, 164 | }); 165 | }); 166 | 167 | it("doesn't match if matcher but not options is correct", () => { 168 | expect(fetch).not.toHaveNthPosted(2, 'http://example2.com/path', { 169 | method: 'post', 170 | headers: { 171 | test: 'not-header', 172 | }, 173 | }); 174 | }); 175 | 176 | it("doesn't match if options but not matcher is correct", () => { 177 | expect(fetch).not.toHaveNthPosted(2, 'http://example-no.com/path', { 178 | method: 'post', 179 | headers: { 180 | test: 'header', 181 | }, 182 | }); 183 | }); 184 | 185 | it("doesn't match if wrong n", () => { 186 | expect(fetch).not.toHaveNthPosted(1, 'http://example2.com/path'); 187 | }); 188 | }); 189 | 190 | describe('toHavePostedTimes', () => { 191 | beforeAll(() => { 192 | fetch.mock('*', 200); 193 | fetch('http://example.com/path', { 194 | method: 'post', 195 | headers: { 196 | test: 'header', 197 | }, 198 | }); 199 | fetch('http://example.com/path', { 200 | method: 'post', 201 | headers: { 202 | test: 'header', 203 | }, 204 | }); 205 | }); 206 | afterAll(() => fetch.reset()); 207 | 208 | it('matches with just url', () => { 209 | expect(fetch).toHavePostedTimes(2, 'http://example.com/path'); 210 | }); 211 | 212 | it('matches with fetch-mock matcher', () => { 213 | expect(fetch).toHavePostedTimes(2, 'begin:http://example.com/path'); 214 | }); 215 | 216 | it('matches with matcher and options', () => { 217 | expect(fetch).toHavePostedTimes(2, 'http://example.com/path', { 218 | method: 'post', 219 | headers: { 220 | test: 'header', 221 | }, 222 | }); 223 | }); 224 | 225 | it("doesn't match if matcher but not options is correct", () => { 226 | expect(fetch).not.toHavePostedTimes(2, 'http://example.com/path', { 227 | method: 'post', 228 | headers: { 229 | test: 'not-header', 230 | }, 231 | }); 232 | }); 233 | 234 | it("doesn't match if options but not matcher is correct", () => { 235 | expect(fetch).not.toHavePostedTimes(2, 'http://example-no.com/path', { 236 | method: 'post', 237 | headers: { 238 | test: 'header', 239 | }, 240 | }); 241 | }); 242 | 243 | it("doesn't match if too few calls", () => { 244 | expect(fetch).not.toHavePostedTimes(1, 'http://example.com/path'); 245 | }); 246 | 247 | it("doesn't match if too many calls", () => { 248 | expect(fetch).not.toHavePostedTimes(3, 'http://example.com/path'); 249 | }); 250 | }); 251 | }); 252 | -------------------------------------------------------------------------------- /__tests__/jest-extensions-put.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest, beforeAll, afterAll */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | describe('jest extensions - put', () => { 5 | describe('when no calls', () => { 6 | beforeAll(() => { 7 | fetch.mock('*', 200); 8 | fetch('http://lala'); 9 | }); 10 | afterAll(() => fetch.reset()); 11 | it('toHavePut should be falsy', () => { 12 | expect(fetch).not.toHavePut('http://example.com/path'); 13 | }); 14 | 15 | it('toHaveLastPut should be falsy', () => { 16 | expect(fetch).not.toHaveLastPut('http://example.com/path'); 17 | }); 18 | 19 | it('toHaveNthPut should be falsy', () => { 20 | expect(fetch).not.toHaveNthPut(1, 'http://example.com/path'); 21 | }); 22 | 23 | it('toHavePutTimes should be falsy', () => { 24 | expect(fetch).not.toHavePutTimes(1, 'http://example.com/path'); 25 | }); 26 | 27 | it('toBeDone should be falsy', () => { 28 | expect(fetch).not.toBeDone('http://example.com/path'); 29 | }); 30 | }); 31 | describe('toHavePut', () => { 32 | beforeAll(() => { 33 | fetch.mock('*', 200); 34 | fetch('http://example.com/path2', { 35 | method: 'put', 36 | headers: { 37 | test: 'header', 38 | }, 39 | }); 40 | fetch('http://example.com/path', { 41 | method: 'put', 42 | headers: { 43 | test: 'header', 44 | }, 45 | }); 46 | }); 47 | afterAll(() => fetch.reset()); 48 | 49 | it('matches with just url', () => { 50 | expect(fetch).toHavePut('http://example.com/path'); 51 | }); 52 | 53 | it('matches with fetch-mock matcher', () => { 54 | expect(fetch).toHavePut('begin:http://example.com/path'); 55 | }); 56 | 57 | it('matches with matcher and options', () => { 58 | expect(fetch).toHavePut('http://example.com/path', { 59 | method: 'put', 60 | headers: { 61 | test: 'header', 62 | }, 63 | }); 64 | }); 65 | 66 | it("doesn't match if matcher but not options is correct", () => { 67 | expect(fetch).not.toHavePut('http://example.com/path', { 68 | method: 'put', 69 | headers: { 70 | test: 'not-header', 71 | }, 72 | }); 73 | }); 74 | 75 | it("doesn't match if options but not matcher is correct", () => { 76 | expect(fetch).not.toHavePut('http://example-no.com/path', { 77 | method: 'put', 78 | headers: { 79 | test: 'header', 80 | }, 81 | }); 82 | }); 83 | }); 84 | describe('toHaveLastPut', () => { 85 | beforeAll(() => { 86 | fetch.mock('*', 200); 87 | fetch('http://example.com/path', { 88 | method: 'put', 89 | headers: { 90 | test: 'header', 91 | }, 92 | }); 93 | }); 94 | afterAll(() => fetch.reset()); 95 | 96 | it('matches with just url', () => { 97 | expect(fetch).toHaveLastPut('http://example.com/path'); 98 | }); 99 | 100 | it('matches with fetch-mock matcher', () => { 101 | expect(fetch).toHaveLastPut('begin:http://example.com/path'); 102 | }); 103 | 104 | it('matches with matcher and options', () => { 105 | expect(fetch).toHaveLastPut('http://example.com/path', { 106 | method: 'put', 107 | headers: { 108 | test: 'header', 109 | }, 110 | }); 111 | }); 112 | 113 | it("doesn't match if matcher but not options is correct", () => { 114 | expect(fetch).not.toHaveLastPut('http://example.com/path', { 115 | method: 'put', 116 | headers: { 117 | test: 'not-header', 118 | }, 119 | }); 120 | }); 121 | 122 | it("doesn't match if options but not matcher is correct", () => { 123 | expect(fetch).not.toHaveLastPut('http://example-no.com/path', { 124 | method: 'put', 125 | headers: { 126 | test: 'header', 127 | }, 128 | }); 129 | }); 130 | }); 131 | 132 | describe('toHaveNthPut', () => { 133 | beforeAll(() => { 134 | fetch.mock('*', 200); 135 | fetch('http://example1.com/path', { 136 | method: 'put', 137 | headers: { 138 | test: 'header', 139 | }, 140 | }); 141 | fetch('http://example2.com/path', { 142 | method: 'put', 143 | headers: { 144 | test: 'header', 145 | }, 146 | }); 147 | }); 148 | afterAll(() => fetch.reset()); 149 | 150 | it('matches with just url', () => { 151 | expect(fetch).toHaveNthPut(2, 'http://example2.com/path'); 152 | }); 153 | 154 | it('matches with fetch-mock matcher', () => { 155 | expect(fetch).toHaveNthPut(2, 'begin:http://example2.com/path'); 156 | }); 157 | 158 | it('matches with matcher and options', () => { 159 | expect(fetch).toHaveNthPut(2, 'http://example2.com/path', { 160 | method: 'put', 161 | headers: { 162 | test: 'header', 163 | }, 164 | }); 165 | }); 166 | 167 | it("doesn't match if matcher but not options is correct", () => { 168 | expect(fetch).not.toHaveNthPut(2, 'http://example2.com/path', { 169 | method: 'put', 170 | headers: { 171 | test: 'not-header', 172 | }, 173 | }); 174 | }); 175 | 176 | it("doesn't match if options but not matcher is correct", () => { 177 | expect(fetch).not.toHaveNthPut(2, 'http://example-no.com/path', { 178 | method: 'put', 179 | headers: { 180 | test: 'header', 181 | }, 182 | }); 183 | }); 184 | 185 | it("doesn't match if wrong n", () => { 186 | expect(fetch).not.toHaveNthPut(1, 'http://example2.com/path'); 187 | }); 188 | }); 189 | 190 | describe('toHavePutTimes', () => { 191 | beforeAll(() => { 192 | fetch.mock('*', 200); 193 | fetch('http://example.com/path', { 194 | method: 'put', 195 | headers: { 196 | test: 'header', 197 | }, 198 | }); 199 | fetch('http://example.com/path', { 200 | method: 'put', 201 | headers: { 202 | test: 'header', 203 | }, 204 | }); 205 | }); 206 | afterAll(() => fetch.reset()); 207 | 208 | it('matches with just url', () => { 209 | expect(fetch).toHavePutTimes(2, 'http://example.com/path'); 210 | }); 211 | 212 | it('matches with fetch-mock matcher', () => { 213 | expect(fetch).toHavePutTimes(2, 'begin:http://example.com/path'); 214 | }); 215 | 216 | it('matches with matcher and options', () => { 217 | expect(fetch).toHavePutTimes(2, 'http://example.com/path', { 218 | method: 'put', 219 | headers: { 220 | test: 'header', 221 | }, 222 | }); 223 | }); 224 | 225 | it("doesn't match if matcher but not options is correct", () => { 226 | expect(fetch).not.toHavePutTimes(2, 'http://example.com/path', { 227 | method: 'put', 228 | headers: { 229 | test: 'not-header', 230 | }, 231 | }); 232 | }); 233 | 234 | it("doesn't match if options but not matcher is correct", () => { 235 | expect(fetch).not.toHavePutTimes(2, 'http://example-no.com/path', { 236 | method: 'put', 237 | headers: { 238 | test: 'header', 239 | }, 240 | }); 241 | }); 242 | 243 | it("doesn't match if too few calls", () => { 244 | expect(fetch).not.toHavePutTimes(1, 'http://example.com/path'); 245 | }); 246 | 247 | it("doesn't match if too many calls", () => { 248 | expect(fetch).not.toHavePutTimes(3, 'http://example.com/path'); 249 | }); 250 | }); 251 | }); 252 | -------------------------------------------------------------------------------- /__tests__/jest-extensions.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest, beforeAll, afterAll */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | describe('jest extensions', () => { 5 | describe('when no calls', () => { 6 | beforeAll(() => { 7 | fetch.mock('*', 200); 8 | }); 9 | afterAll(() => fetch.reset()); 10 | it('toHaveFetched should be falsy', () => { 11 | expect(fetch).not.toHaveFetched('http://example.com/path'); 12 | }); 13 | 14 | it('toHaveLastFetched should be falsy', () => { 15 | expect(fetch).not.toHaveLastFetched('http://example.com/path'); 16 | }); 17 | 18 | it('toHaveNthFetched should be falsy', () => { 19 | expect(fetch).not.toHaveNthFetched(1, 'http://example.com/path'); 20 | }); 21 | 22 | it('toHaveFetchedTimes should be falsy', () => { 23 | expect(fetch).not.toHaveFetchedTimes(1, 'http://example.com/path'); 24 | }); 25 | 26 | it('toBeDone should be falsy', () => { 27 | expect(fetch).not.toBeDone(); 28 | expect(fetch).not.toBeDone('http://example.com/path'); 29 | }); 30 | }); 31 | describe('toHaveFetched', () => { 32 | beforeAll(() => { 33 | fetch.mock('*', 200); 34 | fetch('http://example.com/path2', { 35 | headers: { 36 | test: 'header', 37 | }, 38 | }); 39 | fetch('http://example.com/path', { 40 | headers: { 41 | test: 'header', 42 | }, 43 | }); 44 | }); 45 | afterAll(() => fetch.reset()); 46 | 47 | it('matches with just url', () => { 48 | expect(fetch).toHaveFetched('http://example.com/path'); 49 | }); 50 | 51 | it('matches with fetch-mock matcher', () => { 52 | expect(fetch).toHaveFetched('begin:http://example.com/path'); 53 | }); 54 | 55 | it('matches with matcher and options', () => { 56 | expect(fetch).toHaveFetched('http://example.com/path', { 57 | headers: { 58 | test: 'header', 59 | }, 60 | }); 61 | }); 62 | 63 | it("doesn't match if matcher but not options is correct", () => { 64 | expect(fetch).not.toHaveFetched('http://example.com/path', { 65 | headers: { 66 | test: 'not-header', 67 | }, 68 | }); 69 | }); 70 | 71 | it("doesn't match if options but not matcher is correct", () => { 72 | expect(fetch).not.toHaveFetched('http://example-no.com/path', { 73 | headers: { 74 | test: 'header', 75 | }, 76 | }); 77 | }); 78 | }); 79 | describe('toHaveLastFetched', () => { 80 | beforeAll(() => { 81 | fetch.mock('*', 200); 82 | fetch('http://example.com/path', { 83 | headers: { 84 | test: 'header', 85 | }, 86 | }); 87 | }); 88 | afterAll(() => fetch.reset()); 89 | 90 | it('matches with just url', () => { 91 | expect(fetch).toHaveLastFetched('http://example.com/path'); 92 | }); 93 | 94 | it('matches with fetch-mock matcher', () => { 95 | expect(fetch).toHaveLastFetched('begin:http://example.com/path'); 96 | }); 97 | 98 | it('matches with matcher and options', () => { 99 | expect(fetch).toHaveLastFetched('http://example.com/path', { 100 | headers: { 101 | test: 'header', 102 | }, 103 | }); 104 | }); 105 | 106 | it("doesn't match if matcher but not options is correct", () => { 107 | expect(fetch).not.toHaveLastFetched('http://example.com/path', { 108 | headers: { 109 | test: 'not-header', 110 | }, 111 | }); 112 | }); 113 | 114 | it("doesn't match if options but not matcher is correct", () => { 115 | expect(fetch).not.toHaveLastFetched('http://example-no.com/path', { 116 | headers: { 117 | test: 'header', 118 | }, 119 | }); 120 | }); 121 | }); 122 | 123 | describe('toHaveNthFetched', () => { 124 | beforeAll(() => { 125 | fetch.mock('*', 200); 126 | fetch('http://example1.com/path', { 127 | headers: { 128 | test: 'header', 129 | }, 130 | }); 131 | fetch('http://example2.com/path', { 132 | headers: { 133 | test: 'header', 134 | }, 135 | }); 136 | }); 137 | afterAll(() => fetch.reset()); 138 | 139 | it('matches with just url', () => { 140 | expect(fetch).toHaveNthFetched(2, 'http://example2.com/path'); 141 | }); 142 | 143 | it('matches with fetch-mock matcher', () => { 144 | expect(fetch).toHaveNthFetched(2, 'begin:http://example2.com/path'); 145 | }); 146 | 147 | it('matches with matcher and options', () => { 148 | expect(fetch).toHaveNthFetched(2, 'http://example2.com/path', { 149 | headers: { 150 | test: 'header', 151 | }, 152 | }); 153 | }); 154 | 155 | it("doesn't match if matcher but not options is correct", () => { 156 | expect(fetch).not.toHaveNthFetched(2, 'http://example2.com/path', { 157 | headers: { 158 | test: 'not-header', 159 | }, 160 | }); 161 | }); 162 | 163 | it("doesn't match if options but not matcher is correct", () => { 164 | expect(fetch).not.toHaveNthFetched(2, 'http://example-no.com/path', { 165 | headers: { 166 | test: 'header', 167 | }, 168 | }); 169 | }); 170 | 171 | it("doesn't match if wrong n", () => { 172 | expect(fetch).not.toHaveNthFetched(1, 'http://example2.com/path'); 173 | }); 174 | }); 175 | 176 | describe('toHaveFetchedTimes', () => { 177 | beforeAll(() => { 178 | fetch.mock('*', 200); 179 | fetch('http://example.com/path', { 180 | headers: { 181 | test: 'header', 182 | }, 183 | }); 184 | fetch('http://example.com/path', { 185 | headers: { 186 | test: 'header', 187 | }, 188 | }); 189 | }); 190 | afterAll(() => fetch.reset()); 191 | 192 | it('matches with just url', () => { 193 | expect(fetch).toHaveFetchedTimes(2, 'http://example.com/path'); 194 | }); 195 | 196 | it('matches with fetch-mock matcher', () => { 197 | expect(fetch).toHaveFetchedTimes(2, 'begin:http://example.com/path'); 198 | }); 199 | 200 | it('matches with matcher and options', () => { 201 | expect(fetch).toHaveFetchedTimes(2, 'http://example.com/path', { 202 | headers: { 203 | test: 'header', 204 | }, 205 | }); 206 | }); 207 | 208 | it("doesn't match if matcher but not options is correct", () => { 209 | expect(fetch).not.toHaveFetchedTimes(2, 'http://example.com/path', { 210 | headers: { 211 | test: 'not-header', 212 | }, 213 | }); 214 | }); 215 | 216 | it("doesn't match if options but not matcher is correct", () => { 217 | expect(fetch).not.toHaveFetchedTimes(2, 'http://example-no.com/path', { 218 | headers: { 219 | test: 'header', 220 | }, 221 | }); 222 | }); 223 | 224 | it("doesn't match if too few calls", () => { 225 | expect(fetch).not.toHaveFetchedTimes(1, 'http://example.com/path'); 226 | }); 227 | 228 | it("doesn't match if too many calls", () => { 229 | expect(fetch).not.toHaveFetchedTimes(3, 'http://example.com/path'); 230 | }); 231 | }); 232 | 233 | describe('toBeDone', () => { 234 | beforeAll(() => { 235 | fetch.once('http://example.com/path', 200); 236 | fetch.mock('http://example2.com/path', 200, { repeat: 2 }); 237 | fetch('http://example.com/path', { 238 | headers: { 239 | test: 'header', 240 | }, 241 | }); 242 | fetch('http://example2.com/path', { 243 | headers: { 244 | test: 'header', 245 | }, 246 | }); 247 | }); 248 | afterAll(() => fetch.reset()); 249 | 250 | it('matches with just url', () => { 251 | expect(fetch).toBeDone('http://example.com/path'); 252 | }); 253 | 254 | it("doesn't match if too few calls", () => { 255 | expect(fetch).not.toBeDone('http://example2.com/path'); 256 | }); 257 | }); 258 | }); 259 | -------------------------------------------------------------------------------- /__tests__/regressions.spec.js: -------------------------------------------------------------------------------- 1 | /*global jest */ 2 | jest.mock('node-fetch', () => require('../server').sandbox()); 3 | const fetch = require('node-fetch'); 4 | 5 | describe('regressions and strange cases', () => { 6 | it('works even when jest.resetAllMocks() is called', () => { 7 | jest.resetAllMocks(); 8 | fetch.mock('*', 200); 9 | fetch('http://example.com/path', 200); 10 | expect(fetch).toHaveFetched('http://example.com/path'); 11 | fetch.reset(); 12 | }); 13 | it('works even when jest.clearAllMocks() is called', () => { 14 | jest.clearAllMocks(); 15 | fetch.mock('*', 200); 16 | fetch('http://example.com/path', 200); 17 | expect(fetch).toHaveFetched('http://example.com/path'); 18 | fetch.reset(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /browser.js: -------------------------------------------------------------------------------- 1 | const fetchMock = require('fetch-mock'); 2 | const jestify = require('./jestify'); 3 | 4 | module.exports = jestify(fetchMock); 5 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import { InspectionFilter, InspectionOptions, FetchMockStatic, MockCall, FetchMockSandbox } from 'fetch-mock'; 2 | 3 | declare global { 4 | namespace jest { 5 | interface Matchers { 6 | toHaveFetched(filter?: InspectionFilter, options?: InspectionOptions): R; 7 | toHaveLastFetched(filter?: InspectionFilter, options?: InspectionOptions): R; 8 | toHaveNthFetched(n: number, filter?: InspectionFilter, options?: InspectionOptions): R; 9 | toHaveFetchedTimes(times: number, filter?: InspectionFilter, options?: InspectionOptions): R; 10 | toBeDone(filter?: InspectionFilter): R; 11 | } 12 | } 13 | } 14 | 15 | 16 | interface FetchMockJest { 17 | // Reset the call history 18 | mockClear(): void; 19 | // Remove all configured mocks 20 | mockReset(): void; 21 | // Enable sandbox mode 22 | sandbox(): jest.MockInstance & FetchMockSandbox; 23 | } 24 | 25 | declare const fetchMockJest: FetchMockJest & jest.MockInstance & FetchMockStatic 26 | 27 | export = fetchMockJest; 28 | -------------------------------------------------------------------------------- /jest-extensions.js: -------------------------------------------------------------------------------- 1 | const callsAreEqual = (c1, c2) => { 2 | if (!c1 && !c2) return true; 3 | if (!c1 || !c2) return false; 4 | if (c1[0] !== c2[0]) return false; 5 | if (c1[1] !== c2[1]) return false; 6 | if (c1.request !== c2.request) return false; 7 | if (c1.identifier !== c2.identifier) return false; 8 | if (c1.isUnmatched !== c2.isUnmatched) return false; 9 | if (c1.response !== c2.response) return false; 10 | return true; 11 | }; 12 | 13 | const methodlessExtensions = { 14 | toHaveFetched: (fetchMock, url, options) => { 15 | if (fetchMock.called(url, options)) { 16 | return { pass: true }; 17 | } 18 | return { 19 | pass: false, 20 | message: () => `fetch should have been called with ${url}`, 21 | }; 22 | }, 23 | toHaveLastFetched: (fetchMock, url, options) => { 24 | const allCalls = fetchMock.calls(); 25 | if (!allCalls.length) { 26 | return { 27 | pass: false, 28 | message: () => `No calls made to fetch`, 29 | }; 30 | } 31 | const lastCall = [...allCalls].pop(); 32 | const lastUrlCall = [...fetchMock.calls(url, options)].pop(); 33 | if (callsAreEqual(lastCall, lastUrlCall)) { 34 | return { pass: true }; 35 | } 36 | return { 37 | pass: false, 38 | message: () => 39 | `Last call to fetch should have had a URL of ${url} but was ${lastCall.url}`, 40 | }; 41 | }, 42 | 43 | toHaveNthFetched: (fetchMock, n, url, options) => { 44 | const nthCall = fetchMock.calls()[n - 1]; 45 | const urlCalls = fetchMock.calls(url, options); 46 | if (urlCalls.some((call) => callsAreEqual(call, nthCall))) { 47 | return { pass: true }; 48 | } 49 | return { 50 | pass: false, 51 | message: () => 52 | `${n}th call to fetch should have had a URL of ${url} but was ${nthCall.url}`, 53 | }; 54 | }, 55 | 56 | toHaveFetchedTimes: (fetchMock, times, url, options) => { 57 | const calls = fetchMock.calls(url, options); 58 | if (calls.length === times) { 59 | return { pass: true }; 60 | } 61 | return { 62 | pass: false, 63 | message: () => 64 | `fetch should have been called with a URL of ${url} ${times} times, but it was called ${calls.length} times`, 65 | }; 66 | }, 67 | }; 68 | 69 | expect.extend(methodlessExtensions); 70 | expect.extend({ 71 | toBeDone: (fetchMock, matcher) => { 72 | const done = fetchMock.done(matcher); 73 | if (done) { 74 | return { pass: true }; 75 | } 76 | return { 77 | pass: false, 78 | message: () => 79 | `fetch has not been called the expected number of times ${ 80 | matcher ? `for ${matcher}` : 'in total' 81 | }`, 82 | }; 83 | }, 84 | }); 85 | 86 | [ 87 | 'Got:get', 88 | 'Posted:post', 89 | 'Put:put', 90 | 'Deleted:delete', 91 | 'FetchedHead:head', 92 | 'Patched:patch', 93 | ].forEach((verbs) => { 94 | const [humanVerb, method] = verbs.split(':'); 95 | 96 | const extensions = Object.entries(methodlessExtensions) 97 | .map(([name, func]) => { 98 | return [ 99 | (name = name.replace('Fetched', humanVerb)), 100 | (...args) => { 101 | const opts = args[func.length - 1] || {}; 102 | args[func.length - 1] = { ...opts, method }; 103 | return func(...args); 104 | }, 105 | ]; 106 | }) 107 | .reduce((obj, [name, func]) => ({ ...obj, [name]: func }), {}); 108 | 109 | expect.extend(extensions); 110 | }); 111 | -------------------------------------------------------------------------------- /jestify.js: -------------------------------------------------------------------------------- 1 | /*global jest*/ 2 | require('./jest-extensions'); 3 | 4 | const jestify = (fetchMockInstance) => { 5 | const jestifiedInstance = new Proxy(fetchMockInstance, { 6 | get: (originalFetchMock, name) => { 7 | if (name === 'sandbox') { 8 | return new Proxy(originalFetchMock[name], { 9 | apply: (func, thisArg, args) => { 10 | const sandboxedFetchMock = func.apply(originalFetchMock, args); 11 | return jestify(sandboxedFetchMock); 12 | }, 13 | }); 14 | } 15 | return originalFetchMock[name]; 16 | }, 17 | }); 18 | 19 | // spy on the fetch handler so we can use all the 20 | // jest function assertions on it 21 | const spy = jest.fn(); 22 | const originalFetchHandler = jestifiedInstance.fetchHandler.bind( 23 | jestifiedInstance 24 | ); 25 | 26 | jestifiedInstance.fetchHandler = function (...args) { 27 | const result = originalFetchHandler(...args); 28 | spy.mockReturnValueOnce(result); 29 | spy.apply(this, args); 30 | return result; 31 | }; 32 | 33 | // make sure all the jest expectation helpers can find what they need on fetchMock.mock 34 | Object.assign(jestifiedInstance.mock, spy.mock); 35 | 36 | ['_isMockFunction', 'mockName', 'getMockName'].forEach((prop) => { 37 | jestifiedInstance[prop] = spy[prop]; 38 | }); 39 | 40 | jestifiedInstance.mockClear = () => { 41 | spy.mockClear(); 42 | jestifiedInstance.resetHistory(); 43 | Object.assign(jestifiedInstance.mock, spy.mock); 44 | }; 45 | jestifiedInstance.mockReset = () => { 46 | spy.mockReset(); 47 | jestifiedInstance.reset(); 48 | Object.assign(jestifiedInstance.mock, spy.mock); 49 | }; 50 | jestifiedInstance.mockRestore = () => { 51 | throw new Error( 52 | "mockRestore not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 53 | ); 54 | }; 55 | jestifiedInstance.mockImplementation = () => { 56 | throw new Error( 57 | "mockImplementation not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 58 | ); 59 | }; 60 | jestifiedInstance.mockImplementationOnce = () => { 61 | throw new Error( 62 | "mockImplementationOnce not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 63 | ); 64 | }; 65 | jestifiedInstance.mockName = () => { 66 | throw new Error( 67 | "mockName not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 68 | ); 69 | }; 70 | jestifiedInstance.mockReturnThis = () => { 71 | throw new Error( 72 | "mockReturnThis not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 73 | ); 74 | }; 75 | jestifiedInstance.mockReturnValue = () => { 76 | throw new Error( 77 | "mockReturnValue not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 78 | ); 79 | }; 80 | jestifiedInstance.mockReturnValueOnce = () => { 81 | throw new Error( 82 | "mockReturnValueOnce not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 83 | ); 84 | }; 85 | jestifiedInstance.mockResolvedValue = () => { 86 | throw new Error( 87 | "mockResolvedValue not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 88 | ); 89 | }; 90 | jestifiedInstance.mockResolvedValueOnce = () => { 91 | throw new Error( 92 | "mockResolvedValueOnce not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 93 | ); 94 | }; 95 | jestifiedInstance.mockRejectedValue = () => { 96 | throw new Error( 97 | "mockRejectedValue not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 98 | ); 99 | }; 100 | jestifiedInstance.mockRejectedValueOnce = () => { 101 | throw new Error( 102 | "mockRejectedValueOnce not supported on fetch-mock. Use fetch-mock's methods to manage mock responses" 103 | ); 104 | }; 105 | 106 | // make sure that the mock object that has properties updated 107 | // by the jest spy is the one that is exposed on fetch 108 | spy.mock = jestifiedInstance.mock; 109 | 110 | // Return this monster! 111 | return jestifiedInstance; 112 | }; 113 | 114 | module.exports = (fetchMock) => jestify(fetchMock); 115 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fetch-mock-jest", 3 | "version": "0.0.0", 4 | "description": "Jest wrapper for fetch-mock, a comprehensive stub for fetch", 5 | "main": "server.js", 6 | "browser": "browser.js", 7 | "types": "index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/wheresrhys/fetch-mock-jest.git" 14 | }, 15 | "engines": { 16 | "node": ">=8.0.0" 17 | }, 18 | "keywords": [ 19 | "fetch", 20 | "http", 21 | "mock", 22 | "testing", 23 | "spy", 24 | "jest" 25 | ], 26 | "funding": { 27 | "type": "charity", 28 | "url": "https://www.justgiving.com/refugee-support-europe" 29 | }, 30 | "author": "Rhys Evans", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/wheresrhys/fetch-mock-jest/issues" 34 | }, 35 | "peerDependencies": { 36 | "node-fetch": "*" 37 | }, 38 | "homepage": "https://github.com/wheresrhys/fetch-mock-jest#readme", 39 | "dependencies": { 40 | "fetch-mock": "^9.11.0" 41 | }, 42 | "devDependencies": { 43 | "eslint": "^6.6.0", 44 | "eslint-config-origami-component": "^2.0.0", 45 | "eslint-config-prettier": "^6.5.0", 46 | "eslint-plugin-prettier": "^3.1.1", 47 | "jest": "^25.0.0", 48 | "node-fetch": "^2.6.0", 49 | "prettier": "^2.0.4" 50 | }, 51 | "peerDependenciesMeta": { 52 | "node-fetch": { 53 | "optional": true 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const fetchMock = require('fetch-mock'); 2 | const jestify = require('./jestify'); 3 | 4 | module.exports = jestify(fetchMock); 5 | -------------------------------------------------------------------------------- /tea.yaml: -------------------------------------------------------------------------------- 1 | # https://tea.xyz/what-is-this-file 2 | --- 3 | version: 1.0.0 4 | codeOwners: 5 | - '0xa93409b6Dd2fd3Aa55812E183E5B191fa3562e9c' 6 | quorum: 1 7 | --------------------------------------------------------------------------------