diff --git a/.eslintignore b/.eslintignore index 015c581d..049380a1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,3 +3,4 @@ dist/* coverage/* es5/* .nyc_output/ +docs/js diff --git a/.gitignore b/.gitignore index 9b9d7e8d..b778f969 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ coverage/ /test/fixtures/built-sw.js .nyc_output .eslintcache +/docs/_site/ +/docs/.sass-cache/ diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..34ff721e --- /dev/null +++ b/Gemfile @@ -0,0 +1,8 @@ +source 'http://rubygems.org' + +gem 'jekyll', '3.7.2' + +group :jekyll_plugins do + gem 'jekyll-seo-tag', '2.4.0' + gem 'jekyll-sitemap', '1.2.0' +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..cafd634f --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,69 @@ +GEM + remote: http://rubygems.org/ + specs: + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + colorator (1.1.0) + concurrent-ruby (1.0.5) + em-websocket (0.5.1) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0.6.0) + eventmachine (1.2.7) + ffi (1.9.25) + forwardable-extended (2.6.0) + http_parser.rb (0.6.0) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + jekyll (3.7.2) + addressable (~> 2.4) + colorator (~> 1.0) + em-websocket (~> 0.5) + i18n (~> 0.7) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (~> 1.14) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-seo-tag (2.4.0) + jekyll (~> 3.3) + jekyll-sitemap (1.2.0) + jekyll (~> 3.3) + jekyll-watch (2.0.0) + listen (~> 3.0) + kramdown (1.17.0) + liquid (4.0.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + mercenary (0.3.6) + pathutil (0.16.1) + forwardable-extended (~> 2.6) + public_suffix (3.0.3) + rb-fsevent (0.10.3) + rb-inotify (0.9.10) + ffi (>= 0.5.0, < 2) + rouge (3.2.1) + ruby_dep (1.5.0) + safe_yaml (1.0.4) + sass (3.5.7) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + +PLATFORMS + ruby + +DEPENDENCIES + jekyll (= 3.7.2) + jekyll-seo-tag (= 2.4.0) + jekyll-sitemap (= 1.2.0) + +BUNDLED WITH + 1.16.1 diff --git a/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_borland.scssc b/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_borland.scssc deleted file mode 100644 index 2afcd71b..00000000 Binary files a/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_borland.scssc and /dev/null differ diff --git a/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_main.scssc b/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_main.scssc deleted file mode 100644 index d3fd0e00..00000000 Binary files a/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_main.scssc and /dev/null differ diff --git a/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_mixins.scssc b/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_mixins.scssc deleted file mode 100644 index ec2aebbf..00000000 Binary files a/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/_mixins.scssc and /dev/null differ diff --git a/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/cloudcannon.scssc b/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/cloudcannon.scssc deleted file mode 100644 index 3fcd70b6..00000000 Binary files a/docs/.sass-cache/5b77b8b6457f241d3ccda5c61846e2e0861a9d21/cloudcannon.scssc and /dev/null differ diff --git a/docs/LICENSE b/docs/LICENSE new file mode 100644 index 00000000..3a4a2fb8 --- /dev/null +++ b/docs/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 CloudCannon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/_about/introduction.md b/docs/_about/introduction.md new file mode 100644 index 00000000..a7e9343d --- /dev/null +++ b/docs/_about/introduction.md @@ -0,0 +1,19 @@ +--- +title: +position: 1 +content_markdown: |- + fetch-mock allows mocking http requests made using [fetch](https://fetch.spec.whatwg.org/), or one of the many libraries imitating its api, such as [node-fetch](https://www.npmjs.com/package/node-fetch) or [fetch-ponyfill](https://www.npmjs.com/package/fetch-ponyfill). + + It supports most JavaScript environments, including nodejs, web workers and service workers, and any browser that either supports fetch natively or that can have a fetch polyfill installed. + + As well as shorthand methods for the simplest use cases, it offers a flexible API for customising all aspects of mocking behaviour. + +left_code_blocks: + - code_block: |- + fetchMock.mock('http://example.com', 200); + const res = await fetch('http://example.com'); + assert(res.ok); + fetchMock.restore(); + title: Example + language: javascript +--- diff --git a/docs/_about/previous-versions.md b/docs/_about/previous-versions.md new file mode 100644 index 00000000..cd4d8e5f --- /dev/null +++ b/docs/_about/previous-versions.md @@ -0,0 +1,9 @@ +--- +title: Previous versions +position: 3 +content_markdown: |- + - [v7 upgrade guide](https://github.com/wheresrhys/fetch-mock/blob/master/docs/v6-v7-upgrade-guide.md) + - [v6 docs](https://github.com/wheresrhys/fetch-mock/tree/4231044aa94e234b53e296181ca5b6b4cecb6e3f/docs) + - [v5 docs](https://github.com/wheresrhys/fetch-mock/tree/b8270640d5711feffb01d1bf85bb7da95179c4de/docs) + +--- diff --git a/docs/_about/quickstart.md b/docs/_about/quickstart.md new file mode 100644 index 00000000..e40d1df5 --- /dev/null +++ b/docs/_about/quickstart.md @@ -0,0 +1,68 @@ +--- +title: Quickstart +position: 2 + +content_markdown: |- + + #### Setting up your mock + + - The commonest use case is `fetchMock.mock(matcher, response)`, where `matcher` is an exact url or regex to match, and `response` is a status code, string or object literal. + - You can also use `fetchMock.once()` to limit to a single call or `fetchMock.get()`, `fetchMock.post()` etc. to limit to a method. + - All these methods are chainable so you can easily define several mocks in a single test. + + ```javascript + fetchMock + .get('http://good.com/', 200) + .post('http://good.com/', 400) + .get(/bad\.com/, 500) + ``` + #### Analysing calls to your mock + + - `fetchMock.called(matcher)` reports if any calls matched your mock (or leave `matcher` out if you just want to check `fetch` was called at all). + - `fetchMock.lastCall()`, `fetchMock.lastUrl()` or `fetchMock.lastOptions()` give you access to the parameters last passed in to `fetch`. + - `fetchMock.done()` will tell you if `fetch` was called the expected number of times. + + #### Tearing down your mock + + - `fetchMock.resetHistory()` resets the call history. + - `fetchMock.reset()` or `fetchMock.restore()` will also restore `fetch()` to its native implementation + + #### Example + + Example with node: suppose we have a file `make-request.js` with a function that calls `fetch`: + + ```js + module.exports = function makeRequest() { + return fetch('http://httpbin.org/get').then(function(response) { + return response.json(); + }); + }; + ``` + + + We can use fetch-mock to mock `fetch`. In `mocked.js`: + + ```js + var fetchMock = require('fetch-mock'); + var makeRequest = require('./make-request'); + + // Mock the fetch() global to always return the same value for GET + // requests to all URLs. + fetchMock.get('*', { hello: 'world' }); + + makeRequest().then(function(data) { + console.log('got data', data); + }); + + // Unmock. + fetchMock.reset(); + ``` + + Result: + + ```bash + $ node mocked.js + 'got data' { hello: 'world' } + ``` + +--- diff --git a/docs/_api-inspection/called.md b/docs/_api-inspection/called.md new file mode 100644 index 00000000..de9eb9aa --- /dev/null +++ b/docs/_api-inspection/called.md @@ -0,0 +1,7 @@ +--- +title: .called(filter, options) +navTitle: .called() +position: 1 +description: |- + Returns a Boolean indicating whether any calls to `fetch` matched the given filter +--- diff --git a/docs/_api-inspection/calls.md b/docs/_api-inspection/calls.md new file mode 100644 index 00000000..d16e3a95 --- /dev/null +++ b/docs/_api-inspection/calls.md @@ -0,0 +1,7 @@ +--- +title: .calls(filter, options) +navTitle: .calls() +position: 2 +description: |- + Returns an array of all calls to fetch matching the given filters. Each call is returned as a `[url, options]` array. If `fetch` was called using a `Request` instance, this will be available as a `request` property on this array. +--- diff --git a/docs/_api-inspection/done.md b/docs/_api-inspection/done.md new file mode 100644 index 00000000..936c6252 --- /dev/null +++ b/docs/_api-inspection/done.md @@ -0,0 +1,10 @@ +--- +title: .done(filter, options) +navTitle: .done() +position: 6 +description: |- + Returns a Boolean indicating whether `fetch` was called the expected number of times (or has been called at least once if `repeat` is undefined for the route) +content_markdown: |- + Unlike the other methods for inspecting calls, unmatched calls are irrelevant. If no `filter` is passed, `done()` returns `true` if every route has been called the number of expected times. + {: .warning} +--- diff --git a/docs/_api-inspection/filtering.md b/docs/_api-inspection/filtering.md new file mode 100644 index 00000000..aceb3eab --- /dev/null +++ b/docs/_api-inspection/filtering.md @@ -0,0 +1,47 @@ +--- +title: "Filtering basics" +position: 0 +description: |- + Most inspection methods take two arguments — `filter` and `options` — which allow groups of fetch calls to be extracted and inspected. +parameters: + - name: filter + types: + - String + - RegExp + - Function + content: |- + Enables filtering fetch calls for the most commonly use cases. The behaviour can be counterintuitive. The following rules, applied in the order they are described, are used to try to retrieve calls. If any rule retrieves no calls the next rule will be tried. + options: + - name: matcher + content: |- + If `options` is defined (it can even be an empty object), `filter` will be executed using the same execution plan as [matchers](#api-mockingmock_matcher). Any calls matched by it will be returned. + types: + - String + - RegExp + - Function + - types: + - undefined + content: |- + Retrieves all calls made to `fetch`, whether fetch-mock matched them or not + - types: + - true + content: |- + Retrieves all calls matched by `fetch`. `fetchMock.MATCHED` is an alias for `true` and may be used to make tests more readable + - types: + - false + content: |- + Retrieves all calls not matched by `fetch` (i.e. those handled by `catch()` or `spy()`. `fetchMock.UNMATCHED` is an alias for `false` and may be used to make tests more readable + - name: route + types: + - String + content: Retrieves calls handled by a named route (see [mocking options](#api-mockingmock_options). Failing that, a route whose matcher, when coerced to a string, is equal to the string provided + - name: asdkash d + content: Do I want to fallback to a matcher again?? Seems confusing as hell + + - name: options + types: + - Object + - String + content: |- + Either an object compatible with the [mocking api](#api-mockingmock_options) or a string specifying a http `method` to filter by +--- diff --git a/docs/_api-inspection/lastCall.md b/docs/_api-inspection/lastCall.md new file mode 100644 index 00000000..5776173c --- /dev/null +++ b/docs/_api-inspection/lastCall.md @@ -0,0 +1,7 @@ +--- +title: .lastCall(filter, options) +navTitle: .lastCall() +position: 3 +description: |- + Returns the arguments for the last call to `fetch` matching the given filter +--- diff --git a/docs/_api-inspection/lastOptions.md b/docs/_api-inspection/lastOptions.md new file mode 100644 index 00000000..bd2ffc2d --- /dev/null +++ b/docs/_api-inspection/lastOptions.md @@ -0,0 +1,7 @@ +--- +title: .lastOptions(filter, options) +navTitle: .lastOptions() +position: 5 +description: |- + Returns the options for the call to `fetch` matching the given filter. If `fetch` was last called using a `Request` instance, a set of `options` inferred from the `Request` will be returned +--- diff --git a/docs/_api-inspection/lastUrl.md b/docs/_api-inspection/lastUrl.md new file mode 100644 index 00000000..88436a42 --- /dev/null +++ b/docs/_api-inspection/lastUrl.md @@ -0,0 +1,7 @@ +--- +title: .lastUrl(filter, options) +navTitle: .lastUrl() +position: 4 +description: |- + Returns the url for the last call to `fetch` matching the given filter. If `fetch` was last called using a `Request` instance, the url will be extracted from this +--- diff --git a/docs/_api-lifecycle/flush.md b/docs/_api-lifecycle/flush.md new file mode 100644 index 00000000..8716ae35 --- /dev/null +++ b/docs/_api-lifecycle/flush.md @@ -0,0 +1,12 @@ +--- +title: .flush(waitForBody) +navTitle: ".flush()" +position: 2 +description: |- + Returns a `Promise` that resolves once all fetches handled by fetch-mock have resolved +content_markdown: |- + Useful for testing code that uses `fetch` but doesn't return a promise. + + Pass in `true` to wait for all body parsing methods (`res.json()`, `res.text()`, etc.) to resolve too. + {: .info} +--- diff --git a/docs/_api-lifecycle/resetHistory.md b/docs/_api-lifecycle/resetHistory.md new file mode 100644 index 00000000..0e2a8baa --- /dev/null +++ b/docs/_api-lifecycle/resetHistory.md @@ -0,0 +1,6 @@ +--- +title: .resetHistory() +position: 4 +description: |- + Clears all data recorded for `fetch()`'s calls. It _will not_ restore fetch to its default implementation +--- diff --git a/docs/_api-lifecycle/restore_reset.md b/docs/_api-lifecycle/restore_reset.md new file mode 100644 index 00000000..c710228b --- /dev/null +++ b/docs/_api-lifecycle/restore_reset.md @@ -0,0 +1,20 @@ +--- +title: .restore(), .reset() +navTitle: .restore(), .reset() +position: 3 +description: |- + Restores `fetch()` to its unstubbed state and clears all data recorded for its calls. `reset()` is an alias for `restore()` +--- + +#### `` + +Chainable method that . + +#### `resetHistory()` + +Chainable method that clears all data recorded for `fetch()`'s calls. _It will not restore fetch to its default implementation_ + +_Note that `restore()`, `reset()` and `resetHistory()` are all bound to fetchMock, and can be used directly as callbacks e.g. `afterEach(fetchMock.reset)` will work just fine. There is no need for `afterEach(function () {fetchMock.reset()})`_ + +#### `flush()` + diff --git a/docs/_api-lifecycle/sandbox.md b/docs/_api-lifecycle/sandbox.md new file mode 100644 index 00000000..c9d23e2a --- /dev/null +++ b/docs/_api-lifecycle/sandbox.md @@ -0,0 +1,14 @@ +--- +title: ".sandbox()" +position: 1.0 +description: |- + Returns a drop-in mock for fetch which can be passed to other mocking libraries. It implements the full fetch-mock api and maintains its own state independent of other instances, so tests can be run in parallel. +left_code_blocks: + - code_block: |- + fetchMock + .sandbox() + .mock('http://domain.com', 200) + title: Example + language: javascript + +--- diff --git a/docs/_api-mocking/_defaults.md b/docs/_api-mocking/_defaults.md new file mode 100644 index 00000000..0b832f22 --- /dev/null +++ b/docs/_api-mocking/_defaults.md @@ -0,0 +1,16 @@ +--- +title: +position: +parameters: + - name: + content: +content_markdown: +left_code_blocks: + - code_block: + title: + language: +right_code_blocks: + - code_block: + title: + language: +--- diff --git a/docs/_api-mocking/catch.md b/docs/_api-mocking/catch.md new file mode 100644 index 00000000..1bf42875 --- /dev/null +++ b/docs/_api-mocking/catch.md @@ -0,0 +1,12 @@ +--- +title: ".catch(response)" +navTitle: .catch() +position: 5 +description: |- + Specifies how to respond to calls to `fetch` that don't match any mocks. +parentMethodGroup: mocking +content_markdown: |- + It accepts any valid [fetch-mock response](/#api-mockingmock_response), and can also take an arbitrary function to completely customise behaviour. If no argument is passed, then every unmatched call will receive a `200` response +--- + + diff --git a/docs/_api-mocking/getOnce_postOnce.md b/docs/_api-mocking/getOnce_postOnce.md new file mode 100644 index 00000000..98ea7b8a --- /dev/null +++ b/docs/_api-mocking/getOnce_postOnce.md @@ -0,0 +1,8 @@ +--- +title: ".getOnce(), .postOnce(), .putOnce(), .deleteOnce(), .headOnce(), .patchOnce()" +navTitle: .getOnce(), .postOnce() ... +position: 4 +description: |- + Shorthands for `mock()` restricted to a particular method and that will only respond once +parentMethodGroup: mocking +--- diff --git a/docs/_api-mocking/get_post.md b/docs/_api-mocking/get_post.md new file mode 100644 index 00000000..15b3cd34 --- /dev/null +++ b/docs/_api-mocking/get_post.md @@ -0,0 +1,21 @@ +--- +title: ".get(), .post(), .put(), .delete(), .head(), .patch()" +navTitle: .get(), .post() ... +position: 3 +description: |- + Shorthands for `mock()` restricted to a particular method. +parentMethodGroup: mocking +content_markdown: |- + If you use some other method a lot you can easily define your own shorthands e.g. + {: .info} + + ```javascript + fetchMock.purge = function (matcher, response, options) { + return this.mock( + matcher, + response, + Object.assign({}, options, {method: 'PURGE'}) + ); + } + ``` +--- diff --git a/docs/_api-mocking/mock.md b/docs/_api-mocking/mock.md new file mode 100644 index 00000000..f07dc08d --- /dev/null +++ b/docs/_api-mocking/mock.md @@ -0,0 +1,77 @@ +--- +title: ".mock(matcher, response, options)" +navTitle: .mock() +position: 1.0 +description: "Replaces `fetch` with a stub which records its calls and returns a `Response` instance." +parameters: + - name: matcher + types: + - String + - Regex + - Function + content: Rule for matching calls to `fetch` + - name: response + types: + - String + - Object + - Function + - Promise + - Response + content: Response to send matched calls + - name: options + types: + - Object + content: More options configuring [mainly] matching behaviour +content_markdown: |- + + Alternatively a single parameter, `options`, an Object with `matcher`, `response` and other options defined, can be passed + {: .info} + +left_code_blocks: + - code_block: |- + fetchMock + .mock('http://it.at.here/route', 200) + .mock('begin:http://it', 200) + .mock('end:here/route', 200) + .mock('path:/route', 200) + .mock('*', 200) + title: Strings + language: javascript + - code_block: |- + fetchMock + .mock(/.*\.here.*/, 200) + .mock((url, opts) => opts.method === 'patch', 200) + .mock('express:/:type/:id', 200, { + params: { + type: 'shoe' + } + }) + title: Complex Matchers + language: javascript + - code_block: |- + fetchMock + .mock('*', 'ok') + .mock('*', 404) + .mock('*', {results: []}) + .mock('*', {throw: new Error('Bad kitty'))) + .mock('*', new Promise(res => setTimeout(res, 1000, 404))) + title: Responses + language: javascript + - title: End to end example + language: javascript + code_block: |- + fetchMock + .mock('begin:http://it.at.here/api', 200, { + headers: { + authorization: 'Basic dummy-token' + } + }) + .mock('begin:http://it.at.here/api', 403) + + callApi('/endpoint', 'dummy-token') + .then(res => { + expect(res.status).to.equal(200) + }) +--- + + diff --git a/docs/_api-mocking/mock_matcher.md b/docs/_api-mocking/mock_matcher.md new file mode 100644 index 00000000..c4146360 --- /dev/null +++ b/docs/_api-mocking/mock_matcher.md @@ -0,0 +1,90 @@ +--- +title: "matcher" +position: 1.1 +description: |- + Condition for selecting which requests to mock. For matching based on headers, query strings or other `fetch` options see the `options` parameter documented below +types: + - String + - RegExp + - Function +type: parameter +parametersBlockTitle: Argument values +parentMethod: mock +parentMethodGroup: mocking +parameters: + - name: "*" + types: + - String + content: Matches any url + examples: + - '"*"' + - name: url + types: + - String + examples: + - |- + "http://www.site.com/page.html" + content: Matches an exact url + - name: |- + begin:... + types: + - String + examples: + - |- + "begin:http://www.site.com" + content: Matches a url beginning with a string + - name: |- + end:... + types: + - String + examples: + - |- + "end:.jpg" + content: Matches a url ending with a string + - name: |- + path:... + types: + - String + examples: + - |- + "path:/posts/2018/7/3" + content: Matches a url which has a given path + - name: |- + glob:... + types: + - String + examples: + - |- + "glob:http://*.*" + content: Matches a url using a glob pattern + - name: |- + express:... + types: + - String + examples: + - |- + "express:/user/:user" + content: |- + Matches a [relative] url that matches an [express style path](https://www.npmjs.com/package/path-to-regexp) + - types: + - RegExp + examples: + - |- + /(article|post)/\d+/ + content: Matches a url that matches a regular expression + - types: + - Function + examples: + - |- + (url, {headers}) => !!headers.Authorization + - |- + (_, _, request) => !!request.headers.get('Authorization') + content: Matches if a function returns something truthy. The function will be passed the arguments `fetch` was called with. If `fetch` was called with a `Request` instance, it will be passed `url` and `options` inferred from the `Request` instance. The original `Request` will be passed as a third argument. + + +content_markdown: |- + Note that if using `end:` or an exact url matcher, fetch-mock ([for good reason](https://url.spec.whatwg.org/#url-equivalence)) is unable to distinguish whether URLs without a path end in a trailing slash or not i.e. `http://thing` is treated the same as `http://thing/` + {: .warning} +--- + + diff --git a/docs/_api-mocking/mock_once.md b/docs/_api-mocking/mock_once.md new file mode 100644 index 00000000..4f961d83 --- /dev/null +++ b/docs/_api-mocking/mock_once.md @@ -0,0 +1,7 @@ +--- +title: ".once()" +position: 2 +description: |- + Shorthand for `mock()` which limits to being called one time only. (see `repeat` option above) +parentMethodGroup: mocking +--- diff --git a/docs/_api-mocking/mock_options.md b/docs/_api-mocking/mock_options.md new file mode 100644 index 00000000..cdfda10a --- /dev/null +++ b/docs/_api-mocking/mock_options.md @@ -0,0 +1,62 @@ +--- +title: "options" +position: 1.3 +description: |- + A configuration object with properties to define a route to mock +types: + - Object +type: parameter +parametersBlockTitle: Options +parentMethod: mock +parentMethodGroup: mocking +parameters: + - name: name + types: + - String + content: |- + A unique string naming the route. Used to subsequently retrieve references to the calls, grouped by name. Defaults to `matcher.toString()` + - name: method + types: + - String + content: |- + Http method to match + - name: headers + types: + - Object + - Headers + content: |- + Key/value map of headers to match + - name: query + types: + - Object + content: |- + Key/value map of query strings to match, in any order + - name: params + types: + - Object + content: |- + When the `express:` keyword is used in a string matcher, a key/value map `params` can be passed here, to match the parameters extracted by express path matching + - name: repeat + types: + - Integer + content: |- + An integer, `n`, limiting the number of times the matcher can be used. If the route has already been called `n` times the route will be ignored and the call to `fetch()` will fall through to be handled by any other routes defined (which may eventually result in an error if nothing matches it) + - name: overwriteRoutes + types: + - Boolean + content: See [global configuration](#usageconfiguration) + - name: sendAsJson + default: true + types: + - Boolean + content: See [global configuration](#usageconfiguration) + - name: includeContentLength + default: true + types: + - Boolean + content: See [global configuration](#usageconfiguration) + - name: matcher + content: When using the single argument variant of `.mock()`, any valid matcher as [defined above](#usageapimock_matcher) can be assigned to the options object + - name: response + content: When using the single argument variant of `.mock()`, any valid response as [defined above](#usageapimock_response) can be assigned to the options object +--- diff --git a/docs/_api-mocking/mock_response.md b/docs/_api-mocking/mock_response.md new file mode 100644 index 00000000..c5c0d936 --- /dev/null +++ b/docs/_api-mocking/mock_response.md @@ -0,0 +1,92 @@ +--- +title: "response" +position: 1.2 +description: |- + Response to send matched calls. + Configures the http response returned by the mock. Can take any of the following values (or be a `Promise` for any of them, enabling full control when testing race conditions etc.). Unless otherwise stated, all responses have a `200` status +types: + - String + - Object + - Function + - Promise + - Response +type: parameter +parametersBlockTitle: Argument values +parentMethod: mock +parentMethodGroup: mocking +parameters: + - types: + - Response + examples: + - "new Response('ok', {status: 200})" + content: A `Response` instance - will be used unaltered + - name: status code + types: + - Integer + examples: + - 200, 404, 503 + content: Creates a response with the given status code. The response's `statusText` will also be set to the [default value corresponding to the status](https://fetch.spec.whatwg.org/#dom-response-statustext) + - types: + - String + content: Creates a 200 response with the string as the response body + examples: + - Server responded ok + - Bad Response + - name: config + types: + - Object + content: If an object _only_ contains properties listed below it is used to configure a `Response` + options: + - name: body + types: + - String + - Object + content: |- + Set the response body. For behaviour for `Object`s, see the non-config `Object` section of the docs below + examples: + - Server responded ok + - { token: 'abcdef' } + - name: status + types: + - Integer + content: Set the response status + examples: + - 200, 404, 503 + - name: headers + types: + - Object + content: Set the response headers + examples: + - {'Content-Type': 'text/html'} + - name: redirectUrl + types: + - String + content: |- + The url the response should claim to originate from (to imitate followed directs). Will also set `redirected: true` on the response + - name: throws + types: + - Error + content: |- + `fetch` will return a `Promise` rejected with the value of `throws` + examples: + - "new TypeError('Failed to fetch')" + - types: + - Object + - ArrayBuffer + content: |- + All objects that do not meet the criteria above will be converted to JSON and set as the response `body` if the `sendAsJson` option is on. Otherwise, they will be set as the response `body` (useful for array buffers etc.) + - types: + - Promise + content: |- + A `Promise` that resolves to any of the options documented above + examples: + - "new Promise(res => setTimeout(() => res(200), 50))" + - types: + - Function + content: |- + A function that is passed the arguments `fetch` is called with and that returns any of the responses listed above + examples: + - "(url, opts) => opts.headers.Authorization ? 200 : 403" + - "(_, _, request) => request.headers.get('Authorization') ? 200 : 403" + +--- diff --git a/docs/_api-mocking/spy.md b/docs/_api-mocking/spy.md new file mode 100644 index 00000000..ed66821b --- /dev/null +++ b/docs/_api-mocking/spy.md @@ -0,0 +1,11 @@ +--- +title: ".spy()" +navTitle: .spy() +position: 6 +description: |- + Records call history while passing each call on to `fetch` to be handled by the network +parentMethodGroup: mocking +content_markdown: |- + To use `.spy()` on a sandboxed `fetchMock`, `fetchMock.config.fetch` must be set to a reference to the `fetch` implementation you use in your code. + {: .warning} +--- diff --git a/docs/_config.yml b/docs/_config.yml index b7e0752a..f753773f 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,4 +1,80 @@ -markdown: kramdown -theme: jekyll-theme-slate +# ---- +# Site + title: fetch-mock -description: Mock http requests made using fetch +description: Mock http requests using fetch +url: https://www.wheresrhys.co.uk/fetch-mock-docs-workspace +google_analytics_key: +permalink: pretty + +# ----- +# Build + +timezone: Etc/UTC + +collections: + about: + title: About + position: 0 + usage: + title: Usage + position: 1 + api-mocking: + title: Mocking API + position: 2 + api-lifecycle: + title: Lifecycle methods + position: 3 + api-inspection: + title: Inspection methods + position: 3 + troubleshooting: + title: Troubleshooting + position: 4 +plugins: + - jekyll-sitemap + - jekyll-seo-tag + +exclude: + - readme.md + - LICENSE + +defaults: + - + scope: + path: "" + values: + layout: default + - + scope: + type: "about" + values: + _hide_content: true + - + scope: + type: "general" + values: + _hide_content: true + - + scope: + type: "api" + values: + _hide_content: true + +# ----------- +# CloudCannon +languages: + bash: Bash + javascript: JavaScript + +_options: + content_markdown: + format: p h4 h5 h6 + bold: true + italic: true + link: true + bulletedlist: true + numberedlist: true + image: true + table: true + styles: /css/editor.css diff --git a/docs/_includes/relative-src.html b/docs/_includes/relative-src.html new file mode 100644 index 00000000..45354481 --- /dev/null +++ b/docs/_includes/relative-src.html @@ -0,0 +1 @@ +{% assign prefix = include.src | slice: 0, 2 %}{% assign protocol = include.src | slice: 0, 4 %}{% unless protocol == 'http' or prefix == "//" %}{{ site.baseurl }}{% endunless %}{{ include.src }} \ No newline at end of file diff --git a/docs/_includes/sidebar.html b/docs/_includes/sidebar.html new file mode 100644 index 00000000..a93e2be4 --- /dev/null +++ b/docs/_includes/sidebar.html @@ -0,0 +1,21 @@ + diff --git a/docs/_includes/syntax-highlight.html b/docs/_includes/syntax-highlight.html new file mode 100644 index 00000000..cfdf54ef --- /dev/null +++ b/docs/_includes/syntax-highlight.html @@ -0,0 +1,8 @@ +{% capture highlight %} +``` {{ include.block.language }} +{{ include.block.code_block }} +``` +{: title="{{ include.block.title }}" } +{% endcapture %} + +{{ highlight | markdownify }} \ No newline at end of file diff --git a/docs/_includes/tiny-syntax.html b/docs/_includes/tiny-syntax.html new file mode 100644 index 00000000..6fe695a9 --- /dev/null +++ b/docs/_includes/tiny-syntax.html @@ -0,0 +1,7 @@ +{% capture highlight %} +``` javascript +{{ example }} +``` +{% endcapture %} + +{{ highlight | markdownify }} diff --git a/docs/_includes/types.html b/docs/_includes/types.html new file mode 100644 index 00000000..3030c697 --- /dev/null +++ b/docs/_includes/types.html @@ -0,0 +1,12 @@ +{{ include.block.name }} +
+{% if include.block.types %} + {% for type in include.block.types %} + {{type}} + {% if forloop.last != true %}|{% endif %} + {% endfor %} +{% endif %} +{%if include.block.default %} + [default {{ include.block.default}}] +{% endif %} +
diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 00000000..abdc1f09 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,43 @@ + + + + + + + {% seo %} + + + + + {% if jekyll.environment == 'production' and site.google_analytics_key != '' %} + + + {% endif %} + + + + + + +
+ {{ content }} +
+ + + diff --git a/docs/_sass/_borland.scss b/docs/_sass/_borland.scss new file mode 100644 index 00000000..6ff9c632 --- /dev/null +++ b/docs/_sass/_borland.scss @@ -0,0 +1,58 @@ +code .hll { background-color: #ffffcc } +code .c { color: #aaaaaa; font-style: italic } /* Comment */ +code .err { color: #F00000; background-color: #F0A0A0 } /* Error */ +code .k { color: #0000aa } /* Keyword */ +code .cm { color: #aaaaaa; font-style: italic } /* Comment.Multiline */ +code .cp { color: #4c8317 } /* Comment.Preproc */ +code .c1 { color: #aaaaaa; font-style: italic } /* Comment.Single */ +code .cs { color: #0000aa; font-style: italic } /* Comment.Special */ +code .gd { color: #aa0000 } /* Generic.Deleted */ +code .ge { font-style: italic } /* Generic.Emph */ +code .gr { color: #aa0000 } /* Generic.Error */ +code .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +code .gi { color: #00aa00 } /* Generic.Inserted */ +code .go { color: #888888 } /* Generic.Output */ +code .gp { color: #555555 } /* Generic.Prompt */ +code .gs { font-weight: bold } /* Generic.Strong */ +code .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +code .gt { color: #aa0000 } /* Generic.Traceback */ +code .kc { color: #0000aa } /* Keyword.Constant */ +code .kd { color: #0000aa } /* Keyword.Declaration */ +code .kn { color: #0000aa } /* Keyword.Namespace */ +code .kp { color: #0000aa } /* Keyword.Pseudo */ +code .kr { color: #0000aa } /* Keyword.Reserved */ +code .kt { color: #00aaaa } /* Keyword.Type */ +code .m { color: #009999 } /* Literal.Number */ +code .s { color: #aa5500 } /* Literal.String */ +code .na { color: #1e90ff } /* Name.Attribute */ +code .nb { color: #00aaaa } /* Name.Builtin */ +code .nc { color: #00aa00; text-decoration: underline } /* Name.Class */ +code .no { color: #aa0000 } /* Name.Constant */ +code .nd { color: #888888 } /* Name.Decorator */ +code .ni { color: #800000; font-weight: bold } /* Name.Entity */ +code .nf { color: #00aa00 } /* Name.Function */ +code .nn { color: #00aaaa; text-decoration: underline } /* Name.Namespace */ +code .nt { color: #1e90ff; font-weight: bold } /* Name.Tag */ +code .nv { color: #aa0000 } /* Name.Variable */ +code .ow { color: #0000aa } /* Operator.Word */ +code .w { color: #bbbbbb } /* Text.Whitespace */ +code .mf { color: #009999 } /* Literal.Number.Float */ +code .mh { color: #009999 } /* Literal.Number.Hex */ +code .mi { color: #009999 } /* Literal.Number.Integer */ +code .mo { color: #009999 } /* Literal.Number.Oct */ +code .sb { color: #aa5500 } /* Literal.String.Backtick */ +code .sc { color: #aa5500 } /* Literal.String.Char */ +code .sd { color: #aa5500 } /* Literal.String.Doc */ +code .s2 { color: #aa5500 } /* Literal.String.Double */ +code .se { color: #aa5500 } /* Literal.String.Escape */ +code .sh { color: #aa5500 } /* Literal.String.Heredoc */ +code .si { color: #aa5500 } /* Literal.String.Interpol */ +code .sx { color: #aa5500 } /* Literal.String.Other */ +code .sr { color: #009999 } /* Literal.String.Regex */ +code .s1 { color: #aa5500 } /* Literal.String.Single */ +code .ss { color: #0000aa } /* Literal.String.Symbol */ +code .bp { color: #00aaaa } /* Name.Builtin.Pseudo */ +code .vc { color: #aa0000 } /* Name.Variable.Class */ +code .vg { color: #aa0000 } /* Name.Variable.Global */ +code .vi { color: #aa0000 } /* Name.Variable.Instance */ +code .il { color: #009999 } /* Literal.Number.Integer.Long */ diff --git a/docs/_sass/_docs.scss b/docs/_sass/_docs.scss new file mode 100644 index 00000000..11f2d7c6 --- /dev/null +++ b/docs/_sass/_docs.scss @@ -0,0 +1,183 @@ +.docs { + section { + p, pre, ul { + max-width: 55rem + } + } + + ul { + margin-top: 0; + } + h1, h2, h3, h4, h5, h6 { + margin-top: 0; + font-weight: 300; + } + + h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;} + h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; } + h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; } + h2 { + margin-bottom: 0; + } + h4 { + font-size: 2.4rem; + line-height: 1.35; + letter-spacing: -.08rem; + margin: 0 0 5px 0; + } + + h5 { + font-size: 1.8rem; + line-height: 1.5; + letter-spacing: -.05rem; + } + + p { + margin-top: 0; + } + + h3 a { + text-decoration: none; + color: #474a54; + } + + h3 a:hover { + text-decoration: none; + color: #474a54; + } + a { + color: #1EAEDB; text-decoration: none; + } + + a:hover { + color: #0FA0CE; text-decoration: underline; + } + + pre { + white-space: pre-wrap; + font-size: 1em; + margin: 22px 0; + word-wrap: break-word; + border: 0px; + box-shadow: 0 0 0 1px #eee; + border-radius: 3px; + padding: 10px; + } + + dt code, + dt sup { + color: #aa5500; + } + +} + + + +.types-zone { + // font-family: monospace; + font-size: 0.9em; +} + +dl.options .types-zone { + // font-family: monospace; + font-size: 1em; +} +.default, +dt code { + font-family: monospace; +} + +.types-zone code { + font-family: monospace; + font-weight: bold; + background: none; + color: #aa5500; +} + +.default { + color: #888; +} + + + +p > code, +dt > code.name, +dd > code, +li > code { + font-size: 1.2em; + font-family: monospace; + font-weight: bold; + background: none; + color: #aa5500; +} + + +.error, .warning, .info, .success { + border-left: 5px solid #FD0; + padding: 1rem 2rem; + background-color: #FAFAFA; + border-radius: 2px; +} + +.warning { + border-color: #ffc107; +} + +.info { + border-color: #56ADEC; +} + +.error { + border-color: #F20; +} + +.success { + border-color: #6c0; +} + + +.code-viewer { + .languages { + padding: 0; + margin: 0 0 5px 0; + list-style: none; + font-size: .9em; + + li { + display: inline-block; + + a { + display: block; + padding: 5px 10px; + z-index: 100; + border: 1px solid transparent; + + &:hover { + border-color: #eee; + border-radius: 5px; + } + + &.active:hover { + border-color: transparent; + } + } + } + } + + a { + text-decoration: none; + color: #aaa; + + &:hover { + color: #222; + } + } + + pre { + margin: 0 0 2rem 0; + } +} + +.code-viewer a.active, .code-viewer a.active:hover, .right-code .code-viewer a.active:hover { + color: #1EAEDB; +} diff --git a/docs/_sass/_layout.scss b/docs/_sass/_layout.scss new file mode 100644 index 00000000..fb49f2e2 --- /dev/null +++ b/docs/_sass/_layout.scss @@ -0,0 +1,117 @@ +html { + font-size: 62.5%; + color: #474a54; + background: #fff; + height: 100vh; +} + +html, body { + padding: 0; + margin: 0; +} + +body { + display: grid; + grid-template-columns: 1fr; + grid-template-areas: "navigation" "main"; + background: #fff; + font-size: 1.8rem; + line-height: 1.6; + font-weight: 400; + font-family: system, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Lucida Grande", sans-serif; +} + +body, main { + box-sizing: border-box; + min-height: 100vh; +} + +main { + grid-area: main; + height: 100vh; + overflow-y: scroll; + margin-top: 6rem; +} + +:target { + margin-top: -8rem; + padding-top: 8rem +} + +.docs { + display: grid; + padding-top: 2rem; + grid-gap: 2rem; + grid-template-columns: 1fr 55rem 1fr; +} + +.docs:last-of-type { + margin-bottom: 3rem +} + +section, h2 { + grid-column-start: 2; + grid-column-end: 3; + box-sizing: border-box; +} + +section { + padding-top: 2rem +} + +@media only screen and (min-width:$mobile-break) { + body { + grid-template-columns: 25rem 1fr; + grid-template-areas: "navigation main"; + } + main { + margin-top: 0; + } + :target { + margin-top: -2rem; + padding-top: 2rem; + } + .docs { + grid-template-columns: minmax(0, 8rem) 70rem minmax(8rem, 1fr); + section { + display: grid; + grid-template-columns: 55rem 15rem; + } + + section > * { + grid-column: 1 / 2 + } + + section > dl { + grid-column: 1 / 3 + } + } + +} + +@media only screen and (min-width:75rem) { + body { + grid-template-columns: 30rem 1fr; + } +} + +.navigation { + grid-area: navigation; +} + +.docs:first-child { + display: none; +} + +.docs:not(:nth-child(2)), +.docs section:not(:first-of-type) { + background: #fff; + padding-bottom: 0; + border-top:1px solid #eee; +} + +.docs section:first-of-type { + padding-top: 0; +} + + diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss new file mode 100644 index 00000000..6948006d --- /dev/null +++ b/docs/_sass/_main.scss @@ -0,0 +1,264 @@ +body { + + &.nav-open { + overflow: hidden; + + header { + bottom: 0; + } + } +} + + +em { + text-decoration: underline +} + + + +.doc-content { + border: 0; + border-bottom: 1px solid #eee; + padding: 30px 0; +} + +.doc-content:after { + visibility: hidden; + display: block; + content: ""; + clear: both; + height: 0; +} + +.doc-content:last-child { + border: 0; +} + +.left-docs { + width: 100%; + float: left; + padding: 0 50px; + box-sizing: border-box; + + p, pre, ul, dd { + max-width: 560px + } + + dd { + max-width: 400px + } +} +.code-viewer { + .languages { + padding: 0; + margin: 0 0 5px 0; + list-style: none; + font-size: .9em; + + li { + display: inline-block; + + a { + display: block; + padding: 5px 10px; + z-index: 100; + border: 1px solid transparent; + + &:hover { + border-color: #eee; + border-radius: 5px; + } + + &.active:hover { + border-color: transparent; + } + } + } + } + + a { + text-decoration: none; + color: #aaa; + + &:hover { + color: #222; + } + + + } + + pre { + margin: 0 0 20px 0; + } +} + +.code-viewer a.active, .code-viewer a.active:hover, .right-code .code-viewer a.active:hover { + color: #1EAEDB; +} + + +.right-code .code-viewer a:hover { + color: #fff; +} + +@media (max-width: 1000px) { + + .left-docs { + float: none; + width: 100%; + } + + .doc-content { + background: #fff; + padding-bottom: 0; + border-image: none; + -moz-border-image: none; + -webkit-border-image: none; + border-color: #eee; + } +} + +.navigation { + max-height: 100vh; + position: fixed; + top: 0; + left: 0; + right: 0; + overflow-x: hidden; + z-index: 1; + background-color: $nav-background-color; + + h1 { + height: $nav-header-height; + box-sizing: border-box; + background-color: $brand-colour; + color: #fff; + margin: 0; + font-size: 1.7rem; + line-height: 0.8; + letter-spacing: 0; + font-weight: 600; + text-indent: 0; + @include display-flex(); + @include flex-direction(row); + @include align-items(center); + border-bottom: 1px solid rgba(0, 0, 0, 0.075); + + img { + height: 26px; + margin: 0 18px; + } + } + + .open-nav { + width: 25px; + height: 25px; + margin: 0 0 0 18px; + background-image: url($base-url + '/images/menu.svg'); + background-color: transparent; + background-repeat: no-repeat; + background-size: 100%; + border: 0; + position: relative; + border-radius: 2px; + cursor: pointer; + + &:focus { + outline: none; + background-color: rgba(0, 0, 0, 0.05); + } + + &:hover { + background-color: rgba(0, 0, 0, 0.1); + } + } + + @media (min-width: $mobile-break) { + background-color: transparent; + width: $nav-width; + right: auto; + bottom: auto; + + .copyright { + display: block; + } + + .open-nav { + display: none; + } + + h1 { + box-shadow: inset -10px 0 10px -10px rgba(0, 0, 0, 0.1); + } + } +} + +.copyright { + text-align: center; + font-size: .6em; + margin: 30px 0 0 0; + display: none; +} + + +@mixin flex-direction($values) { + -webkit-flex-direction: $values; + flex-direction: $values; +} + +@mixin flex-flow($values) { + -webkit-flex-flow: $values; + flex-flow: $values; +} + +@mixin align-items($values) { + -webkit-align-items: $values; + align-items: $values; +} + +@mixin justify-content($values) { + -webkit-justify-content: $values; + justify-content: $values; +} + +@mixin flex($values) { + -webkit-flex: $values; + flex: $values; +} + +@mixin display-flex() { + display: -webkit-flex; + display: flex; +} + +@mixin display-inline-flex() { + display: -webkit-inline-flex; + display: inline-flex; +} + +.editor-link { + display: none; + float: right; + margin-top: 0; + border: 0; + border-radius: 2px; + box-sizing: border-box; + font-size: 2rem; + text-decoration: none; + padding: 10px 15px; + margin: 0; + font-size: 18px; + cursor: pointer; + background-color: #f7e064; + color: #333; + box-shadow: 1px 1px 5px 0 rgba(0, 0, 0, 0.2); + + &:hover { + background-color: #f4d525; + color: #333; + } +} + +.cms-editor-active .editor-link { + display: inline-block; +} diff --git a/docs/_sass/_navigation.scss b/docs/_sass/_navigation.scss new file mode 100644 index 00000000..c2b9ae46 --- /dev/null +++ b/docs/_sass/_navigation.scss @@ -0,0 +1,175 @@ +.navigation { + max-height: 100vh; + position: fixed; + top: 0; + left: 0; + right: 0; + overflow-x: hidden; + z-index: 1; +} + +nav { + display: none; +} + +body.nav-open { + overflow: hidden; + + .navigation { + bottom: 0; + } + + nav { + display: block + } +} + +@media only screen and (min-width:$mobile-break) { + .navigation { + position: static; + overflow-y: scroll; + } + nav { + display: block + } + + .open-nav { + display: none; + } +} + + + + + +// nav a { +// padding: 10px 0; +// } + +.navigation { + background-color: $nav-background-color; + + .site-title { + height: 6rem; + position: relative; + box-sizing: border-box; + background-color: #00994D; + text-align: center; + line-height: 6rem; + margin: 0; + font-size: 4.0rem; + letter-spacing: -.1rem; + + + a { + color: #fff; + text-decoration: none; + + + } + } + + nav { + padding: 0 2rem 4rem; + } + section h1 { + font-size: 2.4rem; + line-height: 1.35; + letter-spacing: -.08rem; + margin: 0 0 5px 0; + font-weight: 300; + + } + + section { + ul { + margin: 0; + padding: 0; + list-style: none; + } + li { + padding-left: 2rem + } + li.parameter { + padding-left: 4rem; + font-size: 0.9em; + } + a { + color: #777; + text-decoration: none; + font-size: .90em; + display: block; + width: 100%; + text-overflow: ellipsis; + overflow: hidden; + padding: 2px 0; + + &.active { + color: #2196F3; + text-decoration: none; + } + } + } + + // height: $nav-header-height; + // + // background-color: $brand-colour; + // color: #fff; + // margin: 0; + // font-size: 1.7rem; + // line-height: 0.8; + // letter-spacing: 0; + // font-weight: 600; + // text-indent: 0; + // @include display-flex(); + // @include flex-direction(row); + // @include align-items(center); + // border-bottom: 1px solid rgba(0, 0, 0, 0.075); + // img { + // height: 26px; + // margin: 0 18px; + // } + // } + + .open-nav { + width: 4rem; + height: 4rem; + left: 1rem; + top: 1rem; + position: absolute; + background-image: url($base-url + '/images/menu.svg'); + background-color: transparent; + background-repeat: no-repeat; + background-size: 100%; + border: 0; + border-radius: 2px; + cursor: pointer; + + &:focus { + outline: none; + background-color: rgba(0, 0, 0, 0.05); + } + + &:hover { + background-color: rgba(0, 0, 0, 0.1); + } + } + + // @media (min-width: $mobile-break) { + // background-color: transparent; + // width: $nav-width; + // right: auto; + // bottom: auto; + + // .copyright { + // display: block; + // } + + + + // h1 { + // box-shadow: inset -10px 0 10px -10px rgba(0, 0, 0, 0.1); + // } + // } + +} diff --git a/docs/_sass/_tables.scss b/docs/_sass/_tables.scss new file mode 100644 index 00000000..b52e2cfe --- /dev/null +++ b/docs/_sass/_tables.scss @@ -0,0 +1,37 @@ +dl { + display: grid; + grid-gap: 1rem; + grid-template-columns: 25% 1fr; +} + +dl.parameters { + border-top: 1px solid #eee; + border-bottom: 1px solid #eee; + padding: 0 0 20px 0; + margin: 0 0 20px 0; +} + +dl.options { + border-color: #eee; + border-top-width: 1px; + border-top-style: solid; + border-left-width: 5px; + border-left-style: solid; + padding-left: 2rem; + padding-top: 1rem; + margin-left: -40%; + font-size: 0.9em; +} + +dt { + grid-column-start: 1; + grid-column-end: 2; + font-weight: bold; +} + +dd { + grid-column-start: 2; + grid-column-end: 3; +} + + diff --git a/docs/_site/README.md b/docs/_site/README.md deleted file mode 100644 index 819b23af..00000000 --- a/docs/_site/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Aviator - -API documentation template for Jekyll. Browse through a [live demo](https://tangerine-lemon.cloudvent.net/). -Start documenting your API with this configurable theme. - -![Aviator template screenshot](images/_screenshot.png) - -Aviator was made by [CloudCannon](http://cloudcannon.com/), the Cloud CMS for Jekyll. - -Find more templates, themes and step-by-step Jekyll tutorials at [CloudCannon Academy](https://learn.cloudcannon.com/). - -## Features - -* Three column layout -* Fully responsive -* Full text search -* Pre-styled components -* Auto-generated navigation based on category -* Optimised for editing in [CloudCannon](http://cloudcannon.com/) -* SEO tags -* Google Analytics - -## Setup - -1. Add your site and author details in `_config.yml`. -2. Get a workflow going to see your site's output (with [CloudCannon](https://app.cloudcannon.com/) or Jekyll locally). - -## Develop - -Aviator was built with [Jekyll](http://jekyllrb.com/) version 3.7.2, but should support newer versions as well. - -Install the dependencies with [Bundler](http://bundler.io/): - -~~~bash -$ bundle install -~~~ - -Run `jekyll` commands through Bundler to ensure you're using the right versions: - -~~~bash -$ bundle exec jekyll serve -~~~ - -## Editing - -Aviator is already optimised for adding, updating and removing documentation pages in CloudCannon. - -### Usage - -* Each section is a different collection, this helps organise your content. -* Set the order of the collections with the position field in collection configuration in `_config.yml`. -* Set the order of the documents inside a collection by setting the position in front matter. - -### Search - -* Add `excluded_in_search: true` to any documentation page's front matter to exclude that page in the search results. diff --git a/docs/_site/apple-touch-icon.png b/docs/_site/apple-touch-icon.png deleted file mode 100644 index 815caab2..00000000 Binary files a/docs/_site/apple-touch-icon.png and /dev/null differ diff --git a/docs/_site/css/style.css b/docs/_site/css/style.css deleted file mode 100644 index 42a8e893..00000000 --- a/docs/_site/css/style.css +++ /dev/null @@ -1,674 +0,0 @@ -html, body { - padding: 0; - margin: 0; } - -body, .main { - box-sizing: border-box; - min-height: 100vh; } - -html { - font-size: 62.5%; - color: #474a54; - background: #232323; - height: 100vh; } - -img { - max-width: 100%; } - -@media (max-width: 700px) { - .sidebar, header > form { - display: none; } - - .sidebar h6 { - font-size: 1.4em; } - - .sidebar a { - padding: 10px 0; } - - body .main { - margin: 45px 0 0 0; } } -body { - font-size: 1.8em; - line-height: 1.6; - font-weight: 400; - font-family: system, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Lucida Grande", sans-serif; - background: #fbfbfb; } - body.nav-open { - overflow: hidden; } - body.nav-open .sidebar, - body.nav-open header > form { - display: block; } - body.nav-open header { - bottom: 0; } - -table { - border: 1px solid #E1E1E1; - margin: 0 0 20px 0; - border-collapse: collapse; } - -th, td { - border: 1px solid #ccc; - padding: 10px; - font-size: .9em; - text-align: left; } - -th { - background: #f7f7f7; } - -h1, h2, h3, h4, h5, h6 { - margin-top: 0; - font-weight: 300; } - -h1 { - font-size: 4.0rem; - line-height: 1.2; - letter-spacing: -.1rem; } - -h2 { - font-size: 3.6rem; - line-height: 1.25; - letter-spacing: -.1rem; } - -h3 { - font-size: 3.0rem; - line-height: 1.3; - letter-spacing: -.1rem; } - -h4 { - font-size: 2.4rem; - line-height: 1.35; - letter-spacing: -.08rem; - margin: 0 0 5px 0; } - -h5 { - font-size: 1.8rem; - line-height: 1.5; - letter-spacing: -.05rem; } - -p { - margin-top: 0; } - -h3 a { - text-decoration: none; - color: #474a54; } - -h3 a:hover { - text-decoration: none; - color: #474a54; } - -a { - color: #1EAEDB; - text-decoration: none; } - -a:hover { - color: #0FA0CE; - text-decoration: underline; } - -pre { - white-space: pre-wrap; - font-size: 1em; - margin: 22px 0; - word-wrap: break-word; - } - -dl.parameters { - border-top: 1px solid #eee; - border-bottom: 1px solid #eee; - padding: 0 0 20px 0; - margin: 0 0 20px 0; - display: grid; - grid-gap: 1rem; - grid-template-columns: 25% 1fr; } - -dl.options { - display: grid; - grid-gap: 1rem; - grid-template-columns: 25% 1fr; - border-color: #eee; - border-top-width: 1px; - border-top-style: solid; - padding: 10px; - /* margin-left: -39%; */ - font-size: 0.85em; - } - -dl dt { - grid-column-start: 1; - grid-column-end: 2; - font-weight: bold; } - -dd { - margin-left: 0; } - -dl dd { - grid-column-start: 2; - grid-column-end: 3; } - -.types-zone { - font-size: 0.9em; } - -dl.options .types-zone { - font-size: 1em; } - -.default, -dt code { - font-family: monospace; } - -.types-zone code { - font-family: monospace; - font-weight: bold; - background: none; - color: #aa5500; } - -.default { - color: #888; } - -dt code, -dt sup { - color: #aa5500; } - -p > code, -dt > code.name, -dd > code, -li > code { - font-size: 1.2em; - font-family: monospace; - font-weight: bold; - background: none; - color: #aa5500; } - -em { - text-decoration: underline; } - -.sidebar h6 { - line-height: 1em; - font-size: 1.5rem; - letter-spacing: 1px; - color: #888; - font-weight: bold; } - -.sidebar { - padding: 20px 20px 0 20px; - white-space: nowrap; - overflow-y: auto; } - .sidebar section { - padding: 10px 0; } - .sidebar ul { - padding: 0 0 0 10px; - margin: 0; - list-style: none; } - .sidebar h6 { - padding: 0; - margin: 0 0 5px 0; } - .sidebar a { - color: #777; - text-decoration: none; - font-size: .90em; - display: block; - width: 100%; - text-overflow: ellipsis; - overflow: hidden; - padding: 2px 0; } - .sidebar a.active { - color: #2196F3; - text-decoration: none; } - .sidebar .parameter { - padding-left: 20px; - font-size: 0.9em; } - -.endpoint { - font-size: 10px; - padding: 0 2px; - position: relative; } - -h3 .endpoint { - padding: 4px 6px; - font-size: 19px; } - -.endpoint a { - color: #42A5F5; } - -.main { - margin: 0 0 0 300px; - border-left: 1px solid #eee; } - .main h6 { - font-size: 1.01em; - padding: 0 0 6px 0; - margin: 0; } - .main .description { - color: #666; - margin-top: -11px; } - @media (max-width: 700px) { - .main { - margin: 0; } } - -hr { - border: 0; - border-top: 1px solid #ddd; - margin: 20px 0; } - -.error, .warning, .info, .success { - border-left: 5px solid #FD0; - padding: 10px 15px; - margin-left: -20px; - margin-right: -15px; - background-color: #FAFAFA; - border-radius: 2px; } - -.warning { - border-color: #ffc107; } - -.info { - border-color: #56ADEC; } - -.error { - border-color: #F20; } - -.success { - border-color: #6c0; } - -.doc-content { - border: 0; - border-bottom: 1px solid #eee; - padding: 30px 0; } - -.doc-content:after { - visibility: hidden; - display: block; - content: ""; - clear: both; - height: 0; } - -.doc-content:last-child { - border: 0; } - -.left-docs { - width: 100%; - float: left; - padding: 0 50px; - box-sizing: border-box; } - .left-docs pre { - border: 0px; - box-shadow: 0 0 0 1px #eee; - border-radius: 3px; - padding: 10px; } - .left-docs p, .left-docs pre, .left-docs ul, .left-docs dd { - /* max-width: 560px; */ - } - .left-docs dd { - /* max-width: 400px; */ - } - -.code-viewer .languages { - padding: 0; - margin: 0 0 5px 0; - list-style: none; - font-size: .9em; } - .code-viewer .languages li { - display: inline-block; } - .code-viewer .languages li a { - display: block; - padding: 5px 10px; - z-index: 100; - border: 1px solid transparent; } - .code-viewer .languages li a:hover { - border-color: #eee; - border-radius: 5px; } - .code-viewer .languages li a.active:hover { - border-color: transparent; } -.code-viewer a { - text-decoration: none; - color: #aaa; } - .code-viewer a:hover { - color: #222; } -.code-viewer pre { - margin: 0 0 20px 0; } - -.code-viewer a.active, .code-viewer a.active:hover, .right-code .code-viewer a.active:hover { - color: #1EAEDB; } - -.right-code .code-viewer a:hover { - color: #fff; } - -@media (max-width: 1000px) { - .left-docs { - float: none; - width: 100%; } - - .doc-content { - background: #fff; - padding-bottom: 0; - border-image: none; - -moz-border-image: none; - -webkit-border-image: none; - border-color: #eee; } } -header { - max-height: 100vh; - position: fixed; - top: 0; - left: 0; - right: 0; - overflow-x: hidden; - z-index: 1; - background-color: #f5f5f5; } - header h1 { - height: 60px; - box-sizing: border-box; - background-color: #35d69b; - color: #fff; - margin: 0; - font-size: 1.7rem; - line-height: 0.8; - letter-spacing: 0; - font-weight: 600; - text-indent: 0; - display: -webkit-flex; - display: flex; - -webkit-flex-direction: row; - flex-direction: row; - -webkit-align-items: center; - align-items: center; - border-bottom: 1px solid rgba(0, 0, 0, 0.075); } - header h1 img { - height: 26px; - margin: 0 18px; } - header .open-nav { - width: 25px; - height: 25px; - margin: 0 0 0 18px; - background-image: url("/images/menu.svg"); - background-color: transparent; - background-repeat: no-repeat; - background-size: 100%; - border: 0; - position: relative; - border-radius: 2px; - cursor: pointer; } - header .open-nav:focus { - outline: none; - background-color: rgba(0, 0, 0, 0.05); } - header .open-nav:hover { - background-color: rgba(0, 0, 0, 0.1); } - @media (min-width: 700px) { - header { - background-color: transparent; - width: 300px; - right: auto; - bottom: auto; } - header .copyright { - display: block; } - header .open-nav { - display: none; } - header h1 { - box-shadow: inset -10px 0 10px -10px rgba(0, 0, 0, 0.1); } } - -.copyright { - text-align: center; - font-size: .6em; - margin: 30px 0 0 0; - display: none; } - -code .hll { - background-color: #ffffcc; } - -code .c { - color: #aaaaaa; - font-style: italic; } - -/* Comment */ -code .err { - color: #F00000; - background-color: #F0A0A0; } - -/* Error */ -code .k { - color: #0000aa; } - -/* Keyword */ -code .cm { - color: #aaaaaa; - font-style: italic; } - -/* Comment.Multiline */ -code .cp { - color: #4c8317; } - -/* Comment.Preproc */ -code .c1 { - color: #aaaaaa; - font-style: italic; } - -/* Comment.Single */ -code .cs { - color: #0000aa; - font-style: italic; } - -/* Comment.Special */ -code .gd { - color: #aa0000; } - -/* Generic.Deleted */ -code .ge { - font-style: italic; } - -/* Generic.Emph */ -code .gr { - color: #aa0000; } - -/* Generic.Error */ -code .gh { - color: #000080; - font-weight: bold; } - -/* Generic.Heading */ -code .gi { - color: #00aa00; } - -/* Generic.Inserted */ -code .go { - color: #888888; } - -/* Generic.Output */ -code .gp { - color: #555555; } - -/* Generic.Prompt */ -code .gs { - font-weight: bold; } - -/* Generic.Strong */ -code .gu { - color: #800080; - font-weight: bold; } - -/* Generic.Subheading */ -code .gt { - color: #aa0000; } - -/* Generic.Traceback */ -code .kc { - color: #0000aa; } - -/* Keyword.Constant */ -code .kd { - color: #0000aa; } - -/* Keyword.Declaration */ -code .kn { - color: #0000aa; } - -/* Keyword.Namespace */ -code .kp { - color: #0000aa; } - -/* Keyword.Pseudo */ -code .kr { - color: #0000aa; } - -/* Keyword.Reserved */ -code .kt { - color: #00aaaa; } - -/* Keyword.Type */ -code .m { - color: #009999; } - -/* Literal.Number */ -code .s { - color: #aa5500; } - -/* Literal.String */ -code .na { - color: #1e90ff; } - -/* Name.Attribute */ -code .nb { - color: #00aaaa; } - -/* Name.Builtin */ -code .nc { - color: #00aa00; - text-decoration: underline; } - -/* Name.Class */ -code .no { - color: #aa0000; } - -/* Name.Constant */ -code .nd { - color: #888888; } - -/* Name.Decorator */ -code .ni { - color: #800000; - font-weight: bold; } - -/* Name.Entity */ -code .nf { - color: #00aa00; } - -/* Name.Function */ -code .nn { - color: #00aaaa; - text-decoration: underline; } - -/* Name.Namespace */ -code .nt { - color: #1e90ff; - font-weight: bold; } - -/* Name.Tag */ -code .nv { - color: #aa0000; } - -/* Name.Variable */ -code .ow { - color: #0000aa; } - -/* Operator.Word */ -code .w { - color: #bbbbbb; } - -/* Text.Whitespace */ -code .mf { - color: #009999; } - -/* Literal.Number.Float */ -code .mh { - color: #009999; } - -/* Literal.Number.Hex */ -code .mi { - color: #009999; } - -/* Literal.Number.Integer */ -code .mo { - color: #009999; } - -/* Literal.Number.Oct */ -code .sb { - color: #aa5500; } - -/* Literal.String.Backtick */ -code .sc { - color: #aa5500; } - -/* Literal.String.Char */ -code .sd { - color: #aa5500; } - -/* Literal.String.Doc */ -code .s2 { - color: #aa5500; } - -/* Literal.String.Double */ -code .se { - color: #aa5500; } - -/* Literal.String.Escape */ -code .sh { - color: #aa5500; } - -/* Literal.String.Heredoc */ -code .si { - color: #aa5500; } - -/* Literal.String.Interpol */ -code .sx { - color: #aa5500; } - -/* Literal.String.Other */ -code .sr { - color: #009999; } - -/* Literal.String.Regex */ -code .s1 { - color: #aa5500; } - -/* Literal.String.Single */ -code .ss { - color: #0000aa; } - -/* Literal.String.Symbol */ -code .bp { - color: #00aaaa; } - -/* Name.Builtin.Pseudo */ -code .vc { - color: #aa0000; } - -/* Name.Variable.Class */ -code .vg { - color: #aa0000; } - -/* Name.Variable.Global */ -code .vi { - color: #aa0000; } - -/* Name.Variable.Instance */ -code .il { - color: #009999; } - -/* Literal.Number.Integer.Long */ -.editor-link { - display: none; - float: right; - margin-top: 0; - border: 0; - border-radius: 2px; - box-sizing: border-box; - font-size: 2rem; - text-decoration: none; - padding: 10px 15px; - margin: 0; - font-size: 18px; - cursor: pointer; - background-color: #f7e064; - color: #333; - box-shadow: 1px 1px 5px 0 rgba(0, 0, 0, 0.2); } - .editor-link:hover { - background-color: #f4d525; - color: #333; } - -.cms-editor-active .editor-link { - display: inline-block; } diff --git a/docs/_site/favicon.png b/docs/_site/favicon.png deleted file mode 100644 index 9479bd34..00000000 Binary files a/docs/_site/favicon.png and /dev/null differ diff --git a/docs/_site/index.html b/docs/_site/index.html deleted file mode 100644 index f87223c2..00000000 --- a/docs/_site/index.html +++ /dev/null @@ -1,2628 +0,0 @@ - - - - - - - -API Docs | fetch-mock - - - - - - - - - - - - - - - - - - - - - -
-

- - fetch-mock -

- - - - - -
-
- - - - - - - - - - - -
-
-

- - Introduction - - - -

- -
- - -
- - - - - -

fetch-mock allows mocking http requests made using fetch, or one of the many libraries imitating its api, such as node-fetch or fetch-ponyfill.

- -

It supports most JavaScript environments, including nodejs, web workers and service workers, and any browser that either supports fetch natively or that can have a fetch polyfill installed.

- -

As well as shorthand methods for the simplest use cases, it offers a flexible API for customising all aspects of mocking behaviour.

- - - - - - - -
fetchMock.mock('http://example.com', 200);
-const res = await fetch('http://example.com');
-assert(res.ok);
-fetchMock.restore();
-
- - - -
-
- -
-
-

- - Quickstart - - - -

- -
- - -
- - - - - - -

Setting up your mock

- -
    -
  • The commonest use case is fetchMock.mock(matcher, response), where matcher is an exact url or regex to match, and response is a status code, string or object literal.
  • -
  • You can also use fetchMock.once() to limit to a single call or fetchMock.get(), fetchMock.post() etc. to limit to a method.
  • -
  • All these methods are chainable so you can easily define several mocks in a single test.
  • -
- -
fetchMock
-  .get('http://good.com/', 200)
-  .post('http://good.com/', 400)
-  .get(/bad\.com/, 500)
-
-

Analysing calls to your mock

- -
    -
  • fetchMock.called(matcher) reports if any calls matched your mock (or leave matcher out if you just want to check fetch was called at all).
  • -
  • fetchMock.lastCall(), fetchMock.lastUrl() or fetchMock.lastOptions() give you access to the parameters last passed in to fetch.
  • -
  • fetchMock.done() will tell you if fetch was called the expected number of times.
  • -
- -

Tearing down your mock

- -
    -
  • fetchMock.resetHistory() resets the call history.
  • -
  • fetchMock.reset() or fetchMock.restore() will also restore fetch() to its native implementation
  • -
- -

Example

- -

Example with node: suppose we have a file make-request.js with a function that calls fetch:

- -
module.exports = function makeRequest() {
-  return fetch('http://httpbin.org/get').then(function(response) {
-    return response.json();
-  });
-};
-
- -

We can use fetch-mock to mock fetch. In mocked.js:

- -
var fetchMock = require('fetch-mock');
-var makeRequest = require('./make-request');
-
-// Mock the fetch() global to always return the same value for GET
-// requests to all URLs.
-fetchMock.get('*', { hello: 'world' });
-
-makeRequest().then(function(data) {
-  console.log('got data', data);
-});
-
-// Unmock.
-fetchMock.reset();
-
- -

Result:

- -
$ node mocked.js
-'got data' { hello: 'world' }
-
- - - -
-
- - - - -

Usage

- - - - -
-
-

- - Requirements - - - -

- -
- - -
- - - - - -

fetch-mock requires the following to run:

- - - -

Note that node-fetch is not included as a dependency of this package. This is to allow users a choice over which version to use; fetch-mock will use whichever version you have installed

- - - -
-
- -
-
-

- - Installation - - - -

- -
- - -
- - - - - - -

Install fetch-mock using

- -
npm install --save-dev fetch-mock
-
- -

In most environments use one of the following in your test files

- -
const fetchMock = require('fetch-mock');
-
-// Exposes constants that will make tests more readable
-const { fetchMock, MATCHED, UNMATCHED } = require('fetch-mock');
-
- -

Some exceptions include:

- -

If your client-side code or tests do not use a loader that respects the browser field of package.json use require('fetch-mock/es5/client').

-

If you need to use fetch-mock without commonjs, you can include the precompiled node_modules/fetch-mock/es5/client-bundle.js in a script tag. This loads fetch-mock into the fetchMock global variable.

-

For server side tests running in nodejs 6 or lower use
-require('fetch-mock/es5/server')

- - - -
-
- -
-
-

- - Global or non-global - - - -

- -
- - -
- - - - - -

fetch can be used by your code globally or locally. It’s important to determine which one applies to your codebase as it will impact how you use fetch-mock

- -

Global fetch

-

In the following scenarios fetch will be a global

-
    -
  • When using native fetch (or a polyfill) in the browser
  • -
  • When node-fetch has been assigned to global in your nodejs process (a pattern sometiems used in isomorphic codebases)
  • -
- -

By default fetch-mock assumes fetch is a global so once you’ve required fetch-mock, refer to the quickstart and api docs.

- -

Non-global fetch library

-

In the following scenarios fetch will not be a global

- -
    -
  • Using node-fetch in nodejs without assigning to global
  • -
  • Using fetch-ponyfill in the browser
  • -
  • Using libraries which use fetch-ponyfill internally
  • -
  • Some build setups result in a non-global fetch, though it may not always be obvious that this is the case
  • -
- -

The sandbox() method returns a function that can be used as a drop-in replacement for fetch, and can be passed into your choice of mocking library. The function returned by sandbox() supports the full fetch-mock api so once generated it can be worked with as if it were the original fetch-mock object, e.g.

- -
const fetchMock = require('fetch-mock');
-const myMock = fetchMock.sandbox().mock('/home', 200);
-// pass myMock in to your application code, instead of fetch, run it, then...
-expect(myMock.called('/home')).to.be.true;
-
- - - -
-
- -
-
-

- - Polyfilling fetch - - - -

- -
- - -
- - - - - -

Many older browsers require polyfilling the fetch global. The following approaches can be used

- -

Add the following polyfill.io script to your test page
<script src="https://polyfill.io/v2/polyfill?features=fetch"></script>

-

npm install whatwg-fetch and load ./node_modules/whatwg-fetch/fetch.js into the page, either in a script tag or by referencing in your test runner config.

- - - -
-
- -
-
-

- - Custom subclasses - - - -

- -
- - -
- - - - - -

Some fetch-mock internals require access to the Request, Response and Headers constructors provided by your chosen fetch implementation. These should be set on the fetchMock.config object

- -
const ponyfill = require('fetch-ponyfill')();
-fetchMock.config = Object.assign(fetchMock.config, {
-    Headers: ponyfill.Headers,
-    Request: ponyfill.Request,
-    Response: ponyfill.Response,
-    fetch: ponyfill
-})
-
- - - -
-
- -
-
-

- - Configuration - - - -

- -
- - -
- - -

- -

On any fetchMock instance, config can be set by setting properties on fetchMock.config.

- -

- - - - -
Options
- - -
- -
- sendAsJson -
- - - Boolean - - - - - [default true] - -
- -
-
-

Convert objects into JSON before delivering as stub reponses. Can be useful to set to false globally if e.g. dealing with a lot of array buffers. If true, will also add content-type: application/json header.

- - - -
- -
- includeContentLength -
- - - Boolean - - - - - [default true] - -
- -
-
-

Automatically sets a content-length header on each response.

- - - -
- -
- fallbackToNetwork -
- - - Boolean - | - - String - - - - - [default false] - -
- -
-
-
    -
  • true: Unhandled calls fall through to the network
  • -
  • false: Unhandled calls throw an error
  • -
  • 'always': All calls fall through to the network, effectively disabling fetch-mock.
  • -
- - - -
- -
- overwriteRoutes -
- - - Boolean - - - - - [default undefined] - -
- -
-
-

Determines behaviour if a new route has the same name (or inferred name) as an existing one

-
    -
  • undefined: An error will be throw when routes clash
  • -
  • true: Overwrites the existing route
  • -
  • false: Appends the new route to the list of routes
  • -
- - - -
- -
- warnOnFallback -
- - - Boolean - - - - - [default true] - -
- -
-
-

Print a warning if any call is caught by a fallback handler (set using the fallbackToNetwork option or catch())

- - - -
- -
- Promise -
- - - Constructor - - - - -
- -
-
-

Reference to the Promise constructor of a custom Promise implementation

- - - -
- -
- fetch -
- - - Function - - - - -
- -
-
-

Reference to a custom fetch implementation

- - - -
- -
- Headers -
- - - Constructor - - - - -
- -
-
-

Reference to the Headers constructor of a custom fetch implementation

- - - -
- -
- Request -
- - - Constructor - - - - -
- -
-
-

Reference to the Request constructor of a custom fetch implementation

- - - -
- -
- Response -
- - - Constructor - - - - -
- -
-
-

Reference to the Response constructor of a custom fetch implementation

- - - -
- -
- - -

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

- - - -
-
- - - - -

Mocking API

- - - - -
-
-

- - .mock(matcher, response, options) - - - -

- -
- - -
- - -

- -

Replaces fetch with a stub which records its calls and returns a Response instance.

- -

- - - - -
Parameters
- - -
- -
- matcher -
- - - String - | - - Regex - | - - Function - - - - -
- -
-
-

Rule for matching calls to fetch

- - - -
- -
- response -
- - - String - | - - Object - | - - Function - | - - Promise - | - - Response - - - - -
- -
-
-

Response to send matched calls

- - - -
- -
- options -
- - - Object - - - - -
- -
-
-

More options configuring [mainly] matching behaviour

- - - -
- -
- - - -

Alternatively a single parameter, options, an Object with matcher, response and other options defined, can be passed

- - - - - - - -
fetchMock
-  .mock('http://it.at.here/route', 200)
-  .mock('begin:http://it', 200)
-  .mock('end:here/route', 200)
-  .mock('path:/route', 200)
-  .mock('*', 200)
-
- - - - - -
fetchMock
-  .mock(/.*\.here.*/, 200)
-  .mock((url, opts) => opts.method === 'patch', 200)
-  .mock('express:/:type/:id', 200, {
-    params: {
-      type: 'shoe'
-    }
-  })
-
- - - - - -
fetchMock
-  .mock('*', 'ok')
-  .mock('*', 404)
-  .mock('*', {results: []})
-  .mock('*', {throw: new Error('Bad kitty')))
-  .mock('*', new Promise(res => setTimeout(res, 1000, 404)))
-
- - - - - -
fetchMock
-  .mock('begin:http://it.at.here/api', 200, {
-    headers: {
-      authorization: 'Basic dummy-token'
-    }
-  })
-  .mock('begin:http://it.at.here/api', 403)
-
-callApi('/endpoint', 'dummy-token')
-  .then(res => {
-    expect(res.status).to.equal(200)
-  })
-
- - - -
-
- -
-
-

- - matcher - - - Parameter for mock() - - -

- -
- - - String - | - - RegExp - | - - Function - - - - -
- - -

- -

Condition for selecting which requests to mock. For matching based on headers, query strings or other fetch options see the options parameter documented below

- -

- - - - -
Argument values
- - -
- -
- * -
- - - String - - - - -
- -
-
-

Matches any url

- - - - - - -
"*"
-
- - - - - -
- -
- url -
- - - String - - - - -
- -
-
-

Matches an exact url

- - - - - - -
"http://www.site.com/page.html"
-
- - - - - -
- -
- begin:... -
- - - String - - - - -
- -
-
-

Matches a url beginning with a string

- - - - - - -
"begin:http://www.site.com"
-
- - - - - -
- -
- end:... -
- - - String - - - - -
- -
-
-

Matches a url ending with a string

- - - - - - -
"end:.jpg"
-
- - - - - -
- -
- path:... -
- - - String - - - - -
- -
-
-

Matches a url which has a given path

- - - - - - -
"path:/posts/2018/7/3"
-
- - - - - -
- -
- glob:... -
- - - String - - - - -
- -
-
-

Matches a url using a glob pattern

- - - - - - -
"glob:http://*.*"
-
- - - - - -
- -
- express:... -
- - - String - - - - -
- -
-
-

Matches a [relative] url that matches an express style path

- - - - - - -
"express:/user/:user"
-
- - - - - -
- -
- -
- - - RegExp - - - - -
- -
-
-

Matches a url that matches a regular expression

- - - - - - -
/(article|post)/\d+/
-
- - - - - -
- -
- -
- - - Function - - - - -
- -
-
-

Matches if a function returns something truthy. The function will be passed the arguments fetch was called with. If fetch was called with a Request instance, it will be passed url and options inferred from the Request instance. The original Request will be passed as a third argument.

- - - - - - -
(url, {headers}) => !!headers.Authorization
-
- - - - - - -
(_, _, request) => !!request.headers.get('Authorization')
-
- - - - - -
- -
- - -

Note that if using end: or an exact url matcher, fetch-mock (for good reason) is unable to distinguish whether URLs without a path end in a trailing slash or not i.e. http://thing is treated the same as http://thing/

- - - -
-
- -
-
-

- - response - - - Parameter for mock() - - -

- -
- - - String - | - - Object - | - - Function - | - - Promise - | - - Response - - - - -
- - -

- -

Response to send matched calls. -Configures the http response returned by the mock. Can take any of the following values (or be a Promise for any of them, enabling full control when testing race conditions etc.). Unless otherwise stated, all responses have a 200 status

- -

- - - - -
Argument values
- - -
- -
- -
- - - Response - - - - -
- -
-
-

A Response instance - will be used unaltered

- - - - - - -
new Response('ok', {status: 200})
-
- - - - - -
- -
- status code -
- - - Integer - - - - -
- -
-
-

Creates a response with the given status code. The response’s statusText will also be set to the default value corresponding to the status

- - - - - - -
200, 404, 503
-
- - - - - -
- -
- -
- - - String - - - - -
- -
-
-

Creates a 200 response with the string as the response body

- - - - - - -
Server responded ok
-
- - - - - - -
Bad Response
-
- - - - - -
- -
- config -
- - - Object - - - - -
- -
-
-

If an object only contains properties listed below it is used to configure a Response

- - - -
- -
- body -
- - - String - | - - Object - - - - -
- -
-
-

Set the response body. For behaviour for Objects, see the non-config Object section of the docs below

- - - - - - -
Server responded ok
-
- - - - - - -
{"token"=>"abcdef"}
-
- - - - -
- -
- status -
- - - Integer - - - - -
- -
-
-

Set the response status

- - - - - - -
200, 404, 503
-
- - - - -
- -
- headers -
- - - Object - - - - -
- -
-
-

Set the response headers

- - - - - - -
{"Content-Type"=>"text/html"}
-
- - - - -
- -
- redirectUrl -
- - - String - - - - -
- -
-
-

The url the response should claim to originate from (to imitate followed directs). Will also set redirected: true on the response

- - -
- -
- throws -
- - - Error - - - - -
- -
-
-

fetch will return a Promise rejected with the value of throws

- - - - - - -
new TypeError('Failed to fetch')
-
- - - - -
- -
- -
- -
- -
- - - Object - | - - ArrayBuffer - - - - -
- -
-
-

All objects that do not meet the criteria above will be converted to JSON and set as the response body if the sendAsJson option is on. Otherwise, they will be set as the response body (useful for array buffers etc.)

- - - -
- -
- -
- - - Promise - - - - -
- -
-
-

A Promise that resolves to any of the options documented above

- - - - - - -
new Promise(res => setTimeout(() => res(200), 50))
-
- - - - - -
- -
- -
- - - Function - - - - -
- -
-
-

A function that is passed the arguments fetch is called with and that returns any of the responses listed above

- - - - - - -
(url, opts) => opts.headers.Authorization ? 200 : 403
-
- - - - - - -
(_, _, request) => request.headers.get('Authorization') ?  200 : 403
-
- - - - - -
- -
- - - - - - -
-
- -
-
-

- - options - - - Parameter for mock() - - -

- -
- - - Object - - - - -
- - -

- -

A configuration object with properties to define a route to mock

- -

- - - - -
Options
- - -
- -
- name -
- - - String - - - - -
- -
-
-

A unique string naming the route. Used to subsequently retrieve references to the calls, grouped by name. Defaults to matcher.toString()

- - - -
- -
- method -
- - - String - - - - -
- -
-
-

Http method to match

- - - -
- -
- headers -
- - - Object - | - - Headers - - - - -
- -
-
-

Key/value map of headers to match

- - - -
- -
- query -
- - - Object - - - - -
- -
-
-

Key/value map of query strings to match, in any order

- - - -
- -
- params -
- - - Object - - - - -
- -
-
-

When the express: keyword is used in a string matcher, a key/value map params can be passed here, to match the parameters extracted by express path matching

- - - -
- -
- repeat -
- - - Integer - - - - -
- -
-
-

An integer, n, limiting the number of times the matcher can be used. If the route has already been called n times the route will be ignored and the call to fetch() will fall through to be handled by any other routes defined (which may eventually result in an error if nothing matches it)

- - - -
- -
- overwriteRoutes -
- - - Boolean - - - - -
- -
-
-

See global configuration

- - - -
- -
- sendAsJson -
- - - Boolean - - - - - [default true] - -
- -
-
-

See global configuration

- - - -
- -
- includeContentLength -
- - - Boolean - - - - - [default true] - -
- -
-
-

See global configuration

- - - -
- -
- matcher -
- - -
- -
-
-

When using the single argument variant of .mock(), any valid matcher as defined above can be assigned to the options object

- - - -
- -
- response -
- - -
- -
-
-

When using the single argument variant of .mock(), any valid response as defined above can be assigned to the options object

- - - -
- -
- - - - - - -
-
- -
-
-

- - .once() - - - -

- -
- - -
- - -

- -

Shorthand for mock() which limits to being called one time only. (see repeat option above)

- -

- - - - - - - - -
-
- -
-
-

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

- -
- - -
- - -

- -

Shorthands for mock() restricted to a particular method.

- -

- - - - -

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

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

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

- -
- - -
- - -

- -

Shorthands for mock() restricted to a particular method and that will only respond once

- -

- - - - - - - - -
-
- -
-
-

- - .catch(response) - - - -

- -
- - -
- - -

- -

Specifies how to respond to calls to fetch that don’t match any mocks.

- -

- - - - -

It accepts any valid fetch-mock response, and can also take an arbitrary function to completely customise behaviour. If no argument is passed, then every unmatched call will receive a 200 response

- - - -
-
- -
-
-

- - .spy() - - - -

- -
- - -
- - -

- -

Records call history while passing each call on to fetch to be handled by the network

- -

- - - - -

To use .spy() on a sandboxed fetchMock, fetchMock.config.fetch must be set to a reference to the fetch implementation you use in your code.

- - - -
-
- - - - -

Lifecycle methods

- - - - -
-
-

- - .sandbox() - - - -

- -
- - -
- - -

- -

Returns a drop-in mock for fetch which can be passed to other mocking libraries. It implements the full fetch-mock api and maintains its own state independent of other instances, so tests can be run in parallel.

- -

- - - - - - - - - - - - -
fetchMock
-  .sandbox()
-  .mock('http://domain.com', 200)
-
- - - -
-
- -
-
-

- - .flush(waitForBody) - - - -

- -
- - -
- - -

- -

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

- -

- - - - -

Useful for testing code that uses fetch but doesn’t return a promise.

- -

Pass in true to wait for all body parsing methods (res.json(), res.text(), etc.) to resolve too.

- - - -
-
- -
-
-

- - .restore(), .reset() - - - -

- -
- - -
- - -

- -

Restores fetch() to its unstubbed state and clears all data recorded for its calls. reset() is an alias for restore()

- -

- - - - - - - - -
-
- -
-
-

- - .resetHistory() - - - -

- -
- - -
- - -

- -

Clears all data recorded for fetch()’s calls. It will not restore fetch to its default implementation

- -

- - - - - - - - -
-
- - - - -

Inspection methods

- - - - -
-
-

- - Filtering basics - - - -

- -
- - -
- - -

- -

Most inspection methods take two arguments — filter and options — which allow groups of fetch calls to be extracted and inspected.

- -

- - - - -
Parameters
- - -
- -
- filter -
- - - String - | - - RegExp - | - - Function - - - - -
- -
-
-

Enables filtering fetch calls for the most commonly use cases. The behaviour can be counterintuitive. The following rules, applied in the order they are described, are used to try to retrieve calls. If any rule retrieves no calls the next rule will be tried.

- - - -
- -
- matcher -
- - - String - | - - RegExp - | - - Function - - - - -
- -
-
-

If options is defined (it can even be an empty object), filter will be executed using the same execution plan as matchers. Any calls matched by it will be returned.

- - -
- -
- -
- - - undefined - - - - -
- -
-
-

Retrieves all calls made to fetch, whether fetch-mock matched them or not

- - -
- -
- -
- - - true - - - - -
- -
-
-

Retrieves all calls matched by fetch. fetchMock.MATCHED is an alias for true and may be used to make tests more readable

- - -
- -
- -
- - - false - - - - -
- -
-
-

Retrieves all calls not matched by fetch (i.e. those handled by catch() or spy(). fetchMock.UNMATCHED is an alias for false and may be used to make tests more readable

- - -
- -
- route -
- - - String - - - - -
- -
-
-

Retrieves calls handled by a named route (see mocking options. Failing that, a route whose matcher, when coerced to a string, is equal to the string provided

- - -
- -
- asdkash d -
- - -
- -
-
-

Do I want to fallback to a matcher again?? Seems confusing as hell

- - -
- -
- -
- -
- options -
- - - Object - | - - String - - - - -
- -
-
-

Either an object compatible with the mocking api or a string specifying a http method to filter by

- - - -
- -
- - - - - - -
-
- - - - -

Troubleshooting

- - - - - - -
- - - diff --git a/docs/_site/js/lunr.min.js b/docs/_site/js/lunr.min.js deleted file mode 100644 index 4fd086e7..00000000 --- a/docs/_site/js/lunr.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.7.1 - * Copyright (C) 2016 Oliver Nightingale - * @license MIT - */ -!function(){var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.7.1",t.utils={},t.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),t.utils.asString=function(t){return void 0===t||null===t?"":t.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},t.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},t.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},t.EventEmitter.prototype.hasHandler=function(t){return t in this.events},t.tokenizer=function(e){return arguments.length&&null!=e&&void 0!=e?Array.isArray(e)?e.map(function(e){return t.utils.asString(e).toLowerCase()}):e.toString().trim().toLowerCase().split(t.tokenizer.seperator):[]},t.tokenizer.seperator=/[\s\-]+/,t.tokenizer.load=function(t){var e=this.registeredFunctions[t];if(!e)throw new Error("Cannot load un-registered function: "+t);return e},t.tokenizer.label="default",t.tokenizer.registeredFunctions={"default":t.tokenizer},t.tokenizer.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing tokenizer: "+n),e.label=n,this.registeredFunctions[n]=e},t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.registeredFunctions[e];if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");this._stack.splice(i,0,n)},t.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);-1!=e&&this._stack.splice(e,1)},t.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,i=this._stack.length,r=0;n>r;r++){for(var o=t[r],s=0;i>s&&(o=this._stack[s](o,r,t),void 0!==o&&""!==o);s++);void 0!==o&&""!==o&&e.push(o)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(en.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t1;){if(o===t)return r;t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r]}return o===t?r:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,r=e+Math.floor(i/2),o=this.elements[r];i>1;)t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r];return o>t?r:t>o?r+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,r=0,o=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>o-1||r>s-1)break;a[i]!==h[r]?a[i]h[r]&&r++:(n.add(a[i]),i++,r++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone();for(var r=0,o=n.toArray();rp;p++)c[p]===a&&d++;h+=d/f*l.boost}}this.tokenStore.add(a,{ref:o,tf:h})}n&&this.eventEmitter.emit("add",e,this)},t.Index.prototype.remove=function(t,e){var n=t[this._ref],e=void 0===e?!0:e;if(this.documentStore.has(n)){var i=this.documentStore.get(n);this.documentStore.remove(n),i.forEach(function(t){this.tokenStore.remove(t,n)},this),e&&this.eventEmitter.emit("remove",t,this)}},t.Index.prototype.update=function(t,e){var e=void 0===e?!0:e;this.remove(t,!1),this.add(t,!1),e&&this.eventEmitter.emit("update",t,this)},t.Index.prototype.idf=function(t){var e="@"+t;if(Object.prototype.hasOwnProperty.call(this._idfCache,e))return this._idfCache[e];var n=this.tokenStore.count(t),i=1;return n>0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(this.tokenizerFn(e)),i=new t.Vector,r=[],o=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*o,h=this,u=this.tokenStore.expand(e).reduce(function(n,r){var o=h.corpusTokens.indexOf(r),s=h.idf(r),u=1,l=new t.SortedSet;if(r!==e){var c=Math.max(3,r.length-e.length);u=1/Math.log(c)}o>-1&&i.insert(o,a*s*u);for(var f=h.tokenStore.get(r),d=Object.keys(f),p=d.length,v=0;p>v;v++)l.add(f[d[v]].ref);return n.union(l)},new t.SortedSet);r.push(u)},this);var a=r.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,r=new t.Vector,o=0;i>o;o++){var s=n.elements[o],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);r.insert(this.corpusTokens.indexOf(s),a*h)}return r},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,tokenizer:this.tokenizerFn.label,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",r=n+"[^aeiouy]*",o=i+"[aeiou]*",s="^("+r+")?"+o+r,a="^("+r+")?"+o+r+"("+o+")?$",h="^("+r+")?"+o+r+o+r,u="^("+r+")?"+i,l=new RegExp(s),c=new RegExp(h),f=new RegExp(a),d=new RegExp(u),p=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,m=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),k=new RegExp("^"+r+i+"[^aeiouwxy]$"),x=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,F=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,_=/^(.+?)(s|t)(ion)$/,z=/^(.+?)e$/,O=/ll$/,P=new RegExp("^"+r+i+"[^aeiouwxy]$"),T=function(n){var i,r,o,s,a,h,u;if(n.length<3)return n;if(o=n.substr(0,1),"y"==o&&(n=o.toUpperCase()+n.substr(1)),s=p,a=v,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=g,a=m,s.test(n)){var T=s.exec(n);s=l,s.test(T[1])&&(s=y,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=d,a.test(i)&&(n=i,a=S,h=w,u=k,a.test(n)?n+="e":h.test(n)?(s=y,n=n.replace(s,"")):u.test(n)&&(n+="e"))}if(s=x,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+t[r])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+e[r])}if(s=F,a=_,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=z,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=P,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=O,a=c,s.test(n)&&a.test(n)&&(s=y,n=n.replace(s,"")),"y"==o&&(n=o.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.generateStopWordFilter=function(t){var e=t.reduce(function(t,e){return t[e]=e,t},{});return function(t){return t&&e[t]!==t?t:void 0}},t.stopWordFilter=t.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){return t.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t.charAt(0),r=t.slice(1);return i in n||(n[i]={docs:{}}),0===r.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(r,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;n div.highlighter-rouge:first-of-type").each(function(i) { - var $this = $(this).before("
    "), - $languages = $this.prev(), - $notFirst = $this.nextUntil(":not(div.highlighter-rouge)"), - $all = $this.add($notFirst); - - $all.add($languages).wrapAll("
    "); - - - listLanguages($all, $languages); - - $this.css('display', 'block'); - $notFirst.css('display', 'none'); - - $languages.find('a').first().addClass('active'); - - $languages.find('a').click(function() { - $all.css('display', 'none'); - $all.eq($(this).parent().index()).css('display', 'block'); - - $languages.find('a').removeClass('active'); - $(this).addClass('active'); - return false; - }); - - if ($languages.children().length === 0) { - $languages.remove(); - } - }); - - function listLanguages($el, $insert) { - $el.each(function(i) { - var title = $(this).attr('title'); - if (title) { - $insert.append("
  • " + title + "
  • "); - } - }); - } - - var href = $('.sidebar a').first().attr("href"); - - if (href !== undefined && href.charAt(0) === "#") { - setActiveSidebarLink(); - - $(window).on("scroll", function(evt) { - setActiveSidebarLink(); - }); - } - - function setActiveSidebarLink() { - $('.sidebar a').removeClass('active'); - var $closest = getClosestHeader(); - $closest.addClass('active'); - document.title = $closest.text(); - - } -}); - -function getClosestHeader() { - var $links = $('.sidebar a'), - top = window.scrollY, - $last = $links.first(); - - if (top < 300) { - return $last; - } - - if (top + window.innerHeight >= $(".main").height()) { - return $links.last(); - } - - for (var i = 0; i < $links.length; i++) { - var $link = $links.eq(i), - href = $link.attr("href"); - - if (href !== undefined && href.charAt(0) === "#" && href.length > 1) { - var $anchor = $(href); - - if ($anchor.length > 0) { - var offset = $anchor.offset(); - - if (top < offset.top - 300) { - return $last; - } - - $last = $link; - } - } - } - return $last; -} diff --git a/docs/_site/robots.txt b/docs/_site/robots.txt deleted file mode 100644 index 90ce1962..00000000 --- a/docs/_site/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Sitemap: http://localhost:4000/sitemap.xml \ No newline at end of file diff --git a/docs/_site/sitemap.xml b/docs/_site/sitemap.xml deleted file mode 100644 index c82405c4..00000000 --- a/docs/_site/sitemap.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - -http://localhost:4000/ - - diff --git a/docs/_site/touch-icon.png b/docs/_site/touch-icon.png deleted file mode 100644 index 624d181c..00000000 Binary files a/docs/_site/touch-icon.png and /dev/null differ diff --git a/docs/_site/troubleshooting/it.md b/docs/_site/troubleshooting/it.md deleted file mode 100644 index c4168646..00000000 --- a/docs/_site/troubleshooting/it.md +++ /dev/null @@ -1,14 +0,0 @@ -it.md -- When using karma-webpack it's best not to use the `webpack.ProvidePlugin` for this. Instead just add `node_modules/whatwg-fetch/fetch.js` to your list of files to include, or require it directly into your tests before requiring fetch-mock. - -- chaining - -- note that end matches qs, path matches only path - - -Put this with the spy() docs -When using `node-fetch`, `fetch-mock` will use the instance you have installed. The one exception is that a reference to `fetchMock.config.fetch = require('node-fetch')` is required if you intend to use the `.spy()` method) -{: .info} - - - to Within individual tests `.catch()` and `spy()` can be used for fine-grained control of this" diff --git a/docs/_troubleshooting/troubleshooting.md b/docs/_troubleshooting/troubleshooting.md new file mode 100644 index 00000000..0cc841d8 --- /dev/null +++ b/docs/_troubleshooting/troubleshooting.md @@ -0,0 +1,54 @@ +--- +title: General +position: 1 +content_markdown: |- + ### `fetch` is assigned to a local variable, not a global + + First of all, consider whether you could just use `fetch` as a global. Here are 3 reasons why this is a good idea: + + - The `fetch` standard defines it as a global (and in some cases it won't work unless bound to `window`), so to write isomorphic code it's probably best to stick to this pattern + - [`isomorphic-fetch`](https://www.npmjs.com/package/isomorphic-fetch) takes care of installing it as a global in nodejs or the browser, so there's no effort on your part to do so. + - `fetch-mock` is primarily designed to work with `fetch` as a global and your experience of using it will be far more straightforward if you follow this pattern + + Still not convinced? + + In that case `fetchMock.sandbox()` can be used to generate a function which you can pass in to a mock loading library such as [`mockery`](https://www.npmjs.com/package/mockery) instead of `fetch` + + ### `fetch` doesn't seem to be getting mocked? + + - If using a mock loading library such as `mockery`, are you requiring the module you're testing after registering `fetch-mock` with the mock loader? You probably should be ([Example incorrect usage](https://github.com/wheresrhys/fetch-mock/issues/70)). If you're using ES6 `import` it may not be possible to do this without reverting to using `require()` sometimes. + - If using `isomorphic-fetch` in your source, are you assigning it to a `fetch` variable? You _shouldn't_ be i.e. + - `import 'isomorphic-fetch'`, not `import fetch from 'isomorphic-fetch'` + - `require('isomorphic-fetch')`, not `const fetch = require('isomorphic-fetch')` + + ### Environment doesn't support requiring fetch-mock? + + - If your client-side code or tests do not use a loader that respects the browser field of package.json use `require('fetch-mock/es5/client')`. + - If you need to use fetch-mock without commonjs, you can include the precompiled `node_modules/fetch-mock/es5/client-browserified.js` in a script tag. This loads fetch-mock into the `fetchMock` global variable. + - For server side tests running in nodejs 0.12 or lower use `require('fetch-mock/es5/server')` + + ### Matching `Request` objects in node fails + + In node, if using npm at a version less than 2 the `Request` constructor used by `fetch-mock` won't necessarily be the same as the one used by `node-fetch`. To fix this either: + + - upgrade to npm@3 + - use `fetchMock.config.Request = myRequest`, where `myRequest` is a reference to the Request constructor used in your application code. + + +--- + + +it.md +- When using karma-webpack it's best not to use the `webpack.ProvidePlugin` for this. Instead just add `node_modules/whatwg-fetch/fetch.js` to your list of files to include, or require it directly into your tests before requiring fetch-mock. + +- chaining + +- note that end matches qs, path matches only path + + +Put this with the spy() docs +When using `node-fetch`, `fetch-mock` will use the instance you have installed. The one exception is that a reference to `fetchMock.config.fetch = require('node-fetch')` is required if you intend to use the `.spy()` method) +{: .info} + + + to Within individual tests `.catch()` and `spy()` can be used for fine-grained control of this" diff --git a/docs/_usage/_defaults.md b/docs/_usage/_defaults.md new file mode 100644 index 00000000..4c3e1fc8 --- /dev/null +++ b/docs/_usage/_defaults.md @@ -0,0 +1,16 @@ +--- +title: +position: +parameters: + - name: + content: +content_markdown: +left_code_blocks: + - code_block: + title: + language: +right_code_blocks: + - code_block: + title: + language: +--- diff --git a/docs/_usage/configuration.md b/docs/_usage/configuration.md new file mode 100644 index 00000000..5c9ac7be --- /dev/null +++ b/docs/_usage/configuration.md @@ -0,0 +1,68 @@ +--- +title: Configuration +position: 7 +description: |- + On any `fetchMock` instance, config can be set by setting properties on `fetchMock.config`. +parametersBlockTitle: Options +parameters: + - name: sendAsJson + default: true + types: + - Boolean + content: |- + Convert objects into JSON before delivering as stub reponses. Can be useful to set to `false` globally if e.g. dealing with a lot of array buffers. If `true`, will also add `content-type: application/json` header. + - name: includeContentLength + default: true + types: + - Boolean + content: Automatically sets a `content-length` header on each response. + - name: fallbackToNetwork + default: "false" + types: + - Boolean + - String + content: |- + - `true`: Unhandled calls fall through to the network + - `false`: Unhandled calls throw an error + - `'always'`: All calls fall through to the network, effectively disabling fetch-mock. + - name: overwriteRoutes + default: "undefined" + types: + - Boolean + content: |- + Determines behaviour if a new route has the same name (or inferred name) as an existing one + - `undefined`: An error will be throw when routes clash + - `true`: Overwrites the existing route + - `false`: Appends the new route to the list of routes + - name: warnOnFallback + default: true + types: + - Boolean + content: |- + Print a warning if any call is caught by a fallback handler (set using the `fallbackToNetwork` option or `catch()`) + - name: Promise + types: + - Constructor + content: Reference to the `Promise` constructor of a custom `Promise` implementation + - name: fetch + types: + - Function + content: Reference to a custom `fetch` implementation + - name: Headers + types: + - Constructor + content: Reference to the `Headers` constructor of a custom `fetch` implementation + - name: Request + types: + - Constructor + content: Reference to the `Request` constructor of a custom `fetch` implementation + - name: Response + types: + - Constructor + content: Reference to the `Response` constructor of a custom `fetch` implementation + +content_markdown: |- + Options marked with a `†` can also be overridden for individual calls to `.mock(matcher, response, options)` by setting as properties on the `options` parameter + {: .info} + +--- diff --git a/docs/_usage/custom-classes.md b/docs/_usage/custom-classes.md new file mode 100644 index 00000000..6c496f88 --- /dev/null +++ b/docs/_usage/custom-classes.md @@ -0,0 +1,17 @@ +--- +title: Custom subclasses +position: 6 +content_markdown: |- + Some fetch-mock internals require access to the `Request`, `Response` and `Headers` constructors provided by your chosen `fetch` implementation. These should be set on the `fetchMock.config` object + {: .warning} + + ```javascript + const ponyfill = require('fetch-ponyfill')(); + fetchMock.config = Object.assign(fetchMock.config, { + Headers: ponyfill.Headers, + Request: ponyfill.Request, + Response: ponyfill.Response, + fetch: ponyfill + }) + ``` +--- diff --git a/docs/_usage/global-non-global.md b/docs/_usage/global-non-global.md new file mode 100644 index 00000000..564f606a --- /dev/null +++ b/docs/_usage/global-non-global.md @@ -0,0 +1,31 @@ +--- +title: Global or non-global +position: 3 +content_markdown: |- + `fetch` can be used by your code globally or locally. It's important to determine which one applies to your codebase as it will impact how you use `fetch-mock` + {: .warning} + + #### Global fetch + In the following scenarios `fetch` will be a global + - When using native `fetch` (or a polyfill) in the browser + - When `node-fetch` has been assigned to `global` in your nodejs process (a pattern sometiems used in isomorphic codebases) + + By default fetch-mock assumes `fetch` is a global so once you've required fetch-mock, refer to the quickstart and api docs. + + #### Non-global fetch library + In the following scenarios `fetch` will not be a global + + - Using [node-fetch](https://www.npmjs.com/package/node-fetch) in nodejs without assigning to `global` + - Using [fetch-ponyfill](https://www.npmjs.com/package/fetch-ponyfill) in the browser + - Using libraries which use fetch-ponyfill internally + - Some build setups result in a non-global `fetch`, though it may not always be obvious that this is the case + + The `sandbox()` method returns a function that can be used as a drop-in replacement for `fetch`, and can be passed into your choice of mocking library. The function returned by `sandbox()` supports the full fetch-mock api so once generated it can be worked with as if it were the original `fetch-mock` object, e.g. + + ```js + const fetchMock = require('fetch-mock'); + const myMock = fetchMock.sandbox().mock('/home', 200); + // pass myMock in to your application code, instead of fetch, run it, then... + expect(myMock.called('/home')).to.be.true; + ``` +--- diff --git a/docs/_usage/installation.md b/docs/_usage/installation.md new file mode 100644 index 00000000..d757c034 --- /dev/null +++ b/docs/_usage/installation.md @@ -0,0 +1,31 @@ +--- +title: Installation +position: 2 +content_markdown: |- + + Install fetch-mock using + + ```bash + npm install --save-dev fetch-mock + ``` + + In most environments use one of the following in your test files + + ```js + const fetchMock = require('fetch-mock'); + + // Exposes constants that will make tests more readable + const { fetchMock, MATCHED, UNMATCHED } = require('fetch-mock'); + ``` + + Some exceptions include: + + If your client-side code or tests do not use a loader that respects the `browser` field of `package.json` use `require('fetch-mock/es5/client')`. + {: .warning} + If you need to use fetch-mock without commonjs, you can include the precompiled `node_modules/fetch-mock/es5/client-bundle.js` in a script tag. This loads fetch-mock into the `fetchMock` global variable. + {: .warning} + For server side tests running in nodejs 6 or lower use
    + `require('fetch-mock/es5/server')` + {: .warning} +--- + diff --git a/docs/_usage/polyfilling.md b/docs/_usage/polyfilling.md new file mode 100644 index 00000000..6209e90a --- /dev/null +++ b/docs/_usage/polyfilling.md @@ -0,0 +1,11 @@ +--- +title: Polyfilling fetch +position: 5 +content_markdown: |- + Many older browsers require polyfilling the `fetch` global. The following approaches can be used + + Add the following [polyfill.io](https://polyfill.io/v2/docs/) script to your test page
    `` + {: .info} + `npm install whatwg-fetch` and load `./node_modules/whatwg-fetch/fetch.js` into the page, either in a script tag or by referencing in your test runner config. + {: .info} +--- diff --git a/docs/_usage/requirements.md b/docs/_usage/requirements.md new file mode 100644 index 00000000..f1c0108f --- /dev/null +++ b/docs/_usage/requirements.md @@ -0,0 +1,24 @@ +--- +title: Requirements +position: 1 +content_markdown: |- + fetch-mock requires the following to run: + + - [Node.js](https://nodejs.org/) 8+ for full feature operation + - [Node.js](https://nodejs.org/) 0.12+ with [limitations](http://www.wheresrhys.co.uk/fetch-mock/installation) + - [npm](https://www.npmjs.com/package/npm) (normally comes with Node.js) + - Either of the following + - [node-fetch](https://www.npmjs.com/package/node-fetch) when testing in a nodejs + - A browser that supports the `fetch` API either natively or via a [polyfill/ponyfill](https://ponyfoo.com/articles/polyfills-or-ponyfills) + + Note that **node-fetch** is not included as a dependency of this package. This is to allow users a choice over which version to use; fetch-mock will use whichever version you have installed + {: .warning} +left_code_blocks: + - code_block: + title: + language: +right_code_blocks: + - code_block: + title: + language: +--- diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index 6f6d7b5c..00000000 --- a/docs/api.md +++ /dev/null @@ -1,158 +0,0 @@ -- [Introduction](/fetch-mock) -- [Quickstart](/fetch-mock/quickstart) -- [Installation and usage](/fetch-mock/installation) -- API documentation -- [Troubleshooting](/fetch-mock/troubleshooting) -- [Examples](/fetch-mock/examples) - -# API Documentation - -## Mocking calls to `fetch` - -#### `mock(matcher, response, options)` or `mock(options)` - -Replaces `fetch` with a stub which records its calls, grouped by route, and optionally returns a mocked `Response` object or passes the call through to `fetch()`. Calls to `.mock()` can be chained. _Note that once mocked, `fetch` will error on any unmatched calls. Use `.spy()` or `.catch()` to handle unmocked calls more gracefully_ - -- `matcher`: Condition for selecting which requests to mock. (For matching based on headers, query strings or other `fetch` options see the `options` parameter documented below). Accepts any of the following: - - `string`: Either - - an exact url to match e.g. 'http://www.site.com/page.html' - - `*` to match any url - - `begin:http://www.site.com/` to match urls beginning with a string - - `end:.jpg` to match urls ending with a string - - `path:/posts/2018/7/3` to match urls with a given path - - `glob:http://*.*` to match glob patterns - - `express:/user/:user` to match [express style paths](https://www.npmjs.com/package/path-to-regexp) - - `RegExp`: A regular expression to test the url against - - `Function(url, options, [request])`: A function (returning a Boolean) that is passed the url and options `fetch()` is called with. If `fetch()` was called with a `Request` instance, `url` and some basic `options` will be extracted from teh `Request`, but if more fine graned examination of it is needed, it is available as the third parameter - -_Note that if using `end:` or an exact url matcher, `fetch-mock` ([for good reason](https://url.spec.whatwg.org/#url-equivalence)) is unable to distinguish whether URLs without a path end in a trailing slash or not i.e. `http://thing` is treated the same as `http://thing/`_ - -- `response`: Configures the http response returned by the mock. Can take any of the following values (or be a `Promise` for any of them, enabling full control when testing race conditions etc.) - - `Response`: A `Response` instance - will be used unaltered - - `number`: Creates a response with this status - - `string`: Creates a 200 response with the string as the response body - - `configObject` If an object _does not contain_ any properties aside from those listed below it is treated as config to build a `Response` - - `body`: Set the response body (`string` or `object`) - - `status`: Set the response status (default `200`) - - `headers`: Set the response headers. (`object`) - - `throws`: If this property is present then fetch returns a `Promise` rejected with the value of `throws` - - `sendAsJson`: This property determines whether or not the request body should be converted to `JSON` before being sent (defaults to `true`). - - `includeContentLength`: Set this property to true to automatically add the `content-length` header (defaults to `true`). - - `redirectUrl`: _experimental_ the url the response should be from (to imitate followed redirects - will set `redirected: true` on the response) - - `object`: All objects that do not meet the criteria above are converted to `JSON` and returned as the body of a 200 response. - - `Function(url, opts)`: A function that is passed the url and opts `fetch()` is called with and that returns any of the responses listed above (or a `Promise` for any of them) -- `options`: A configuration object with all/additional properties to define a route to mock - - `name`: A unique string naming the route. Used to subsequently retrieve references to the calls, grouped by name. Defaults to `matcher.toString()` - - `method`: http method to match - - `headers`: key/value map of headers to match - - `query`: key/value map of query strings to match, in any order - - `params`: when the `express:` keyword is used in a string matcher, a key/value map `params` can be passed here, to match the parameters extracted by express path matching - - `matcher`: as specified above - - `response`: as specified above - - `repeat`: An integer, `n`, limiting the number of times the matcher can be used. If the route has already been called `n` times the route will be ignored and the call to `fetch()` will fall through to be handled by any other routes defined (which may eventually result in an error if nothing matches it) - - `overwriteRoutes`: If the route you're adding clashes with an existing route, setting `true` here will overwrite the clashing route, `false` will add another route to the stack which will be used as a fallback (useful when using the `repeat` option). Adding a clashing route without specifying this option will throw an error. It can also be set as a global option (see the **Config** section below) - -#### `sandbox()` - -This returns a drop-in mock for fetch which can be passed to other mocking libraries. It implements the full fetch-mock api and maintains its own state independent of other instances, so tests can be run in parallel. e.g. - -#### `once()` - -Shorthand for `mock()` which limits to being called one time only. (see `repeat` option above) - -#### `get()`, `post()`, `put()`, `delete()`, `head()`, `patch()` - -Shorthands for `mock()` restricted to a particular method _Tip: if you use some other method a lot you can easily define your own shorthands e.g.:_ - -``` -fetchMock.purge = function (matcher, response, options) { - return this.mock(matcher, response, Object.assign({}, options, {method: 'PURGE'})); -} -``` - -#### `getOnce()`, `postOnce()`, `putOnce()`, `deleteOnce()`, `headOnce()`, `patchOnce()` - -Shorthands for `mock()` restricted to a particular method and that will only respond once - -#### `catch(response)` - -This is used to define how to respond to calls to fetch that don't match any of the defined mocks. It accepts the same types of response as a normal call to `.mock()`. It can also take an arbitrary function to completely customise behaviour of unmatched calls. It is chainable and can be called before or after other calls to `.mock()`. If `.catch()` is called without any parameters then every unmatched call will receive a `200` response - -#### `spy()` - -Similar to `catch()`, this records the call history of unmatched calls, but instead of responding with a stubbed response, the request is passed through to native `fetch()` and is allowed to communicate over the network. - -To use `.spy()` on a sandboxed `fetchMock`, `fetchMock.config.fetch` must be set to a reference to the `fetch` implementation you use in your code. - -``` - fetchMock.sandbox().mock('http://domain.com', 200) -``` - -Existing sandboxed `fetchMock`s can also have `.sandbox()` called on them, thus building mocks that inherit some settings from a parent mock - -#### `restore()/reset()` - -Chainable method that restores `fetch()` to its unstubbed state and clears all data recorded for its calls. - -#### `resetHistory()` - -Chainable method that clears all data recorded for `fetch()`'s calls. _It will not restore fetch to its default implementation_ - -_Note that `restore()`, `reset()` and `resetHistory()` are all bound to fetchMock, and can be used directly as callbacks e.g. `afterEach(fetchMock.reset)` will work just fine. There is no need for `afterEach(function () {fetchMock.reset()})`_ - -## Inspecting how `fetch()` has been called - -### Filtering - -Most of the methods below accept two parameters, `(filter, options)` - -- `filter` Enables filtering fetch calls for the most commonly use cases. The behaviour can be counterintuitive. The following rules, applied in the order they are described, are used to try to retrieve calls. If any rule retrieves no calls the next rule will be tried. - - If `options` is defined (it can even be an empty object), `filter` is executed using the same execution plan as matchers used in `.mock()`. Any calls matched by it will be returned. `options` will be used in a similar way to the options used by `mock()`. `options` may be a string specifying a `method` to filter by - - If `filter` is `undefined` all calls, matched _and_ unmatched, are returned - - If `filter` is `true` (or `fetchMock.MATCHED`) all calls that matched some route are returned - - If `filter` is `false` (or `fetchMock.UNMATCHED`) all calls that did not match any route are returned (when `.spy()`, `catch()` or `config.fallThroughToNetwork` were used to prevent errors being thrown) - - If `filter` is the name of a named route, all calls handled by that route are returned - - If `filter` is equal to `matcher` or `matcher.toString()` for a route, all calls handled by that route are returned - - `filter` is executed using the same execution plan as matchers used in `.mock()`. Any calls matched by it will be returned. - -#### `called(filter, method)` - -Returns a Boolean indicating whether fetch was called and a route was matched. If `filter` is specified it only returns `true` if that particular route was matched. - -#### `done(filter, method)` - -Returns a Boolean indicating whether fetch was called the expected number of times (or at least once if the route defines no expectation is set for the route). _Unlike the other methods for inspecting calls, unmatched calls are irrelevant_. Therefore, if no `filter` is passed, `done()` returns `true` if every route has been called the number of expected times. - -#### `calls(filter, method)` - -Returns an array of all calls to fetch matchingthe given filters. Each call is returned as an array of length 2, `[url, options]`. If `fetch` was called using a `Request` instance, this will be available as a `request` property on this array. - -#### `lastCall(filter, method)` - -Returns the arguments for the last matched call to fetch - -#### `lastUrl(filter, method)` - -Returns the url for the last matched call to fetch. When `fetch` was last called using a `Request` instance, the url will be extracted from this - -#### `lastOptions(filter, method)` - -Returns the options for the last matched call to fetch. When `fetch` was last called using a `Request` instance, a set of `options` inferred from the `Request` will be returned - -#### `flush()` - -Returns a `Promise` that resolves once all fetches handled by fetch-mock have resolved. Pass in `true` to wait for all response methods (`res.json()`, `res.text()`, etc.) to resolve too. Useful for testing code that uses `fetch` but doesn't return a promise. - -## Config - -On either the global or sandboxed `fetchMock` instances, the following config options can be set by setting properties on `fetchMock.config`. Many can also be set on individual calls to `.mock()`. - -- `sendAsJson` [default `true`] - by default fetchMock will convert objects to JSON before sending. This is overrideable from each call but for some scenarios e.g. when dealing with a lot of array buffers, it can be useful to default to `false` -- `includeContentLength` [default `true`]: When set to true this will make fetchMock automatically add the `content-length` header. This is especially useful when combined with `sendAsJson` because then fetchMock does the conversion to JSON for you and knows the resulting length so you don’t have to compute this yourself by basically doing the same conversion to JSON. -- `fallbackToNetwork` [default `false`] If true then unmatched calls will transparently fall through to the network, if false an error will be thrown. If set to `always`, all calls will fall through, effectively disabling fetch-mock. to Within individual tests `.catch()` and `spy()` can be used for fine-grained control of this -- `overwriteRoutes`: If a new route clashes with an existing route, setting `true` here will overwrite the clashing route, `false` will add another route to the stack which will be used as a fallback (useful when using the `repeat` option). Adding a clashing route without specifying this option will throw an error. -- `warnOnFallback` [default `true`] If true then any unmatched calls that are caught by a fallback handler (either the network or a custom function set using `catch()`) will emit warnings -- `Headers`,`Request`,`Response`,`Promise`, `fetch` - When using non standard fetch (e.g. a ponyfill, or aversion of `node-fetch` other than the one bundled with `fetch-mock`) or an alternative Promise implementation, this will configure fetch-mock to use your chosen implementations. - -Note that `Object.assign(fetchMock.config, require('fetch-ponyfill')())` will configure fetch-mock to use all of fetch-ponyfill's classes. In most cases, it should only be necessary to set this once before any tests run. diff --git a/docs/_site/css/editor.css b/docs/css/editor.css similarity index 100% rename from docs/_site/css/editor.css rename to docs/css/editor.css diff --git a/docs/css/style.scss b/docs/css/style.scss new file mode 100644 index 00000000..6a7e06af --- /dev/null +++ b/docs/css/style.scss @@ -0,0 +1,26 @@ +--- +layout: null +sitemap: false +--- + +$brand-colour: #35d69b; + +$nav-header-height: 60px; +$nav-background-color: #f5f5f5; +$nav-width: 300px; + +$mobile-break: 45rem; + +{% if site.baseurl %} + $base-url: {{ site.baseurl }}; +{% else %} + $base-url: ''; +{% endif %} + +@import "layout"; +@import "docs"; +@import "tables"; +@import "navigation"; +@import "borland"; +// @import "cloudcannon"; + diff --git a/docs/examples.md b/docs/examples.md deleted file mode 100644 index c4dff841..00000000 --- a/docs/examples.md +++ /dev/null @@ -1,10 +0,0 @@ -- [Introduction](/fetch-mock) -- [Quickstart](/fetch-mock/quickstart) -- [Installation and usage ](/fetch-mock/installation) -- [API documentation](/fetch-mock/api) -- [Troubleshooting](/fetch-mock/troubleshooting) -- Examples - -# Examples - -//todo diff --git a/docs/images/_screenshot.png b/docs/images/_screenshot.png new file mode 100644 index 00000000..181756df Binary files /dev/null and b/docs/images/_screenshot.png differ diff --git a/docs/_site/images/emblem.svg b/docs/images/emblem.svg similarity index 100% rename from docs/_site/images/emblem.svg rename to docs/images/emblem.svg diff --git a/docs/_site/images/logo.png b/docs/images/logo.png similarity index 100% rename from docs/_site/images/logo.png rename to docs/images/logo.png diff --git a/docs/_site/images/logo.svg b/docs/images/logo.svg similarity index 100% rename from docs/_site/images/logo.svg rename to docs/images/logo.svg diff --git a/docs/_site/images/menu.svg b/docs/images/menu.svg similarity index 100% rename from docs/_site/images/menu.svg rename to docs/images/menu.svg diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..06d0d2d2 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,85 @@ +--- +title: API Docs +--- +{% assign sorted_collections = site.collections | sort: "position" %} +{% for collection in sorted_collections %} +
    + {% if collection.title %} + {% unless collection.title == "About" %} +

    {{collection.title}}

    + {% endunless %} + {% endif %} + {% assign sorted_docs = collection.docs | sort: "position" %} + {% for doc in sorted_docs %} + +
    +

    + + {{ doc.title }} + + {% if doc.parentMethod %} + Parameter for {{doc.parentMethod}}() + {% endif %} + +

    + {% include types.html block=doc %} + {% if doc.description %} +

    + + {{ doc.description | markdownify }} +

    + {% endif %} + + {% if doc.parameters %} + {% if doc.parametersBlockTitle %} +

    {{ doc.parametersBlockTitle }}

    + {% else %} +

    Parameters

    + {% endif %} + +
    + {% for parameter in doc.parameters %} +
    + {% include types.html block=parameter %} +
    +
    + {{ parameter.content | markdownify }} + {% if parameter.examples %} + {% for example in parameter.examples %} + {% include tiny-syntax.html example=example %} + {% endfor %} + {% endif %} + {% if parameter.options %} +
    + {% for option in parameter.options %} +
    + {% include types.html block=option %} +
    +
    + {{ option.content | markdownify }} + {% if option.examples %} + {% for example in option.examples %} + {% include tiny-syntax.html example=example %} + {% endfor %} + {% endif %} +
    + {% endfor %} +
    + {% endif %} +
    + {% endfor %} +
    + {% endif %} + + {{ doc.content_markdown | markdownify | replace: "
    ", "
    Parameters
    " }} + + {% if doc.left_code_blocks and doc.left_code_blocks[0].code_block %} + {% for block in doc.left_code_blocks %} + {% include syntax-highlight.html block=block %} + {% endfor %} + {% endif %} +
    + + {% endfor %} +
    +{% endfor %} diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 46d93df4..00000000 --- a/docs/index.md +++ /dev/null @@ -1,25 +0,0 @@ -fetch-mock allows mocking http requests made using fetch, or any one of the many libraries imitating its api such as [isomorphic-fetch](https://www.npmjs.com/package/isomorphic-fetch), [node-fetch](https://www.npmjs.com/package/node-fetch) and [fetch-ponyfill](https://www.npmjs.com/package/fetch-ponyfill). - -The library will run in most JavaScript environments, including nodejs, web workers and service workers, and any browser that either supports fetch natively or that can have a fetch polyfill/ponyfill installed. - -As well as shorthand methods for the simplest use cases, it offers a flexible API for customising all aspects of mocking behaviour. - -**Uses `async / await` - for older node versions use v5, or require the transpiled version: require('fetch-mock/es5/server')** - -
    - I devote a lot of time to maintaining fetch-mock for free. I don't ask for payment, but am raising money for a refugee charity - please consider donating -
    - -## These docs are for v7 - -- Introduction -- [Quickstart](/fetch-mock/quickstart) -- [Installation and usage ](/fetch-mock/installation) -- [API documentation](/fetch-mock/api) -- [Troubleshooting](/fetch-mock/troubleshooting) -- [Examples](/fetch-mock/examples) - -* [V6 - V7 upgrade guide](/fetch-mock/v6-v7-upgrade) -* [V6 docs](/fetch-mock/v6) -* [V5 - V6 upgrade guide](/fetch-mock/v5-v6-upgrade) -* [V5 docs](/fetch-mock/v5) diff --git a/docs/installation.md b/docs/installation.md deleted file mode 100644 index b35c3ffe..00000000 --- a/docs/installation.md +++ /dev/null @@ -1,69 +0,0 @@ -- [Introduction](/fetch-mock) -- [Quickstart](/fetch-mock/quickstart) -- Installation and usage -- [API documentation](/fetch-mock/api) -- [Troubleshooting](/fetch-mock/troubleshooting) -- [Examples](/fetch-mock/examples) - -# Installation - -Install fetch-mock using `npm install --save-dev fetch-mock` - -In most environments use one of the following to use it in your code. - -```js -const fetchMock = require('fetch-mock'); - -// The following is recommended in order to expose constants that -// will make tests that check for matched or unmatched calls more -// readable -const { fetchMock, MATCHED, UNMATCHED } = require('fetch-mock'); -``` - -Some exceptions include: - -- If your client-side code or tests do not use a loader that respects the browser field of `package.json` use `require('fetch-mock/es5/client')`. -- If you need to use fetch-mock without commonjs, you can include the precompiled `node_modules/fetch-mock/es5/client-bundle.js` in a script tag. This loads fetch-mock into the `fetchMock` global variable. -- For server side tests running in nodejs 6 or lower use `require('fetch-mock/es5/server')`. You will also need to `npm i -D babel-polyfill` - -## Global fetch - -By default fetch-mock assumes `fetch` is a global so once you've required fetch-mock refer to the quickstart and api docs. - -### Polyfilling fetch - -Many older browsers will require polyfilling the `fetch` global - -- In nodejs `require('isomorphic-fetch')` before any of your tests. -- In the browser `require('isomorphic-fetch')` can also be used, but it may be easier to `npm install whatwg-fetch` (the module isomorphic-fetch is built around) and load `./node_modules/whatwg-fetch/fetch.js` directly into the page, either in a script tag or by referencing in your test runner config. -- When using karma-webpack it's best not to use the `webpack.ProvidePlugin` for this. Instead just add `node_modules/whatwg-fetch/fetch.js` to your list of files to include, or require it directly into your tests before requiring fetch-mock. - -## Non-global fetch - -When using a non-global fetch implementation (such as node-fetch or fetch-ponyfill) use the `sandbox()` method to return a function that can be used as a replacement for fetch, and be passed into your source code using your choice of mocking library. The function returned by `sandbox()` supports the full fetch-mock api so once generated it can be worked with as if it were the original `fetch-mock` object, e.g. - -``` -const fetchMock = require('fetch-mock'); -const myMock = fetchMock.sandbox().mock('/home', 200); -// pass myMock in to your application code, instead of fetch, run it, then... -expect(myMock.called('/home')).to.be.true; -``` - -## References to Request, Response, Headers, fetch and Promise - -If you're using a non-global fetch implementation, or wish to use a custom Promise implementation, you may need to tell fetch-mock to use these when matching requests and returning responses. Do this by setting these properties on `fetchMock.config`, e.g - -``` -const ponyfill = require('fetch-ponyfill')(); -fetchMock.config = Object.assign(fetchMock.config, { - Promise: require('Bluebird').promise, - Headers: ponyfill.Headers, - Request: ponyfill.Request, - Response: ponyfill.Response, - fetch: ponyfill -}, -``` - -This should be done before running any tests. - -Note that when using `node-fetch`, `fetch-mock` will use the instance you already have installed so there should be no need to set any of the above (apart from `fetch`, which is required if you intend to use the `.spy()` method) diff --git a/docs/js/lunr.min.js b/docs/js/lunr.min.js new file mode 100644 index 00000000..6dcb7ab2 --- /dev/null +++ b/docs/js/lunr.min.js @@ -0,0 +1,857 @@ +/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.7.1 + * Copyright (C) 2016 Oliver Nightingale + * @license MIT + */ +!(function() { + var t = function(e) { + const n = new t.Index(); + return ( + n.pipeline.add(t.trimmer, t.stopWordFilter, t.stemmer), + e && e.call(n, n), + n + ); + }; + (t.version = '0.7.1'), + (t.utils = {}), + (t.utils.warn = (function(t) { + return function(e) { + t.console && console.warn && console.warn(e); + }; + })(this)), + (t.utils.asString = function(t) { + return void 0 === t || null === t ? '' : t.toString(); + }), + (t.EventEmitter = function() { + this.events = {}; + }), + (t.EventEmitter.prototype.addListener = function() { + let t = Array.prototype.slice.call(arguments), + e = t.pop(), + n = t; + if ('function' !== typeof e) + throw new TypeError('last argument must be a function'); + n.forEach(function(t) { + this.hasHandler(t) || (this.events[t] = []), this.events[t].push(e); + }, this); + }), + (t.EventEmitter.prototype.removeListener = function(t, e) { + if (this.hasHandler(t)) { + const n = this.events[t].indexOf(e); + this.events[t].splice(n, 1), + this.events[t].length || delete this.events[t]; + } + }), + (t.EventEmitter.prototype.emit = function(t) { + if (this.hasHandler(t)) { + const e = Array.prototype.slice.call(arguments, 1); + this.events[t].forEach(function(t) { + t.apply(void 0, e); + }); + } + }), + (t.EventEmitter.prototype.hasHandler = function(t) { + return t in this.events; + }), + (t.tokenizer = function(e) { + return arguments.length && null != e && void 0 != e + ? Array.isArray(e) + ? e.map(function(e) { + return t.utils.asString(e).toLowerCase(); + }) + : e + .toString() + .trim() + .toLowerCase() + .split(t.tokenizer.seperator) + : []; + }), + (t.tokenizer.seperator = /[\s\-]+/), + (t.tokenizer.load = function(t) { + const e = this.registeredFunctions[t]; + if (!e) throw new Error('Cannot load un-registered function: ' + t); + return e; + }), + (t.tokenizer.label = 'default'), + (t.tokenizer.registeredFunctions = { default: t.tokenizer }), + (t.tokenizer.registerFunction = function(e, n) { + n in this.registeredFunctions && + t.utils.warn('Overwriting existing tokenizer: ' + n), + (e.label = n), + (this.registeredFunctions[n] = e); + }), + (t.Pipeline = function() { + this._stack = []; + }), + (t.Pipeline.registeredFunctions = {}), + (t.Pipeline.registerFunction = function(e, n) { + n in this.registeredFunctions && + t.utils.warn('Overwriting existing registered function: ' + n), + (e.label = n), + (t.Pipeline.registeredFunctions[e.label] = e); + }), + (t.Pipeline.warnIfFunctionNotRegistered = function(e) { + const n = e.label && e.label in this.registeredFunctions; + n || + t.utils.warn( + 'Function is not registered with pipeline. This may cause problems when serialising the index.\n', + e + ); + }), + (t.Pipeline.load = function(e) { + const n = new t.Pipeline(); + return ( + e.forEach(function(e) { + const i = t.Pipeline.registeredFunctions[e]; + if (!i) throw new Error('Cannot load un-registered function: ' + e); + n.add(i); + }), + n + ); + }), + (t.Pipeline.prototype.add = function() { + const e = Array.prototype.slice.call(arguments); + e.forEach(function(e) { + t.Pipeline.warnIfFunctionNotRegistered(e), this._stack.push(e); + }, this); + }), + (t.Pipeline.prototype.after = function(e, n) { + t.Pipeline.warnIfFunctionNotRegistered(n); + let i = this._stack.indexOf(e); + if (-1 == i) throw new Error('Cannot find existingFn'); + (i += 1), this._stack.splice(i, 0, n); + }), + (t.Pipeline.prototype.before = function(e, n) { + t.Pipeline.warnIfFunctionNotRegistered(n); + const i = this._stack.indexOf(e); + if (-1 == i) throw new Error('Cannot find existingFn'); + this._stack.splice(i, 0, n); + }), + (t.Pipeline.prototype.remove = function(t) { + const e = this._stack.indexOf(t); + -1 != e && this._stack.splice(e, 1); + }), + (t.Pipeline.prototype.run = function(t) { + for ( + var e = [], n = t.length, i = this._stack.length, r = 0; + n > r; + r++ + ) { + for ( + var o = t[r], s = 0; + i > s && ((o = this._stack[s](o, r, t)), void 0 !== o && '' !== o); + s++ + ); + void 0 !== o && '' !== o && e.push(o); + } + return e; + }), + (t.Pipeline.prototype.reset = function() { + this._stack = []; + }), + (t.Pipeline.prototype.toJSON = function() { + return this._stack.map(function(e) { + return t.Pipeline.warnIfFunctionNotRegistered(e), e.label; + }); + }), + (t.Vector = function() { + (this._magnitude = null), (this.list = void 0), (this.length = 0); + }), + (t.Vector.Node = function(t, e, n) { + (this.idx = t), (this.val = e), (this.next = n); + }), + (t.Vector.prototype.insert = function(e, n) { + this._magnitude = void 0; + const i = this.list; + if (!i) return (this.list = new t.Vector.Node(e, n, i)), this.length++; + if (e < i.idx) + return (this.list = new t.Vector.Node(e, n, i)), this.length++; + for (var r = i, o = i.next; void 0 != o; ) { + if (e < o.idx) + return (r.next = new t.Vector.Node(e, n, o)), this.length++; + (r = o), (o = o.next); + } + return (r.next = new t.Vector.Node(e, n, o)), this.length++; + }), + (t.Vector.prototype.magnitude = function() { + if (this._magnitude) return this._magnitude; + for (var t, e = this.list, n = 0; e; ) + (t = e.val), (n += t * t), (e = e.next); + return (this._magnitude = Math.sqrt(n)); + }), + (t.Vector.prototype.dot = function(t) { + for (var e = this.list, n = t.list, i = 0; e && n; ) + e.idx < n.idx + ? (e = e.next) + : e.idx > n.idx + ? (n = n.next) + : ((i += e.val * n.val), (e = e.next), (n = n.next)); + return i; + }), + (t.Vector.prototype.similarity = function(t) { + return this.dot(t) / (this.magnitude() * t.magnitude()); + }), + (t.SortedSet = function() { + (this.length = 0), (this.elements = []); + }), + (t.SortedSet.load = function(t) { + const e = new this(); + return (e.elements = t), (e.length = t.length), e; + }), + (t.SortedSet.prototype.add = function() { + let t, e; + for (t = 0; t < arguments.length; t++) + (e = arguments[t]), + ~this.indexOf(e) || this.elements.splice(this.locationFor(e), 0, e); + this.length = this.elements.length; + }), + (t.SortedSet.prototype.toArray = function() { + return this.elements.slice(); + }), + (t.SortedSet.prototype.map = function(t, e) { + return this.elements.map(t, e); + }), + (t.SortedSet.prototype.forEach = function(t, e) { + return this.elements.forEach(t, e); + }), + (t.SortedSet.prototype.indexOf = function(t) { + for ( + var e = 0, + n = this.elements.length, + i = n - e, + r = e + Math.floor(i / 2), + o = this.elements[r]; + i > 1; + + ) { + if (o === t) return r; + t > o && (e = r), + o > t && (n = r), + (i = n - e), + (r = e + Math.floor(i / 2)), + (o = this.elements[r]); + } + return o === t ? r : -1; + }), + (t.SortedSet.prototype.locationFor = function(t) { + for ( + var e = 0, + n = this.elements.length, + i = n - e, + r = e + Math.floor(i / 2), + o = this.elements[r]; + i > 1; + + ) + t > o && (e = r), + o > t && (n = r), + (i = n - e), + (r = e + Math.floor(i / 2)), + (o = this.elements[r]); + return o > t ? r : t > o ? r + 1 : void 0; + }), + (t.SortedSet.prototype.intersect = function(e) { + for ( + var n = new t.SortedSet(), + i = 0, + r = 0, + o = this.length, + s = e.length, + a = this.elements, + h = e.elements; + ; + + ) { + if (i > o - 1 || r > s - 1) break; + a[i] !== h[r] + ? a[i] < h[r] + ? i++ + : a[i] > h[r] && r++ + : (n.add(a[i]), i++, r++); + } + return n; + }), + (t.SortedSet.prototype.clone = function() { + const e = new t.SortedSet(); + return (e.elements = this.toArray()), (e.length = e.elements.length), e; + }), + (t.SortedSet.prototype.union = function(t) { + let e, n, i; + this.length >= t.length ? ((e = this), (n = t)) : ((e = t), (n = this)), + (i = e.clone()); + for (let r = 0, o = n.toArray(); r < o.length; r++) i.add(o[r]); + return i; + }), + (t.SortedSet.prototype.toJSON = function() { + return this.toArray(); + }), + (t.Index = function() { + (this._fields = []), + (this._ref = 'id'), + (this.pipeline = new t.Pipeline()), + (this.documentStore = new t.Store()), + (this.tokenStore = new t.TokenStore()), + (this.corpusTokens = new t.SortedSet()), + (this.eventEmitter = new t.EventEmitter()), + (this.tokenizerFn = t.tokenizer), + (this._idfCache = {}), + this.on( + 'add', + 'remove', + 'update', + function() { + this._idfCache = {}; + }.bind(this) + ); + }), + (t.Index.prototype.on = function() { + const t = Array.prototype.slice.call(arguments); + return this.eventEmitter.addListener.apply(this.eventEmitter, t); + }), + (t.Index.prototype.off = function(t, e) { + return this.eventEmitter.removeListener(t, e); + }), + (t.Index.load = function(e) { + e.version !== t.version && + t.utils.warn( + 'version mismatch: current ' + t.version + ' importing ' + e.version + ); + const n = new this(); + return ( + (n._fields = e.fields), + (n._ref = e.ref), + (n.tokenizer = t.tokenizer.load(e.tokenizer)), + (n.documentStore = t.Store.load(e.documentStore)), + (n.tokenStore = t.TokenStore.load(e.tokenStore)), + (n.corpusTokens = t.SortedSet.load(e.corpusTokens)), + (n.pipeline = t.Pipeline.load(e.pipeline)), + n + ); + }), + (t.Index.prototype.field = function(t, e) { + var e = e || {}, + n = { name: t, boost: e.boost || 1 }; + return this._fields.push(n), this; + }), + (t.Index.prototype.ref = function(t) { + return (this._ref = t), this; + }), + (t.Index.prototype.tokenizer = function(e) { + const n = e.label && e.label in t.tokenizer.registeredFunctions; + return ( + n || + t.utils.warn( + 'Function is not a registered tokenizer. This may cause problems when serialising the index' + ), + (this.tokenizerFn = e), + this + ); + }), + (t.Index.prototype.add = function(e, n) { + var i = {}, + r = new t.SortedSet(), + o = e[this._ref], + n = void 0 === n ? !0 : n; + this._fields.forEach(function(t) { + const n = this.pipeline.run(this.tokenizerFn(e[t.name])); + i[t.name] = n; + for (let o = 0; o < n.length; o++) { + const s = n[o]; + r.add(s), this.corpusTokens.add(s); + } + }, this), + this.documentStore.set(o, r); + for (let s = 0; s < r.length; s++) { + for ( + var a = r.elements[s], h = 0, u = 0; + u < this._fields.length; + u++ + ) { + let l = this._fields[u], + c = i[l.name], + f = c.length; + if (f) { + for (var d = 0, p = 0; f > p; p++) c[p] === a && d++; + h += (d / f) * l.boost; + } + } + this.tokenStore.add(a, { ref: o, tf: h }); + } + n && this.eventEmitter.emit('add', e, this); + }), + (t.Index.prototype.remove = function(t, e) { + var n = t[this._ref], + e = void 0 === e ? !0 : e; + if (this.documentStore.has(n)) { + const i = this.documentStore.get(n); + this.documentStore.remove(n), + i.forEach(function(t) { + this.tokenStore.remove(t, n); + }, this), + e && this.eventEmitter.emit('remove', t, this); + } + }), + (t.Index.prototype.update = function(t, e) { + var e = void 0 === e ? !0 : e; + this.remove(t, !1), + this.add(t, !1), + e && this.eventEmitter.emit('update', t, this); + }), + (t.Index.prototype.idf = function(t) { + const e = '@' + t; + if (Object.prototype.hasOwnProperty.call(this._idfCache, e)) + return this._idfCache[e]; + let n = this.tokenStore.count(t), + i = 1; + return ( + n > 0 && (i = 1 + Math.log(this.documentStore.length / n)), + (this._idfCache[e] = i) + ); + }), + (t.Index.prototype.search = function(e) { + let n = this.pipeline.run(this.tokenizerFn(e)), + i = new t.Vector(), + r = [], + o = this._fields.reduce(function(t, e) { + return t + e.boost; + }, 0), + s = n.some(function(t) { + return this.tokenStore.has(t); + }, this); + if (!s) return []; + n.forEach(function(e, n, s) { + let a = (1 / s.length) * this._fields.length * o, + h = this, + u = this.tokenStore.expand(e).reduce(function(n, r) { + let o = h.corpusTokens.indexOf(r), + s = h.idf(r), + u = 1, + l = new t.SortedSet(); + if (r !== e) { + const c = Math.max(3, r.length - e.length); + u = 1 / Math.log(c); + } + o > -1 && i.insert(o, a * s * u); + for ( + let f = h.tokenStore.get(r), + d = Object.keys(f), + p = d.length, + v = 0; + p > v; + v++ + ) + l.add(f[d[v]].ref); + return n.union(l); + }, new t.SortedSet()); + r.push(u); + }, this); + const a = r.reduce(function(t, e) { + return t.intersect(e); + }); + return a + .map(function(t) { + return { ref: t, score: i.similarity(this.documentVector(t)) }; + }, this) + .sort(function(t, e) { + return e.score - t.score; + }); + }), + (t.Index.prototype.documentVector = function(e) { + for ( + var n = this.documentStore.get(e), + i = n.length, + r = new t.Vector(), + o = 0; + i > o; + o++ + ) { + let s = n.elements[o], + a = this.tokenStore.get(s)[e].tf, + h = this.idf(s); + r.insert(this.corpusTokens.indexOf(s), a * h); + } + return r; + }), + (t.Index.prototype.toJSON = function() { + return { + version: t.version, + fields: this._fields, + ref: this._ref, + tokenizer: this.tokenizerFn.label, + documentStore: this.documentStore.toJSON(), + tokenStore: this.tokenStore.toJSON(), + corpusTokens: this.corpusTokens.toJSON(), + pipeline: this.pipeline.toJSON() + }; + }), + (t.Index.prototype.use = function(t) { + const e = Array.prototype.slice.call(arguments, 1); + e.unshift(this), t.apply(this, e); + }), + (t.Store = function() { + (this.store = {}), (this.length = 0); + }), + (t.Store.load = function(e) { + const n = new this(); + return ( + (n.length = e.length), + (n.store = Object.keys(e.store).reduce(function(n, i) { + return (n[i] = t.SortedSet.load(e.store[i])), n; + }, {})), + n + ); + }), + (t.Store.prototype.set = function(t, e) { + this.has(t) || this.length++, (this.store[t] = e); + }), + (t.Store.prototype.get = function(t) { + return this.store[t]; + }), + (t.Store.prototype.has = function(t) { + return t in this.store; + }), + (t.Store.prototype.remove = function(t) { + this.has(t) && (delete this.store[t], this.length--); + }), + (t.Store.prototype.toJSON = function() { + return { store: this.store, length: this.length }; + }), + (t.stemmer = (function() { + let t = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }, + e = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }, + n = '[^aeiou]', + i = '[aeiouy]', + r = n + '[^aeiouy]*', + o = i + '[aeiou]*', + s = '^(' + r + ')?' + o + r, + a = '^(' + r + ')?' + o + r + '(' + o + ')?$', + h = '^(' + r + ')?' + o + r + o + r, + u = '^(' + r + ')?' + i, + l = new RegExp(s), + c = new RegExp(h), + f = new RegExp(a), + d = new RegExp(u), + p = /^(.+?)(ss|i)es$/, + v = /^(.+?)([^s])s$/, + g = /^(.+?)eed$/, + m = /^(.+?)(ed|ing)$/, + y = /.$/, + S = /(at|bl|iz)$/, + w = new RegExp('([^aeiouylsz])\\1$'), + k = new RegExp('^' + r + i + '[^aeiouwxy]$'), + x = /^(.+?[^aeiou])y$/, + b = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/, + E = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/, + F = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/, + _ = /^(.+?)(s|t)(ion)$/, + z = /^(.+?)e$/, + O = /ll$/, + P = new RegExp('^' + r + i + '[^aeiouwxy]$'), + T = function(n) { + let i, r, o, s, a, h, u; + if (n.length < 3) return n; + if ( + ((o = n.substr(0, 1)), + 'y' == o && (n = o.toUpperCase() + n.substr(1)), + (s = p), + (a = v), + s.test(n) + ? (n = n.replace(s, '$1$2')) + : a.test(n) && (n = n.replace(a, '$1$2')), + (s = g), + (a = m), + s.test(n)) + ) { + var T = s.exec(n); + (s = l), s.test(T[1]) && ((s = y), (n = n.replace(s, ''))); + } else if (a.test(n)) { + var T = a.exec(n); + (i = T[1]), + (a = d), + a.test(i) && + ((n = i), + (a = S), + (h = w), + (u = k), + a.test(n) + ? (n += 'e') + : h.test(n) + ? ((s = y), (n = n.replace(s, ''))) + : u.test(n) && (n += 'e')); + } + if (((s = x), s.test(n))) { + var T = s.exec(n); + (i = T[1]), (n = i + 'i'); + } + if (((s = b), s.test(n))) { + var T = s.exec(n); + (i = T[1]), (r = T[2]), (s = l), s.test(i) && (n = i + t[r]); + } + if (((s = E), s.test(n))) { + var T = s.exec(n); + (i = T[1]), (r = T[2]), (s = l), s.test(i) && (n = i + e[r]); + } + if (((s = F), (a = _), s.test(n))) { + var T = s.exec(n); + (i = T[1]), (s = c), s.test(i) && (n = i); + } else if (a.test(n)) { + var T = a.exec(n); + (i = T[1] + T[2]), (a = c), a.test(i) && (n = i); + } + if (((s = z), s.test(n))) { + var T = s.exec(n); + (i = T[1]), + (s = c), + (a = f), + (h = P), + (s.test(i) || (a.test(i) && !h.test(i))) && (n = i); + } + return ( + (s = O), + (a = c), + s.test(n) && a.test(n) && ((s = y), (n = n.replace(s, ''))), + 'y' == o && (n = o.toLowerCase() + n.substr(1)), + n + ); + }; + return T; + })()), + t.Pipeline.registerFunction(t.stemmer, 'stemmer'), + (t.generateStopWordFilter = function(t) { + const e = t.reduce(function(t, e) { + return (t[e] = e), t; + }, {}); + return function(t) { + return t && e[t] !== t ? t : void 0; + }; + }), + (t.stopWordFilter = t.generateStopWordFilter([ + 'a', + 'able', + 'about', + 'across', + 'after', + 'all', + 'almost', + 'also', + 'am', + 'among', + 'an', + 'and', + 'any', + 'are', + 'as', + 'at', + 'be', + 'because', + 'been', + 'but', + 'by', + 'can', + 'cannot', + 'could', + 'dear', + 'did', + 'do', + 'does', + 'either', + 'else', + 'ever', + 'every', + 'for', + 'from', + 'get', + 'got', + 'had', + 'has', + 'have', + 'he', + 'her', + 'hers', + 'him', + 'his', + 'how', + 'however', + 'i', + 'if', + 'in', + 'into', + 'is', + 'it', + 'its', + 'just', + 'least', + 'let', + 'like', + 'likely', + 'may', + 'me', + 'might', + 'most', + 'must', + 'my', + 'neither', + 'no', + 'nor', + 'not', + 'of', + 'off', + 'often', + 'on', + 'only', + 'or', + 'other', + 'our', + 'own', + 'rather', + 'said', + 'say', + 'says', + 'she', + 'should', + 'since', + 'so', + 'some', + 'than', + 'that', + 'the', + 'their', + 'them', + 'then', + 'there', + 'these', + 'they', + 'this', + 'tis', + 'to', + 'too', + 'twas', + 'us', + 'wants', + 'was', + 'we', + 'were', + 'what', + 'when', + 'where', + 'which', + 'while', + 'who', + 'whom', + 'why', + 'will', + 'with', + 'would', + 'yet', + 'you', + 'your' + ])), + t.Pipeline.registerFunction(t.stopWordFilter, 'stopWordFilter'), + (t.trimmer = function(t) { + return t.replace(/^\W+/, '').replace(/\W+$/, ''); + }), + t.Pipeline.registerFunction(t.trimmer, 'trimmer'), + (t.TokenStore = function() { + (this.root = { docs: {} }), (this.length = 0); + }), + (t.TokenStore.load = function(t) { + const e = new this(); + return (e.root = t.root), (e.length = t.length), e; + }), + (t.TokenStore.prototype.add = function(t, e, n) { + var n = n || this.root, + i = t.charAt(0), + r = t.slice(1); + return ( + i in n || (n[i] = { docs: {} }), + 0 === r.length + ? ((n[i].docs[e.ref] = e), void (this.length += 1)) + : this.add(r, e, n[i]) + ); + }), + (t.TokenStore.prototype.has = function(t) { + if (!t) return !1; + for (let e = this.root, n = 0; n < t.length; n++) { + if (!e[t.charAt(n)]) return !1; + e = e[t.charAt(n)]; + } + return !0; + }), + (t.TokenStore.prototype.getNode = function(t) { + if (!t) return {}; + for (var e = this.root, n = 0; n < t.length; n++) { + if (!e[t.charAt(n)]) return {}; + e = e[t.charAt(n)]; + } + return e; + }), + (t.TokenStore.prototype.get = function(t, e) { + return this.getNode(t, e).docs || {}; + }), + (t.TokenStore.prototype.count = function(t, e) { + return Object.keys(this.get(t, e)).length; + }), + (t.TokenStore.prototype.remove = function(t, e) { + if (t) { + for (var n = this.root, i = 0; i < t.length; i++) { + if (!(t.charAt(i) in n)) return; + n = n[t.charAt(i)]; + } + delete n.docs[e]; + } + }), + (t.TokenStore.prototype.expand = function(t, e) { + var n = this.getNode(t), + i = n.docs || {}, + e = e || []; + return ( + Object.keys(i).length && e.push(t), + Object.keys(n).forEach(function(n) { + 'docs' !== n && e.concat(this.expand(t + n, e)); + }, this), + e + ); + }), + (t.TokenStore.prototype.toJSON = function() { + return { root: this.root, length: this.length }; + }), + (function(t, e) { + 'function' === typeof define && define.amd + ? define(e) + : 'object' === typeof exports + ? (module.exports = e()) + : (t.lunr = e()); + })(this, function() { + return t; + }); +})(); diff --git a/docs/js/main.js b/docs/js/main.js new file mode 100644 index 00000000..069b6f11 --- /dev/null +++ b/docs/js/main.js @@ -0,0 +1,112 @@ +jQuery(function() { + let $sidebar = $('nav'), + $main = $('main'); + + const found = true; + + let $el; + + $sidebar.find('a').click(function() { + $('body').removeClass('nav-open'); + }); + + $('section > div.highlighter-rouge:first-of-type').each(function(i) { + let $this = $(this).before('
      '), + $languages = $this.prev(), + $notFirst = $this.nextUntil(':not(div.highlighter-rouge)'), + $all = $this.add($notFirst); + + $all.add($languages).wrapAll('
      '); + + listLanguages($all, $languages); + + $this.css('display', 'block'); + $notFirst.css('display', 'none'); + + $languages + .find('a') + .first() + .addClass('active'); + + $languages.find('a').click(function() { + $all.css('display', 'none'); + $all + .eq( + $(this) + .parent() + .index() + ) + .css('display', 'block'); + + $languages.find('a').removeClass('active'); + $(this).addClass('active'); + return false; + }); + + if ($languages.children().length === 0) { + $languages.remove(); + } + }); + + function listLanguages($el, $insert) { + $el.each(function(i) { + const title = $(this).attr('title'); + if (title) { + $insert.append('
    • ' + title + '
    • '); + } + }); + } + + const href = $('.sidebar a') + .first() + .attr('href'); + + if (href !== undefined && href.charAt(0) === '#') { + setActiveSidebarLink(); + + $(window).on('scroll', function(evt) { + setActiveSidebarLink(); + }); + } + + function setActiveSidebarLink() { + $('.sidebar a').removeClass('active'); + const $closest = getClosestHeader(); + $closest.addClass('active'); + document.title = $closest.text(); + } +}); + +function getClosestHeader() { + let $links = $('.sidebar a'), + top = window.scrollY, + $last = $links.first(); + + if (top < 300) { + return $last; + } + + if (top + window.innerHeight >= $('.main').height()) { + return $links.last(); + } + + for (let i = 0; i < $links.length; i++) { + let $link = $links.eq(i), + href = $link.attr('href'); + + if (href !== undefined && href.charAt(0) === '#' && href.length > 1) { + const $anchor = $(href); + + if ($anchor.length > 0) { + const offset = $anchor.offset(); + + if (top < offset.top - 300) { + return $last; + } + + $last = $link; + } + } + } + return $last; +} diff --git a/docs/quickstart.md b/docs/quickstart.md deleted file mode 100644 index e4e51ed3..00000000 --- a/docs/quickstart.md +++ /dev/null @@ -1,57 +0,0 @@ -- [Introduction](/fetch-mock) -- Quickstart -- [Installation and usage ](/fetch-mock/installation) -- [API documentation](/fetch-mock/api) -- [Troubleshooting](/fetch-mock/troubleshooting) -- [Examples](/fetch-mock/examples) - -# Quickstart - -## Setting up your mock - -The commonest use case is `fetchMock.mock(matcher, response)`, where `matcher` is a string or regex to match and `response` is a statusCode, string or object literal. You can also use `fetchMock.once(url ...)` to limit to a single call or `fetchMock.get()`, `fetchMock.post()` etc. to limit to a method. All these methods are chainable so you can easily define several mocks in a single test. - -## Analysing calls to your mock - -`fetchMock.called(matcher)` reports if any calls matched your mock (or leave `matcher` out if you just want to check `fetch` was called at all). `fetchMock.lastCall()`, `fetchMock.lastUrl()` or `fetchMock.lastOptions()` give you access to the parameters last passed in to `fetch`. `fetchMock.done()` will tell you if `fetch` was called the expected number of times. - -## Tearing down your mock - -`fetchMock.reset()` resets the call history. `fetchMock.restore()` will also restore `fetch()` to its native implementation - -## Example - -Example with node: suppose we have a file `make-request.js` with a function that calls `fetch`: - -```js -module.exports = function makeRequest() { - return fetch('http://httpbin.org/get').then(function(response) { - return response.json(); - }); -}; -``` - -We can use fetch-mock to mock `fetch`. In `mocked.js`: - -```js -var fetchMock = require('fetch-mock'); -var makeRequest = require('./make-request'); - -// Mock the fetch() global to always return the same value for GET -// requests to all URLs. -fetchMock.get('*', { hello: 'world' }); - -makeRequest().then(function(data) { - console.log('got data', data); -}); - -// Unmock. -fetchMock.restore(); -``` - -Result: - -```bash -$ node mocked.js -'got data' { hello: 'world' } -``` diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md deleted file mode 100644 index 982aaf8e..00000000 --- a/docs/troubleshooting.md +++ /dev/null @@ -1,40 +0,0 @@ -- [Introduction](/fetch-mock) -- [Quickstart](/fetch-mock/quickstart) -- [Installation and usage ](/fetch-mock/installation) -- [API documentation](/fetch-mock/api) -- Troubleshooting -- [Examples](/fetch-mock/examples) - -# Troubleshooting - -### `fetch` is assigned to a local variable, not a global - -First of all, consider whether you could just use `fetch` as a global. Here are 3 reasons why this is a good idea: - -- The `fetch` standard defines it as a global (and in some cases it won't work unless bound to `window`), so to write isomorphic code it's probably best to stick to this pattern -- [`isomorphic-fetch`](https://www.npmjs.com/package/isomorphic-fetch) takes care of installing it as a global in nodejs or the browser, so there's no effort on your part to do so. -- `fetch-mock` is primarily designed to work with `fetch` as a global and your experience of using it will be far more straightforward if you follow this pattern - -Still not convinced? - -In that case `fetchMock.sandbox()` can be used to generate a function which you can pass in to a mock loading library such as [`mockery`](https://www.npmjs.com/package/mockery) instead of `fetch` - -### `fetch` doesn't seem to be getting mocked? - -- If using a mock loading library such as `mockery`, are you requiring the module you're testing after registering `fetch-mock` with the mock loader? You probably should be ([Example incorrect usage](https://github.com/wheresrhys/fetch-mock/issues/70)). If you're using ES6 `import` it may not be possible to do this without reverting to using `require()` sometimes. -- If using `isomorphic-fetch` in your source, are you assigning it to a `fetch` variable? You _shouldn't_ be i.e. - - `import 'isomorphic-fetch'`, not `import fetch from 'isomorphic-fetch'` - - `require('isomorphic-fetch')`, not `const fetch = require('isomorphic-fetch')` - -### Environment doesn't support requiring fetch-mock? - -- If your client-side code or tests do not use a loader that respects the browser field of package.json use `require('fetch-mock/es5/client')`. -- If you need to use fetch-mock without commonjs, you can include the precompiled `node_modules/fetch-mock/es5/client-browserified.js` in a script tag. This loads fetch-mock into the `fetchMock` global variable. -- For server side tests running in nodejs 0.12 or lower use `require('fetch-mock/es5/server')` - -### Matching `Request` objects in node fails - -In node, if using npm at a version less than 2 the `Request` constructor used by `fetch-mock` won't necessarily be the same as the one used by `node-fetch`. To fix this either: - -- upgrade to npm@3 -- use `fetchMock.config.Request = myRequest`, where `myRequest` is a reference to the Request constructor used in your application code. diff --git a/docs/v5-v6-upgrade.md b/docs/v5-v6-upgrade.md deleted file mode 100644 index 32471a1f..00000000 --- a/docs/v5-v6-upgrade.md +++ /dev/null @@ -1,38 +0,0 @@ -# Upgrading from V5 to V6 - -This is a long overdue refactor of the entire library. As feature requests have come in, the code and test suite had become increasingly spaghettified, and this new version is a massive improvement on the previous implementation. - -For the most common use cases, and the basic mocking and inspecting api, very little has changed. The main changes are around how fetch-mock is configured and installed, and turning a few nice new features on by default (couldn't do so in v5 as would've been a breaking change) - -# Changes - -## Configuration and installation - -- Requires `async / await` - for older node versions use v5, or require the transpiled version: `require('fetch-mock/es5/server')` -- _No change to mocking fetch as a global_ -- Uses whatever version of `node-fetch` you have already installed in your project i.e. can be used with `node-fetch` 2 -- `.sandbox()` no longer accepts a custom `Promise` implementation as a parameter -- Sandboxes can now be 'sub-classed' i.e. define some mocks on a sandbox, then call `.sandbox()` on it to create a new one inheriting all its settings -- No longer has a `setImplementations()` method. Instead, assign custom `Promise` and `fetch` helper classes directly to the `config` property of the fetch-mock instance. This may be done before or after sandboxing -- No longer has a `configure()` method. Instead set options directly on the `.config` property. See the api docs for a complete list of options - -## Routing - -- `^` is no longer a valid way of matching the beginning of strings; use `begin:` instead -- `overwriteRoutes` option allows for existing routes in a mock to be overwritten. It's also possible to define multiple routes with 'the same' matcher. Default behaviour is to error. Set to `false` to use old "buffer-like" behavior - -## Responses - -- `Content-Length` header generated by default for all responses (can be configured to not do so globally or per response.) -- Objects will be converted to `JSON` responses if they contain any properties not listed in the docs as special response config options (previous behaviour was to convert if any of the properties were present). This means that e.g. `{user: 'me', status: 'happy'}` can easily be sent as `JSON` -- `__redirectUrl` option is now named `redirectUrl` -- `times` option is now named `repeat` - -## Inspecting - -- All inspection methods now filter, in addition to the existing check against `matcher.toString()`, based on the following rules - - An exact url - - `true` for matched calls only - - `false` for unmatched calls only - - `undefined` (or no argument) includes all calls to `fetch` in order in a single array, i.e. no longer an object with `matched` and `unmatched` properties -- When `fetch` was last called with a `Request` object, `lastUrl()` and `lastOpts()` give easier access to the `url` and full `Request` object diff --git a/docs/v5/_config.yml b/docs/v5/_config.yml deleted file mode 100644 index b7e0752a..00000000 --- a/docs/v5/_config.yml +++ /dev/null @@ -1,4 +0,0 @@ -markdown: kramdown -theme: jekyll-theme-slate -title: fetch-mock -description: Mock http requests made using fetch diff --git a/docs/v5/api.md b/docs/v5/api.md deleted file mode 100644 index a948126f..00000000 --- a/docs/v5/api.md +++ /dev/null @@ -1,147 +0,0 @@ -- [Docs for latest version](/fetch-mock) -- [Introduction](/fetch-mock/v5) -- [Quickstart](/fetch-mock/v5/quickstart) -- [Installation and usage](/fetch-mock/v5/installation) -- API documentation -- [Troubleshooting](/fetch-mock/v5/troubleshooting) -- [Examples](/fetch-mock/v5/examples) - -# V5 API Documentation - -- [V4 - V5 upgrade guide](/fetch-mock/v5/v4-v5-upgrade) -- [V4 docs](https://github.com/wheresrhys/fetch-mock/blob/95d79052efffef5c80b3d87d5050392293e1bfaa/README.md) - -## Mocking calls to `fetch` - -#### `mock(matcher, response, options)` or `mock(options)` - -Replaces `fetch()` with a stub which records its calls, grouped by route, and optionally returns a mocked `Response` object or passes the call through to `fetch()`. Calls to `.mock()` can be chained. _Note that once mocked, `fetch` will error on any unmatched calls. Use `.spy()` or `.catch()` to handle unmocked calls more gracefully_ - -- `matcher`: Condition for selecting which requests to mock Accepts any of the following - - `string`: Either - - an exact url to match e.g. 'http://www.site.com/page.html' - - '\*' to match any url - - `begin:http://www.site.com/` to match urls beginning with a string - - `end:.jpg` to match urls ending with a string - - `glob:http://*.*` to match glob patterns - - `express:/user/:user` to match [express style paths](https://www.npmjs.com/package/path-to-regexp) - - [deprecated] if the string begins with a `^`, the string following the `^` must begin the url e.g. '^http://www.site.com' would match 'http://www.site.com' or 'http://www.site.com/page.html' - - `RegExp`: A regular expression to test the url against - - `Function(url, opts)`: A function (returning a Boolean) that is passed the url and opts `fetch()` is called with (or, if `fetch()` was called with one, the `Request` instance) -- `response`: Configures the http response returned by the mock. Can take any of the following values (or be a `Promise` for any of them, enabling full control when testing race conditions etc.) - - `Response`: A `Response` instance - will be used unaltered - - `number`: Creates a response with this status - - `string`: Creates a 200 response with the string as the response body - - `object`: As long as the object does not contain any of the properties below it is converted into a json string and returned as the body of a 200 response. If any of the properties below are defined it is used to configure a `Response` object - - `body`: Set the response body (`string` or `object`) - - `status`: Set the response status (default `200`) - - `headers`: Set the response headers. (`object`) - - `throws`: If this property is present then a `Promise` rejected with the value of `throws` is returned - - `sendAsJson`: This property determines whether or not the request body should be JSON.stringified before being sent (defaults to true). - - `includeContentLength`: Set this property to true to automatically add the `content-length` header (defaults to false). - - `Function(url, opts)`: A function that is passed the url and opts `fetch()` is called with and that returns any of the responses listed above (or a `Promise` for any of them) -- `options`: A configuration object with all/additional properties to define a route to mock - - `name`: A unique string naming the route. Used to subsequently retrieve references to the calls, grouped by name. If not specified defaults to `matcher.toString()` _Note: If a non-unique name is provided no error will be thrown (because names are optional, so auto-generated ones may legitimately clash)_ - - `method`: http method to match - - `headers`: key/value map of headers to match - - `matcher`: as specified above - - `response`: as specified above - - `__redirectUrl`: _experimental_ the url the response should be from (to imitate followed redirects - will set `redirected: true` on the response) - - `times`: An integer, `n`, limiting the number of times the matcher can be used. If the route has already been called `n` times the route will be ignored and the call to `fetch()` will fall through to be handled by any other routes defined (which may eventually result in an error if nothing matches it) - -#### `once()` - -Shorthand for `mock()` which limits to being called one time only. (see `times` option above) - -#### `get()`, `post()`, `put()`, `delete()`, `head()`, `patch()` - -Shorthands for `mock()` restricted to a particular method _Tip: if you use some other method a lot you can easily define your own shorthands e.g.:_ - -``` -fetchMock.purge = function (matcher, response, options) { - return this.mock(matcher, response, Object.assign({}, options, {method: 'PURGE'})); -} -``` - -#### `getOnce()`, `postOnce()`, `putOnce()`, `deleteOnce()`, `headOnce()`, `patchOnce()` - -Shorthands for `mock()` restricted to a particular method and that can only be called one time only - -#### `catch(response)` - -This is used to define how to respond to calls to fetch that don't match any of the defined mocks. It accepts the same types of response as a normal call to `.mock(matcher, response)`. It can also take an arbitrary function to completely customise behaviour of unmatched calls. It is chainable and can be called before or after other calls to `.mock()`. If `.catch()` is called without any parameters then every unmatched call will receive a `200` response e.g. - -``` -fetchMock - .mock('http://my-api.com', 200) - .catch(503) -``` - -#### `spy()` - -Similar to `catch()`, this records the call history of unmatched calls, but instead of responding with a stubbed response, the request is passed through to native `fetch()` and is allowed to communicate over the network. - -#### `sandbox(Promise)` _experimental_ - -This returns a drop-in mock for fetch which can be passed to other mocking libraries. It implements the full fetch-mock api and maintains its own state independent of other instances, so tests can be run in parallel. e.g. - -``` - fetchMock.sandbox().mock('http://domain.com', 200) -``` - -`sandbox()` can optionally be passed a custom promise implementation. If not provided, the `Promise` global is used. - -#### `flush()` - -Returns a promise that resolves once all fetches handled by fetch-mock have resolved. Useful for testing code that uses `fetch` but doesn't return a promise. - -#### `restore()` - -Chainable method that restores `fetch()` to its unstubbed state and clears all data recorded for its calls. - -#### `reset()` - -Chainable method that clears all data recorded for `fetch()`'s calls - -_Note that `restore()` and `reset()` are both bound to fetchMock, and can be used directly as callbacks e.g. `afterEach(fetchMock.restore)` will work just fine. There is no need for `afterEach(function () {fetchMock.restore()})`_ - -## Analysing how `fetch()` has been called - -**For the methods below `matcherName`, if given, should be either the name of a route (see advanced usage below) or equal to `matcher.toString()` for any unnamed route. You _can_ pass in the original regex or function used as a matcher, but they will be converted to strings and used to look up values in fetch-mock's internal maps of calls, rather than used as regexes or functions** - -#### `called(matcherName)` - -Returns a Boolean indicating whether fetch was called and a route was matched. If `matcherName` is specified it only returns `true` if that particular route was matched. - -#### `done(matcherName)` - -Returns a Boolean indicating whether fetch was called the expected number of times (or at least once if the route defines no expectation is set for the route). If no `matcherName` is passed it returns `true` if every route has been called the number of expected times. - -#### `calls(matcherName)` - -Returns an object `{matched: [], unmatched: []}` containing arrays of all calls to fetch, grouped by whether fetch-mock matched them or not. If `matcherName` is specified then only calls to fetch matching that route are returned. - -#### `lastCall(matcherName)` - -Returns the arguments for the last matched call to fetch - -#### `lastUrl(matcherName)` - -Returns the url for the last matched call to fetch - -#### `lastOptions(matcherName)` - -Returns the options for the last matched call to fetch - -## Utilities - -#### `configure(opts)` - -Set some global config options, which include - -- `sendAsJson` [default `true`] - by default fetchMock will convert objects to JSON before sending. This is overrideable from each call but for some scenarios e.g. when dealing with a lot of array buffers, it can be useful to default to `false` -- `includeContentLength` [default `false`]: When set to true this will make fetchMock automatically add the `content-length` header. This is especially useful when combined with `sendAsJson` because then fetchMock does the conversion to JSON for you and knows the resulting length so you don’t have to compute this yourself by basically doing the same conversion to JSON. - -#### `setImplementations(opts)` - -When using non global fetch (e.g. a ponyfill) or an alternative Promise implementation, this will configure fetch-mock to use your chosen implementations. `opts` is an object with one or more of the following properties: `Headers`,`Request`,`Response`,`Promise`. Note that `setImplementations(require('fetch-ponyfill')())` will configure fetch-mock to use all of fetch-ponyfill's classes. `setImplementations()` shoul, in most cases, be called only once, before any tests run. diff --git a/docs/v5/examples.md b/docs/v5/examples.md deleted file mode 100644 index c51a5b7f..00000000 --- a/docs/v5/examples.md +++ /dev/null @@ -1,11 +0,0 @@ -- [Docs for latest version](/fetch-mock) -- [Introduction](/fetch-mock/v5) -- [Quickstart](/fetch-mock/v5/quickstart) -- [Installation and usage](/fetch-mock/v5/installation) -- [API documentation](/fetch-mock/v5/api) -- [Troubleshooting](/fetch-mock/v5/troubleshooting) -- Examples - -# V5 Examples - -//todo diff --git a/docs/v5/index.md b/docs/v5/index.md deleted file mode 100644 index 5c44d16a..00000000 --- a/docs/v5/index.md +++ /dev/null @@ -1,16 +0,0 @@ -# Version 5 docs - -- [Docs for latest version](/fetch-mock) - -fetch-mock allows mocking http requests made using fetch, or any one of the many libraries imitating its api such as [isomorphic-fetch](https://www.npmjs.com/package/isomorphic-fetch), [node-fetch](https://www.npmjs.com/package/node-fetch) and [fetch-ponyfill](https://www.npmjs.com/package/fetch-ponyfill). - -The library will run in most JavaScript environments, including nodejs, web workers and service workers, and any browser that either supports fetch natively or that can have a fetch polyfill/ponyfill installed. - -As well as shorthand methods for the simplest use cases, it offers a flexible API for customising all aspects of mocking behaviour. - -- Introduction -- [Quickstart](/fetch-mock/v5/quickstart) -- [Installation and usage](/fetch-mock/v5/installation) -- [API documentation](/fetch-mock/v5/api) -- [Troubleshooting](/fetch-mock/v5/troubleshooting) -- [Examples](/fetch-mock/v5/examples) diff --git a/docs/v5/installation.md b/docs/v5/installation.md deleted file mode 100644 index bae025f1..00000000 --- a/docs/v5/installation.md +++ /dev/null @@ -1,56 +0,0 @@ -- [Docs for latest version](/fetch-mock) -- [Introduction](/fetch-mock/v5) -- [Quickstart](/fetch-mock/v5/quickstart) -- Installation and usage -- [API documentation](/fetch-mock/v5/api) -- [Troubleshooting](/fetch-mock/v5/troubleshooting) -- [Examples](/fetch-mock/v5/examples) - -# V5 Installation - -Install fetch-mock using `npm install --save-dev fetch-mock` - -In most environments use `const fetchMock = require('fetch-mock')` to use it in your code. Some exceptions include: - -- If your client-side code or tests do not use a loader that respects the browser field of `package.json` use `require('fetch-mock/es5/client')`. -- If you need to use fetch-mock without commonjs, you can include the precompiled `node_modules/fetch-mock/es5/client-browserified.js` in a script tag. This loads fetch-mock into the `fetchMock` global variable. -- For server side tests running in nodejs 0.12 or lower use `require('fetch-mock/es5/server')` - -## Global fetch - -By default fetch-mock assumes `fetch` is a global so once you've required fetch-mock refer to the quickstart and api docs. - -### Polyfilling fetch - -Many older browsers will require polyfilling the `fetch` global - -- In nodejs `require('isomorphic-fetch')` before any of your tests. -- In the browser `require('isomorphic-fetch')` can also be used, but it may be easier to `npm install whatwg-fetch` (the module isomorphic-fetch is built around) and load `./node_modules/whatwg-fetch/fetch.js` directly into the page, either in a script tag or by referencing in your test runner config. -- When using karma-webpack it's best not to use the `webpack.ProvidePlugin` for this. Instead just add `node_modules/whatwg-fetch/fetch.js` to your list of files to include, or require it directly into your tests before requiring fetch-mock. - -## Non-global fetch - -When using a non-global fetch implementation (such as node-fetch or fetch-ponyfill) use the `sandbox()` method to return a function that can be used as a replacement for fetch, and be passed into your source code using your choice of mocking library. The function returned by `sandbox()` supports the full fetch-mock api so once generated it can be worked with as if it were the original `fetch-mock` object, e.g. - -``` -const fetchMock = require('fetch-mock'); -const myMock = fetchMock.sandbox().mock('/home', 200); -// pass myMock in to your application code, instead of fetch, run it, then... -expect(myMock.called('/home')).to.be.true; -``` - -## References to Request, Response, Helpers and Promise - -If you're using a non-global fetch implementation, or wish to use a custom Promise implementation, you may need to tell fetch-mock to use these when matching requests and returning responses. Do this using the `.setImplementations()` method. e.g. - -``` -fetchMock.setImplementations({Promise: require('Bluebird').promise}) -``` - -In particular, when using fetch-ponyfill - -``` -setImplementations(require('fetch-ponyfill')())` -``` - -will set all the internal references to point at fetch-ponyfill's classes. diff --git a/docs/v5/quickstart.md b/docs/v5/quickstart.md deleted file mode 100644 index 2267cbe4..00000000 --- a/docs/v5/quickstart.md +++ /dev/null @@ -1,58 +0,0 @@ -- [Docs for latest version](/fetch-mock) -- [Introduction](/fetch-mock/v5) -- Quickstart -- [Installation and usage](/fetch-mock/v5/installation) -- [API documentation](/fetch-mock/v5/api) -- [Troubleshooting](/fetch-mock/v5/troubleshooting) -- [Examples](/fetch-mock/v5/examples) - -# V5 Quickstart - -## Setting up your mock - -The commonest use case is `fetchMock.mock(matcher, response)`, where `matcher` is a string or regex to match and `response` is a statusCode, string or object literal. You can also use `fetchMock.once(url ...)` to limit to a single call or `fetchMock.get()`, `fetchMock.post()` etc. to limit to a method. All these methods are chainable so you can easily define several mocks in a single test. - -## Analysing calls to your mock - -`fetchMock.called(matcher)` reports if any calls matched your mock (or leave `matcher` out if you just want to check `fetch` was called at all). `fetchMock.lastCall()`, `fetchMock.lastUrl()` or `fetchMock.lastOptions()` give you access to the parameters last passed in to `fetch`. `fetchMock.done()` will tell you if `fetch` was called the expected number of times. - -## Tearing down your mock - -`fetchMock.reset()` resets the call history. `fetchMock.restore()` will also restore `fetch()` to its native implementation - -## Example - -Example with node: suppose we have a file `make-request.js` with a function that calls `fetch`: - -```js -module.exports = function makeRequest() { - return fetch('http://httpbin.org/get').then(function(response) { - return response.json(); - }); -}; -``` - -We can use fetch-mock to mock `fetch`. In `mocked.js`: - -```js -var fetchMock = require('fetch-mock'); -var makeRequest = require('./make-request'); - -// Mock the fetch() global to always return the same value for GET -// requests to all URLs. -fetchMock.get('*', { hello: 'world' }); - -makeRequest().then(function(data) { - console.log('got data', data); -}); - -// Unmock. -fetchMock.restore(); -``` - -Result: - -```bash -$ node mocked.js -'got data' { hello: 'world' } -``` diff --git a/docs/v5/troubleshooting.md b/docs/v5/troubleshooting.md deleted file mode 100644 index 0d15e997..00000000 --- a/docs/v5/troubleshooting.md +++ /dev/null @@ -1,41 +0,0 @@ -- [Docs for latest version](/fetch-mock) -- [Introduction](/fetch-mock/v5) -- [Quickstart](/fetch-mock/v5/quickstart) -- [Installation and usage](/fetch-mock/v5/installation) -- [API documentation](/fetch-mock/v5/api) -- Troubleshooting -- [Examples](/fetch-mock/v5/examples) - -# V5 Troubleshooting - -### `fetch` is assigned to a local variable, not a global - -First of all, consider whether you could just use `fetch` as a global. Here are 3 reasons why this is a good idea: - -- The `fetch` standard defines it as a global (and in some cases it won't work unless bound to `window`), so to write isomorphic code it's probably best to stick to this pattern -- [`isomorphic-fetch`](https://www.npmjs.com/package/isomorphic-fetch) takes care of installing it as a global in nodejs or the browser, so there's no effort on your part to do so. -- `fetch-mock` is primarily designed to work with `fetch` as a global and your experience of using it will be far more straightforward if you follow this pattern - -Still not convinced? - -In that case `fetchMock.sandbox()` can be used to generate a function which you can pass in to a mock loading library such as [`mockery`](https://www.npmjs.com/package/mockery) instead of `fetch` - -### `fetch` doesn't seem to be getting mocked? - -- If using a mock loading library such as `mockery`, are you requiring the module you're testing after registering `fetch-mock` with the mock loader? You probably should be ([Example incorrect usage](https://github.com/wheresrhys/fetch-mock/issues/70)). If you're using ES6 `import` it may not be possible to do this without reverting to using `require()` sometimes. -- If using `isomorphic-fetch` in your source, are you assigning it to a `fetch` variable? You _shouldn't_ be i.e. - - `import 'isomorphic-fetch'`, not `import fetch from 'isomorphic-fetch'` - - `require('isomorphic-fetch')`, not `const fetch = require('isomorphic-fetch')` - -### Environment doesn't support requiring fetch-mock? - -- If your client-side code or tests do not use a loader that respects the browser field of package.json use `require('fetch-mock/es5/client')`. -- If you need to use fetch-mock without commonjs, you can include the precompiled `node_modules/fetch-mock/es5/client-browserified.js` in a script tag. This loads fetch-mock into the `fetchMock` global variable. -- For server side tests running in nodejs 0.12 or lower use `require('fetch-mock/es5/server')` - -### Matching `Request` objects in node fails - -In node, if using npm at a version less than 2 the `Request` constructor used by `fetch-mock` won't necessarily be the same as the one used by `node-fetch`. To fix this either: - -- upgrade to npm@3 -- use `fetchMock.setImplementations({Request: myRequest})`, where `myRequest` is a reference to the Request constructor used in your application code. diff --git a/docs/v5/v4-v5-upgrade.md b/docs/v5/v4-v5-upgrade.md deleted file mode 100644 index 97f90c6b..00000000 --- a/docs/v5/v4-v5-upgrade.md +++ /dev/null @@ -1,65 +0,0 @@ -# Upgrading from v4 to v5 - -## Handling unmatched calls (`greed`) - -In previous versions fetch-mock had a `greed` property, set to - -- `good` - unmatched calls respond with a 200 -- `bad` - unmatched calls error -- `none` - allow unmatched calls to use native `fetch` and the network - -This has now been replaced by a `.catch()` method which accepts the same types of response as a normal call to `.mock(matcher, response)`. It can also take an arbitrary function to completely customise behaviour of unmatched calls. It is chainable and can be called before or after other calls to `.mock()`. The api to check for unmatched calls remains unchanged. e.g. - -```javascript -fetchMock.mock({ matcher: 'http://it.at.there', response: 404, greed: 'good' }); -// changes to -fetchMock.mock('http://it.at.there', 404).catch(200); -``` - -> Can I still let calls to `fetch` fall through to the network? - -**No**. In general it's bad practice to have your tests dependent on the network, and the previous default behaviour didn't do enough to discourage this. -However, if there's demand for the feature to be added in it shouldn't be too difficult. I just didn't want to add the feature unless people are unhappy with the upgrade on offer - -## Matching calls on methods -The previous signature of `.mock(matcher, method, response)` has changed to `mock(matcher, response, {method})` - _sorry_ :grimace:, but the previous API overloaded parameters and made it difficult to add new functionality (e.g. it's blocked rolling out a 'mock n times' feature for a while). - -But there is some good news, in the form of `get()`, `post()`, `put()`, `delete()`, `head()` shorthands. - -e.g. - -```javascript -fetchMock.mock('http://it.at.there', 'GET', 200); -// changes to -fetchMock.mock('http://it.at.there', 200, { method: 'GET' }); -// or -fetchMock.get('http://it.at.there', 200); -``` - -## Complex configuration of multiple routes - -Previously several routes could be configured at once by passing an array of route configs in to `.mock()`. This is no longer supported as the chainability of `.mock()` means setting up multiple mocks is easy. However, to continue support for arrays of routes, ` .mock()`` is bound to `fetchMock`, so the following can be done - -```javascript -arrayOfRoutes.map(fetchMock.mock); -``` - -### Using non-global fetch - -It's already extensively documented in the README why it's a bad idea to do so, and the `useNonGlobalFetch` method has finally been removed. Since a [bugfix](https://github.com/wheresrhys/fetch-mock/pull/102) a few months ago it should no longer be necessary even when using a non-global fetch. `getMock()` has also been removed, and now `fetchMock.fetchMock` can be used directly as a mock for `fetch`. - -### restoring/resetting before continuing to mock (`reMock()`) - -Previously the `reMock()` method provided a shorthand for `restore()` followed by `mock()`. Now both `.reset()` and `.restore()` are chainable, so - -```javascript -fetchMock.reMock('http://it.at.there', 404); -//changes to -fetchMock.restore().mock('http://it.at.there', 404); -``` - -## New features - -- use `fetchMock.configure({sendAsJson: false})` to make it easier to work with Buffers -- pass a native `Response` object directly into the second paramter of `.mock()` -- use '\*' to match any url diff --git a/docs/v6-v7-upgrade.md b/docs/v6-v7-upgrade-guide.md similarity index 99% rename from docs/v6-v7-upgrade.md rename to docs/v6-v7-upgrade-guide.md index 7d76924f..e3faa3f9 100644 --- a/docs/v6-v7-upgrade.md +++ b/docs/v6-v7-upgrade-guide.md @@ -88,4 +88,3 @@ Most of the methods below accept two parameters, `(filter, options)` - If `filter` is equal to `matcher` or `matcher.toString()` for a route, all calls handled by that route are returned - `filter` is executed using the same execution plan as matchers used in `.mock()`. Any calls matched by it will be returned. If `options` is also passed this is used in a similar way to the options used by `mock()`. Alternatively, `options` can be a string specifying a `method` to filter by - diff --git a/docs/v6/_config.yml b/docs/v6/_config.yml deleted file mode 100644 index b7e0752a..00000000 --- a/docs/v6/_config.yml +++ /dev/null @@ -1,4 +0,0 @@ -markdown: kramdown -theme: jekyll-theme-slate -title: fetch-mock -description: Mock http requests made using fetch diff --git a/docs/v6/api.md b/docs/v6/api.md deleted file mode 100644 index ea953074..00000000 --- a/docs/v6/api.md +++ /dev/null @@ -1,158 +0,0 @@ -- [Introduction](/fetch-mock) -- [Quickstart](/fetch-mock/quickstart) -- [Installation and usage](/fetch-mock/installation) -- API documentation -- [Troubleshooting](/fetch-mock/troubleshooting) -- [Examples](/fetch-mock/examples) - -# API Documentation - -- [V5 - V6 upgrade guide](/fetch-mock/v5-v6-upgrade) -- [V5 docs](/fetch-mock/v5) - -## Mocking calls to `fetch` - -#### `mock(matcher, response, options)` or `mock(options)` - -Replaces `fetch` with a stub which records its calls, grouped by route, and optionally returns a mocked `Response` object or passes the call through to `fetch()`. Calls to `.mock()` can be chained. _Note that once mocked, `fetch` will error on any unmatched calls. Use `.spy()` or `.catch()` to handle unmocked calls more gracefully_ - -- `matcher`: Condition for selecting which requests to mock. (For matching based on headers, query strings or other `fetch` options see the `options` parameter documented below). Accepts any of the following: - - - `string`: Either - - an exact url to match e.g. 'http://www.site.com/page.html' - - `*` to match any url - - `begin:http://www.site.com/` to match urls beginning with a string - - `end:.jpg` to match urls ending with a string - - `glob:http://*.*` to match glob patterns - - `express:/user/:user` to match [express style paths](https://www.npmjs.com/package/path-to-regexp) - - `RegExp`: A regular expression to test the url against - - `Function(url, opts)`: A function (returning a Boolean) that is passed the url and opts `fetch()` is called with (or, if `fetch()` was called with one, the `Request` instance) - -- `response`: Configures the http response returned by the mock. Can take any of the following values (or be a `Promise` for any of them, enabling full control when testing race conditions etc.) - - `Response`: A `Response` instance - will be used unaltered - - `number`: Creates a response with this status - - `string`: Creates a 200 response with the string as the response body - - `configObject` If an object _does not contain_ any properties aside from those listed below it is treated as config to build a `Response` - - `body`: Set the response body (`string` or `object`) - - `status`: Set the response status (default `200`) - - `headers`: Set the response headers. (`object`) - - `throws`: If this property is present then a the value of `throws` is thrown - - `sendAsJson`: This property determines whether or not the request body should be converted to `JSON` before being sent (defaults to `true`). - - `includeContentLength`: Set this property to true to automatically add the `content-length` header (defaults to `true`). - - `redirectUrl`: _experimental_ the url the response should be from (to imitate followed redirects - will set `redirected: true` on the response) - - `object`: All objects that do not meet the criteria above are converted to `JSON` and returned as the body of a 200 response. - - `Function(url, opts)`: A function that is passed the url and opts `fetch()` is called with and that returns any of the responses listed above (or a `Promise` for any of them) -- `options`: A configuration object with all/additional properties to define a route to mock - - `name`: A unique string naming the route. Used to subsequently retrieve references to the calls, grouped by name. Defaults to `matcher.toString()` - - `method`: http method to match - - `headers`: key/value map of headers to match - - `query`: key/value map of query strings to match, in any order - - `matcher`: as specified above - - `response`: as specified above - - `repeat`: An integer, `n`, limiting the number of times the matcher can be used. If the route has already been called `n` times the route will be ignored and the call to `fetch()` will fall through to be handled by any other routes defined (which may eventually result in an error if nothing matches it) - - `overwriteRoutes`: If the route you're adding clashes with an existing route, setting `true` here will overwrite the clashing route, `false` will add another route to the stack which will be used as a fallback (useful when using the `repeat` option). Adding a clashing route without specifying this option will throw an error. It can also be set as a global option (see the **Config** section below) - -#### `sandbox()` - -This returns a drop-in mock for fetch which can be passed to other mocking libraries. It implements the full fetch-mock api and maintains its own state independent of other instances, so tests can be run in parallel. e.g. - -#### `once()` - -Shorthand for `mock()` which limits to being called one time only. (see `repeat` option above) - -#### `get()`, `post()`, `put()`, `delete()`, `head()`, `patch()` - -Shorthands for `mock()` restricted to a particular method _Tip: if you use some other method a lot you can easily define your own shorthands e.g.:_ - -``` -fetchMock.purge = function (matcher, response, options) { - return this.mock(matcher, response, Object.assign({}, options, {method: 'PURGE'})); -} -``` - -#### `getOnce()`, `postOnce()`, `putOnce()`, `deleteOnce()`, `headOnce()`, `patchOnce()` - -Shorthands for `mock()` restricted to a particular method and that will only respond once - -#### `catch(response)` - -This is used to define how to respond to calls to fetch that don't match any of the defined mocks. It accepts the same types of response as a normal call to `.mock()`. It can also take an arbitrary function to completely customise behaviour of unmatched calls. It is chainable and can be called before or after other calls to `.mock()`. If `.catch()` is called without any parameters then every unmatched call will receive a `200` response - -#### `spy()` - -Similar to `catch()`, this records the call history of unmatched calls, but instead of responding with a stubbed response, the request is passed through to native `fetch()` and is allowed to communicate over the network. - -To use `.spy()` on a sandboxed `fetchMock`, `fetchMock.config.fetch` must be set to a reference to the `fetch` implementation you use in your code. - -``` - fetchMock.sandbox().mock('http://domain.com', 200) -``` - -Existing sandboxed `fetchMock`s can also have `.sandbox()` called on them, thus building mocks that inherit some settings from a parent mock - -#### `restore()` - -Chainable method that restores `fetch()` to its unstubbed state and clears all data recorded for its calls. - -#### `reset()` - -Chainable method that clears all data recorded for `fetch()`'s calls. _It will not restore fetch to its default implementation_ - -_Note that `restore()` and `reset()` are both bound to fetchMock, and can be used directly as callbacks e.g. `afterEach(fetchMock.restore)` will work just fine. There is no need for `afterEach(function () {fetchMock.restore()})`_ - -## Inspecting how `fetch()` has been called - -### Filtering - -Most of the methods below accept two parameters, `(filter, method)` - -- `filter` Enables filtering fetch calls for the most commonly use cases. It can be: - - the name of a route - - The value of `matcher` or `matcher.toString()` for any unnamed route. You _can_ pass in the original regex or function as a matcher, but they will be converted to strings and used to look up values in fetch-mock's internal maps of calls, _not_ used as regexes or functions executed on teh url - - If `filter` is a string, and it does not match any routes, it is asumed the string is a url, and calls to `fetch` made with that url are returned - - `true` for matched calls only - - `false` for unmatched calls only - - `undefined` for all calls to fetch -- `method` A http method to filter by - -#### `called(filter, method)` - -Returns a Boolean indicating whether fetch was called and a route was matched. If `filter` is specified it only returns `true` if that particular route was matched. - -#### `done(filter, method)` - -Returns a Boolean indicating whether fetch was called the expected number of times (or at least once if the route defines no expectation is set for the route). _Unlike the other methods for inspecting calls, unmatched calls are irrelevant_. Therefore, if no `filter` is passed, `done()` returns `true` if every route has been called the number of expected times. - -#### `calls(filter, method)` - -Returns an array of all calls to fetch matchingthe given filters. Each call is returned as an array of length 2. - -#### `lastCall(filter, method)` - -Returns the arguments for the last matched call to fetch - -#### `lastUrl(filter, method)` - -Returns the url for the last matched call to fetch. When `fetch` was last called using a `Request` instance, the url will be extracted from this - -#### `lastOptions(filter, method)` - -Returns the options for the last matched call to fetch. When `fetch` was last called using a `Request` instance, the entire `Request` instance will be returned - -#### `flush()` - -Returns a `Promise` that resolves once all fetches handled by fetch-mock have resolved. Useful for testing code that uses `fetch` but doesn't return a promise. - -## Config - -On either the global or sandboxed `fetchMock` instances, the following config options can be set by setting properties on `fetchMock.config`. Many can also be set on individual calls to `.mock()`. - -- `sendAsJson` [default `true`] - by default fetchMock will convert objects to JSON before sending. This is overrideable from each call but for some scenarios e.g. when dealing with a lot of array buffers, it can be useful to default to `false` -- `includeContentLength` [default `true`]: When set to true this will make fetchMock automatically add the `content-length` header. This is especially useful when combined with `sendAsJson` because then fetchMock does the conversion to JSON for you and knows the resulting length so you don’t have to compute this yourself by basically doing the same conversion to JSON. -- `fallbackToNetwork` [default `false`] If true then unmatched calls will transparently fall through to the network, if false an error will be thrown. If set to `always`, all calls will fall through, effectively disabling fetch-mock. to Within individual tests `.catch()` and `spy()` can be used for fine-grained control of this -- `overwriteRoutes`: If a new route clashes with an existing route, setting `true` here will overwrite the clashing route, `false` will add another route to the stack which will be used as a fallback (useful when using the `repeat` option). Adding a clashing route without specifying this option will throw an error. -- `warnOnFallback` [default `true`] If true then any unmatched calls that are caught by a fallback handler (either the network or a custom function set using `catch()`) will emit warnings -- `Headers`,`Request`,`Response`,`Promise`, `fetch` - When using non standard fetch (e.g. a ponyfill, or aversion of `node-fetch` other than the one bundled with `fetch-mock`) or an alternative Promise implementation, this will configure fetch-mock to use your chosen implementations. - -Note that `Object.assign(fetchMock.config, require('fetch-ponyfill')())` will configure fetch-mock to use all of fetch-ponyfill's classes. In most cases, it should only be necessary to set this once before any tests run. diff --git a/docs/v6/examples.md b/docs/v6/examples.md deleted file mode 100644 index c4dff841..00000000 --- a/docs/v6/examples.md +++ /dev/null @@ -1,10 +0,0 @@ -- [Introduction](/fetch-mock) -- [Quickstart](/fetch-mock/quickstart) -- [Installation and usage ](/fetch-mock/installation) -- [API documentation](/fetch-mock/api) -- [Troubleshooting](/fetch-mock/troubleshooting) -- Examples - -# Examples - -//todo diff --git a/docs/v6/index.md b/docs/v6/index.md deleted file mode 100644 index 4ce164e1..00000000 --- a/docs/v6/index.md +++ /dev/null @@ -1,22 +0,0 @@ -fetch-mock allows mocking http requests made using fetch, or any one of the many libraries imitating its api such as [isomorphic-fetch](https://www.npmjs.com/package/isomorphic-fetch), [node-fetch](https://www.npmjs.com/package/node-fetch) and [fetch-ponyfill](https://www.npmjs.com/package/fetch-ponyfill). - -The library will run in most JavaScript environments, including nodejs, web workers and service workers, and any browser that either supports fetch natively or that can have a fetch polyfill/ponyfill installed. - -As well as shorthand methods for the simplest use cases, it offers a flexible API for customising all aspects of mocking behaviour. - -**Uses `async / await` - for older node versions use v5, or require the transpiled version: require('fetch-mock/es5/server')** - -
      - I devote a lot of time to maintaining fetch-mock for free. I don't ask for payment, but am raising money for a refugee charity - please consider donating -
      - -## These docs are for v6 - -- [v5 docs](/fetch-mock/v5) -- [V5 - V6 upgrade guide](/fetch-mock/v5-v6-upgrade) -- Introduction -- [Quickstart](/fetch-mock/quickstart) -- [Installation and usage ](/fetch-mock/installation) -- [API documentation](/fetch-mock/api) -- [Troubleshooting](/fetch-mock/troubleshooting) -- [Examples](/fetch-mock/examples) diff --git a/docs/v6/installation.md b/docs/v6/installation.md deleted file mode 100644 index 107bab77..00000000 --- a/docs/v6/installation.md +++ /dev/null @@ -1,58 +0,0 @@ -- [Introduction](/fetch-mock) -- [Quickstart](/fetch-mock/quickstart) -- Installation and usage -- [API documentation](/fetch-mock/api) -- [Troubleshooting](/fetch-mock/troubleshooting) -- [Examples](/fetch-mock/examples) - -# Installation - -Install fetch-mock using `npm install --save-dev fetch-mock` - -In most environments use `const fetchMock = require('fetch-mock')` to use it in your code. Some exceptions include: - -- If your client-side code or tests do not use a loader that respects the browser field of `package.json` use `require('fetch-mock/es5/client')`. -- If you need to use fetch-mock without commonjs, you can include the precompiled `node_modules/fetch-mock/es5/client-bundle.js` in a script tag. This loads fetch-mock into the `fetchMock` global variable. -- For server side tests running in nodejs 6 or lower use `require('fetch-mock/es5/server')`. You will also need to `npm i -D babel-polyfill` - -## Global fetch - -By default fetch-mock assumes `fetch` is a global so once you've required fetch-mock refer to the quickstart and api docs. - -### Polyfilling fetch - -Many older browsers will require polyfilling the `fetch` global - -- In nodejs `require('isomorphic-fetch')` before any of your tests. -- In the browser `require('isomorphic-fetch')` can also be used, but it may be easier to `npm install whatwg-fetch` (the module isomorphic-fetch is built around) and load `./node_modules/whatwg-fetch/fetch.js` directly into the page, either in a script tag or by referencing in your test runner config. -- When using karma-webpack it's best not to use the `webpack.ProvidePlugin` for this. Instead just add `node_modules/whatwg-fetch/fetch.js` to your list of files to include, or require it directly into your tests before requiring fetch-mock. - -## Non-global fetch - -When using a non-global fetch implementation (such as node-fetch or fetch-ponyfill) use the `sandbox()` method to return a function that can be used as a replacement for fetch, and be passed into your source code using your choice of mocking library. The function returned by `sandbox()` supports the full fetch-mock api so once generated it can be worked with as if it were the original `fetch-mock` object, e.g. - -``` -const fetchMock = require('fetch-mock'); -const myMock = fetchMock.sandbox().mock('/home', 200); -// pass myMock in to your application code, instead of fetch, run it, then... -expect(myMock.called('/home')).to.be.true; -``` - -## References to Request, Response, Headers, fetch and Promise - -If you're using a non-global fetch implementation, or wish to use a custom Promise implementation, you may need to tell fetch-mock to use these when matching requests and returning responses. Do this by setting these properties on `fetchMock.config`, e.g - -``` -const ponyfill = require('fetch-ponyfill')(); -fetchMock.config = Object.assign(fetchMock.config, { - Promise: require('Bluebird').promise, - Headers: ponyfill.Headers, - Request: ponyfill.Request, - Response: ponyfill.Response - fetch: ponyfill -}, -``` - -This should be done before running any tests. - -Note that when using `node-fetch`, `fetch-mock` will use the instance you already have installed so there should be no need to set any of the above (apart from `fetch`, which is required if you intend to use the `.spy()` method) diff --git a/docs/v6/quickstart.md b/docs/v6/quickstart.md deleted file mode 100644 index e4e51ed3..00000000 --- a/docs/v6/quickstart.md +++ /dev/null @@ -1,57 +0,0 @@ -- [Introduction](/fetch-mock) -- Quickstart -- [Installation and usage ](/fetch-mock/installation) -- [API documentation](/fetch-mock/api) -- [Troubleshooting](/fetch-mock/troubleshooting) -- [Examples](/fetch-mock/examples) - -# Quickstart - -## Setting up your mock - -The commonest use case is `fetchMock.mock(matcher, response)`, where `matcher` is a string or regex to match and `response` is a statusCode, string or object literal. You can also use `fetchMock.once(url ...)` to limit to a single call or `fetchMock.get()`, `fetchMock.post()` etc. to limit to a method. All these methods are chainable so you can easily define several mocks in a single test. - -## Analysing calls to your mock - -`fetchMock.called(matcher)` reports if any calls matched your mock (or leave `matcher` out if you just want to check `fetch` was called at all). `fetchMock.lastCall()`, `fetchMock.lastUrl()` or `fetchMock.lastOptions()` give you access to the parameters last passed in to `fetch`. `fetchMock.done()` will tell you if `fetch` was called the expected number of times. - -## Tearing down your mock - -`fetchMock.reset()` resets the call history. `fetchMock.restore()` will also restore `fetch()` to its native implementation - -## Example - -Example with node: suppose we have a file `make-request.js` with a function that calls `fetch`: - -```js -module.exports = function makeRequest() { - return fetch('http://httpbin.org/get').then(function(response) { - return response.json(); - }); -}; -``` - -We can use fetch-mock to mock `fetch`. In `mocked.js`: - -```js -var fetchMock = require('fetch-mock'); -var makeRequest = require('./make-request'); - -// Mock the fetch() global to always return the same value for GET -// requests to all URLs. -fetchMock.get('*', { hello: 'world' }); - -makeRequest().then(function(data) { - console.log('got data', data); -}); - -// Unmock. -fetchMock.restore(); -``` - -Result: - -```bash -$ node mocked.js -'got data' { hello: 'world' } -``` diff --git a/docs/v6/troubleshooting.md b/docs/v6/troubleshooting.md deleted file mode 100644 index 982aaf8e..00000000 --- a/docs/v6/troubleshooting.md +++ /dev/null @@ -1,40 +0,0 @@ -- [Introduction](/fetch-mock) -- [Quickstart](/fetch-mock/quickstart) -- [Installation and usage ](/fetch-mock/installation) -- [API documentation](/fetch-mock/api) -- Troubleshooting -- [Examples](/fetch-mock/examples) - -# Troubleshooting - -### `fetch` is assigned to a local variable, not a global - -First of all, consider whether you could just use `fetch` as a global. Here are 3 reasons why this is a good idea: - -- The `fetch` standard defines it as a global (and in some cases it won't work unless bound to `window`), so to write isomorphic code it's probably best to stick to this pattern -- [`isomorphic-fetch`](https://www.npmjs.com/package/isomorphic-fetch) takes care of installing it as a global in nodejs or the browser, so there's no effort on your part to do so. -- `fetch-mock` is primarily designed to work with `fetch` as a global and your experience of using it will be far more straightforward if you follow this pattern - -Still not convinced? - -In that case `fetchMock.sandbox()` can be used to generate a function which you can pass in to a mock loading library such as [`mockery`](https://www.npmjs.com/package/mockery) instead of `fetch` - -### `fetch` doesn't seem to be getting mocked? - -- If using a mock loading library such as `mockery`, are you requiring the module you're testing after registering `fetch-mock` with the mock loader? You probably should be ([Example incorrect usage](https://github.com/wheresrhys/fetch-mock/issues/70)). If you're using ES6 `import` it may not be possible to do this without reverting to using `require()` sometimes. -- If using `isomorphic-fetch` in your source, are you assigning it to a `fetch` variable? You _shouldn't_ be i.e. - - `import 'isomorphic-fetch'`, not `import fetch from 'isomorphic-fetch'` - - `require('isomorphic-fetch')`, not `const fetch = require('isomorphic-fetch')` - -### Environment doesn't support requiring fetch-mock? - -- If your client-side code or tests do not use a loader that respects the browser field of package.json use `require('fetch-mock/es5/client')`. -- If you need to use fetch-mock without commonjs, you can include the precompiled `node_modules/fetch-mock/es5/client-browserified.js` in a script tag. This loads fetch-mock into the `fetchMock` global variable. -- For server side tests running in nodejs 0.12 or lower use `require('fetch-mock/es5/server')` - -### Matching `Request` objects in node fails - -In node, if using npm at a version less than 2 the `Request` constructor used by `fetch-mock` won't necessarily be the same as the one used by `node-fetch`. To fix this either: - -- upgrade to npm@3 -- use `fetchMock.config.Request = myRequest`, where `myRequest` is a reference to the Request constructor used in your application code. diff --git a/docs/v6/v5-v6-upgrade.md b/docs/v6/v5-v6-upgrade.md deleted file mode 100644 index 32471a1f..00000000 --- a/docs/v6/v5-v6-upgrade.md +++ /dev/null @@ -1,38 +0,0 @@ -# Upgrading from V5 to V6 - -This is a long overdue refactor of the entire library. As feature requests have come in, the code and test suite had become increasingly spaghettified, and this new version is a massive improvement on the previous implementation. - -For the most common use cases, and the basic mocking and inspecting api, very little has changed. The main changes are around how fetch-mock is configured and installed, and turning a few nice new features on by default (couldn't do so in v5 as would've been a breaking change) - -# Changes - -## Configuration and installation - -- Requires `async / await` - for older node versions use v5, or require the transpiled version: `require('fetch-mock/es5/server')` -- _No change to mocking fetch as a global_ -- Uses whatever version of `node-fetch` you have already installed in your project i.e. can be used with `node-fetch` 2 -- `.sandbox()` no longer accepts a custom `Promise` implementation as a parameter -- Sandboxes can now be 'sub-classed' i.e. define some mocks on a sandbox, then call `.sandbox()` on it to create a new one inheriting all its settings -- No longer has a `setImplementations()` method. Instead, assign custom `Promise` and `fetch` helper classes directly to the `config` property of the fetch-mock instance. This may be done before or after sandboxing -- No longer has a `configure()` method. Instead set options directly on the `.config` property. See the api docs for a complete list of options - -## Routing - -- `^` is no longer a valid way of matching the beginning of strings; use `begin:` instead -- `overwriteRoutes` option allows for existing routes in a mock to be overwritten. It's also possible to define multiple routes with 'the same' matcher. Default behaviour is to error. Set to `false` to use old "buffer-like" behavior - -## Responses - -- `Content-Length` header generated by default for all responses (can be configured to not do so globally or per response.) -- Objects will be converted to `JSON` responses if they contain any properties not listed in the docs as special response config options (previous behaviour was to convert if any of the properties were present). This means that e.g. `{user: 'me', status: 'happy'}` can easily be sent as `JSON` -- `__redirectUrl` option is now named `redirectUrl` -- `times` option is now named `repeat` - -## Inspecting - -- All inspection methods now filter, in addition to the existing check against `matcher.toString()`, based on the following rules - - An exact url - - `true` for matched calls only - - `false` for unmatched calls only - - `undefined` (or no argument) includes all calls to `fetch` in order in a single array, i.e. no longer an object with `matched` and `unmatched` properties -- When `fetch` was last called with a `Request` object, `lastUrl()` and `lastOpts()` give easier access to the `url` and full `Request` object