{"id":13452565,"url":"https://github.com/FormidableLabs/yesno","last_synced_at":"2025-03-23T19:34:30.685Z","repository":{"id":33534585,"uuid":"155753261","full_name":"FormidableLabs/yesno","owner":"FormidableLabs","description":"Simple HTTP testing for NodeJS","archived":true,"fork":false,"pushed_at":"2024-02-20T16:32:43.000Z","size":1499,"stargazers_count":88,"open_issues_count":33,"forks_count":6,"subscribers_count":49,"default_branch":"main","last_synced_at":"2025-03-10T17:52:15.140Z","etag":null,"topics":["http","http-mock","mocking-utility","nodejs","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FormidableLabs.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-01T17:43:37.000Z","updated_at":"2024-04-28T22:01:03.000Z","dependencies_parsed_at":"2024-07-31T07:14:38.032Z","dependency_job_id":"3da36243-24a6-4bdd-9113-6e8b6cb7448d","html_url":"https://github.com/FormidableLabs/yesno","commit_stats":{"total_commits":87,"total_committers":12,"mean_commits":7.25,"dds":0.5862068965517242,"last_synced_commit":"341a295bdd576efa3f7ef2b7fc037494bf870c1e"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Fyesno","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Fyesno/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Fyesno/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Fyesno/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FormidableLabs","download_url":"https://codeload.github.com/FormidableLabs/yesno/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245159487,"owners_count":20570393,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http","http-mock","mocking-utility","nodejs","typescript"],"created_at":"2024-07-31T07:01:27.685Z","updated_at":"2025-03-23T19:34:30.219Z","avatar_url":"https://github.com/FormidableLabs.png","language":"TypeScript","readme":"[![YesNo — Formidable, We build the modern web](https://raw.githubusercontent.com/FormidableLabs/yesno/master/yesno-Hero.png)](https://formidable.com/open-source/)\n\n[![Build Status](https://travis-ci.com/FormidableLabs/yesno.svg?branch=main)](https://travis-ci.com/FormidableLabs/yesno)\n[![codecov](https://codecov.io/gh/FormidableLabs/yesno/branch/main/graph/badge.svg)](https://codecov.io/gh/FormidableLabs/yesno)\n[![Maintenance Status][maintenance-image]](#maintenance-status)\n\n\n\nYesNo is an HTTP testing library for NodeJS that uses [Mitm](https://github.com/moll/node-mitm) to intercept outgoing HTTP requests. YesNo provides a simple API to access, manipulate and record requests, using mocks or live services, so that you can easily define what requests should and should not be made by your app.\n\n_Note:_ YesNo is still in beta! We're actively working toward our [first major release](https://github.com/FormidableLabs/yesno/projects/1), meaning the API is subject to change. Any and all feedback is appreciated.\n\n- [Why?](#Why)\n- [Installation](#installation)\n- [Usage](#Usage)\n  - [Intercepting live requests](#intercepting-live-requests)\n  - [Mocking responses](#mocking-responses)\n  - [Recording requests](#recording-requests)\n  - [Filtering results](#filtering-results)\n  - [Restoring HTTP behavior](#restoring-http-behavior)\n- [Examples](#Examples)\n- [API](#API)\n\n## Why?\n\nNodeJS applications often need to generate HTTP requests, whether that is to orchestrate across internal microservices, integrate with third party APIs or whatever. Because the correct behavior of the app is usually dependent on _sending the correct request_ and _receiving the correct response_, it's important that our tests properly validate our HTTP requests. We can accomplish this through a mix of _spying_ and _mocking_.\n\nWhereas a naive approach would be to mock the method calls to our request library or configure our application to make requests to a test server, YesNo uses [Mitm](https://github.com/moll/node-mitm) to intercept HTTP requests at the lowest level possible in process. **This allows us to access the request that is _actually_ generated by the application and return an _actual_ response, meaning we can test the actual HTTP behavior of our application, not the behavior of our mocks.**\n\nYesNo's sole purpose is to provide an easy interface to intercepting requests and defining mocks. You are free to use your existing assertion library to validate requests.\n\n## Installation\n\n```\nnpm i --save-dev yesno-http\n```\n\n## Usage\n\n_To see our preferred usage, skip to [recording](#recording-requests)!_\n\n### Intercepting live requests\n\nTo begin intercepting requests all we need to do is to call `yesno.spy()`. Afterwards we can access any _finished_ requests we've intercepted by calling `yesno.intercepted()`. The requests still sent unmodified to its destination, and the client still receives the unmodified response - we just maintain a serialized reference.\n\n```javascript\nconst { yesno } = require('yesno-http');\nconst { expect } = require('chai');\nconst myApi = require('../src/my-api');\n\ndescribe('my-api', () =\u003e {\n it('should get users', async () =\u003e {\n   yesno.spy(); // Intercept requests\n   const users = await myApi.getUsers();\n   const intercepted = yesno.intercepted(); // Get the intercepted requests\n\n   // Intercepted requests have a standardized format\n   expect(intercepted).have.lengthOf(1);\n   expect(intercepted[0]).have.nested.property('url', 'https://api.example.com/users');\n   expect(users).to.eql(intercepted[0].response.body.users); // JSON bodies are parsed to objects\n })\n});\n```\n\nHere we assert that _only 1_ HTTP request was generated by `myApi.getUsers()` , that the request was for the _correct URL_ and that the return value is equal to the `users` property of the JSON response body. YesNo will automatically parse the body of JSON requests/responses into an object - otherwise the body will be a string (see [ISerializedHttp](#ISerializedHttp) for the serialized request format).\n\n### Mocking responses\n\nA lot of the time when unit testings we don't want our app to hit any external services, but we still want to validate its HTTP behavior. In this case we can call `yesno.mock()`, which will intercept generated HTTP requests and respond with a provided mock response.\n\n```javascript\nyesno.mock([{\n request: {\n   method: 'POST',\n   path: '/users',\n   host: 'example.com',\n   protocol: 'https'\n },\n response: {\n   headers: {\n     'x-test-header': 'fizbaz'\n   },\n   body: {\n     users: [{ username: 'foobar' }]\n   },\n   statusCode: 200\n }\n}]);\n\nconst users = await myApi.getUsers();\n\nexpect(users).to.eql(yesno.mocks()[0].response.body.users);\n```\n\nYesNo first checks to make sure the request generated by `myApi.getUser()` has the same URL as our mock, then responds with the body, status code and headers in our response.\n\nMocks also allow us to easily test the behavior of our application when it receives \"unexpected\" responses, such as non-200 HTTP status codes or error response bodies.\n\n### Recording Requests\n\nWhile mocking is useful mocks themselves are hard to maintain. When APIs changes (sometimes unexpectedly!) our mocks become stale, meaning we're testing for the wrong behavior. To solve this problem YesNo allows you to _record_ requests, saving the requests we've intercepted to a local file.\n\n```javascript\nconst recording = await yesno.recording({ filename: './get-users-yesno.json' });\nawait myApi.getUsers();\n  expect(yesno.matching(/users/).response()).to.have.property('statusCode', 200);\n\nrecording.complete();\n```\n\nThis workflow has the advantage of ensuring that our mocks closely represent the _real_ HTTP request/responses our application deals with and making it easy to refresh these mocks when an API has been updated.\n\nTo make this workflow even easier, YesNo includes a `test` method which accepts a jest or mocha style test statement and surrounds it with our record statements. Using the above as an example, we could rewrite it as:\n\n```javascript\nconst itRecorded = yesno.test({ it, dir: `${__dirname}/mocks` })\n\n// Mocks for this test will be saved to or loaded from\n// \"./mocks/get-users-yesno.json\"\nitRecorded('Get Users', async () =\u003e {\n  await myApi.getUsers();\n  expect(yesno.matching(/users/).response()).to.have.property('statusCode', 200);\n})\n```\n\nNow we skip the recording boilerplate and just write our test!\n\nIn case you need to load and generate fixtures manually, YesNo also exposes the `save` and `load` methods that `record` uses internally.\n\n### Filtering results\nOnce requests have finished we still need to assert that the requests were correct. We've already seen `yesno.intercepted()`, which returns _all_ the intercepted requests, but this is just shorthand for `yesno.matching().intercepted()`, which we can use to selectively access requests.\n\nConsider the following, where we use `yesno.matching()` to access only the intercepted user request, then assert a password was hashed.\n\n```javascript\nyesno.spy();\n\nawait myApi.complicatedAuthFlow(token); // Lots of HTTP requests!\nawait myApi.updateUser(userId, rawPassword);\n\nexpect(\n // Match only requests with this url\n yesno.matching(`https://example.com/users/${userId}`).intercepted()[0]\n).to.have.nested.property(\"request.body.password\", hash(rawPassword));\n```\n\nWe can even use this syntax to selectively redact values from the serialized requests, so that we don't persist sensitive data to our mocks. This is a common problem when auth tokens are being sent back and forth between the APIs.\n\n```javascript\nawait myApi.complicatedAuthFlow(token); // Lots of HTTP requests!\nawait myApi.updateUser(userId, rawPassword);\n\nyesno.matching(/auth/).redact(['request.headers.authorization', 'response.body.token']);\n\n\nexpect(yesno.matching(/auth/).intercepted()).to.have.nested.property(\n 'request.headers.authorization', '*****');\n\nawait yesno.save(testName, dir); // Recorded mocks are sanitized\n```\n\nThe matching method can filter on any of the properties in the serialized object. See the API documentation for more examples.\n\n### Mocking matched results\n\nMatched results can be replaced with static or dynamic mocked responses. Use the `.respond()` method on a filtered http collection to define the response.\n\n```\nyesno.matching(/get/).respond({ statusCode: 400 })\n\nyesno.matching({ request: { path: '/post' } }) .respond((request) =\u003e ({ statusCode: 401, body: request.body }))\n```\n\nResponses defined in this way take precedence over normally loaded mocks.\n\n### Ignoring matched mocks to proxy requests\n\nMatched requests can ignore the defined mocks and proxy the request to the original host. This provides mixing of live and mocked results. Use the `.ignore()` method on a filtered http collection to disable the mock.\n\nMatching requests set in this way take precedence over all defined and loaded mocks.\n\n### Restoring HTTP behavior\n\nWhen we no longer need YesNo to intercept requests we can call `yesno.restore()`. This will completely restore HTTP behavior \u0026 clear our mocks. It's advisable to run this after every test.\n\n```javascript\ndescribe('api', () =\u003e {\n beforeEach(() =\u003e yesno.spy()); // Spy on each test\n afterEach(() =\u003e yesno.restore()); // Cleanup!\n\n describe('lots of tests with lots of requests', () =\u003e { ... });\n});\n```\n\nIf you're using `yesno.test()` it'll call restore for you whenever it runs.\n\n## Examples\n\nVisit the [examples](https://github.com/FormidableLabs/yesno/tree/main/examples) directory to see sample tests written with YesNo.\n\nYou can run the tests yourselves after cloning the repo.\n\n```sh\nnpm install\nnpm run example-server # Start test server\n```\n\nThen in a separate window\n\n```sh\nnpm run example-tests\n```\n\n## API\n\nYesNo is written in [TypeScript](typescriptlang.org) and uses its type syntax where possible.\n\nTo see typedoc generated documentation, click [here](./docs/README.md).\n\n##### [`YesNo`](#YesNo)\n- [YesNo](#yesno)\n  - [Why?](#why)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Intercepting live requests](#intercepting-live-requests)\n    - [Mocking responses](#mocking-responses)\n    - [Recording Requests](#recording-requests)\n    - [Filtering results](#filtering-results)\n    - [Mocking matched results](#mocking-matched-results)\n    - [Restoring HTTP behavior](#restoring-http-behavior)\n  - [Examples](#examples)\n  - [API](#api)\n        - [`YesNo`](#yesno-1)\n        - [`FilteredHttpCollection`](#filteredhttpcollection)\n        - [`Recording`](#recording)\n        - [`ISerializedHttp`](#iserializedhttp)\n    - [`YesNo`](#yesno-2)\n        - [`yesno.spy(options?: IInterceptOptions): void`](#yesnospyoptions-iinterceptoptions-void)\n        - [`IInterceptOptions`](#iinterceptoptions)\n        - [`yesno.mock(mocks: ISerializedHttp[] | ISerializedHttpMock[], options?: IInterceptOptions): void`](#yesnomockmocks-iserializedhttp--iserializedhttpmock-options-iinterceptoptions-void)\n        - [`yesno.recording(options?: IInterceptOptions \u0026 IFileOptions): Promise\u003cRecording\u003e`](#yesnorecordingoptions-iinterceptoptions--ifileoptions-promiserecording)\n        - [`yesno.test(options: IRecordableTest): (name: string, test: () =\u003e Promise\u003cany\u003e) =\u003e void`](#yesnotestoptions-irecordabletest-name-string-test---promiseany--void)\n        - [`IRecordableTest`](#irecordabletest)\n        - [`yesno.restore(): void`](#yesnorestore-void)\n        - [`yesno.save(options: IFileOptions \u0026 ISaveOptions): Promise\u003cvoid\u003e`](#yesnosaveoptions-ifileoptions--isaveoptions-promisevoid)\n        - [`IFileOptions`](#ifileoptions)\n        - [`ISaveOptions`](#isaveoptions)\n        - [`yesno.load(options: IFileOptions): Promise\u003cISerializedHttp[]\u003e`](#yesnoloadoptions-ifileoptions-promiseiserializedhttp)\n        - [`yesno.matching(filter?: HttpFilter): FilteredHttpCollection`](#yesnomatchingfilter-httpfilter-filteredhttpcollection)\n    - [`FilteredHttpCollection`](#filteredhttpcollection-1)\n        - [`collection.mocks(): ISerializedHttp[]`](#collectionmocks-iserializedhttp)\n        - [`collection.ignore(): ISerializedHttp`](#collectionignore-iserializedhttp)\n        - [`collection.intercepted(): ISerializedHttp[]`](#collectionintercepted-iserializedhttp)\n        - [`collection.redact(property: string | string[], redactor: Redactor = () =\u003e \"*****\"): void`](#collectionredactproperty-string--string-redactor-redactor----%22%22-void)\n        - [`collection.request(): ISerializedHttp`](#collectionrequest-iserializedhttp)\n        - [`collection.respond(): ISerializedHttp`](#collectionrespond-iserializedhttp)\n        - [`collection.response(): ISerializedHttp`](#collectionresponse-iserializedhttp)\n      - [Recording](#recording-1)\n        - [`recording.complete(): Promise\u003cvoid\u003e`](#recordingcomplete-promisevoid)\n      - [ISerializedHttp](#iserializedhttp-1)\n  - [Maintenance Status](#maintenance-status)\n\n##### [`FilteredHttpCollection`](#filteredhttpcollection-1)\n- [`collection.mocks(): ISerializedHttp[]`](#collectionmocks-iserializedhttp);\n- [`collection.ignore(): ISerializedHttp`](#collectionignore-iserializedhttp);\n- [`collection.intercepted(): ISerializedHttp[]`](#collectionintercepted-iserializedhttp);\n- [`collection.redact(property: string | string[], redactor: Redactor = () =\u003e \"*****\"): void`](#collectionredactproperty-string--string-redactor-redactor-----void);\n- [`collection.request(): ISerializedHttp`](#collectionrequest-iserializedhttp);\n- [`collection.respond(): ISerializedHttp`](#collectionrespond-iserializedhttp);\n- [`collection.response(): ISerializedHttp`](#collectionresponse-iserializedhttp);\n\n##### [`Recording`](#Recording)\n- [`recording.complete(): Promise\u003cvoid\u003e`](#recordingcomplete---promisevoid)\n\n##### [`ISerializedHttp`](#link)\n\n### `YesNo`\n\nThe `yesno` instance implements all the methods of the `FilteredHttpCollection` interface.\n\n##### `yesno.spy(options?: IInterceptOptions): void`\n\nEnables intercept of requests if not already enabled.\n\n##### `IInterceptOptions`\n\n`options.ignorePorts: number[]`: _Important._ Since YesNo uses Mitm internally, by default it will intercept any sockets, HTTP or otherwise. If you need to ignore a port (eg for a database connection), provide that port number here. Normally you will run YesNo after long running connections have been established, so this won't be a problem.\n\n##### `yesno.mock(mocks: ISerializedHttp[] | ISerializedHttpMock[], options?: IInterceptOptions): void`\n\nEnables intercept of requests if not already enabled and configures YesNo to respond to all forthcoming intercepted requests with the provided `mocks`.\n\nYesNo responds to the Nth intercepted request with the Nth mock. If the HTTP method \u0026 URL of the intercepted request does not match the corresponding mock then the client request will fail.\n\nWhen YesNo cannot provide a mock for an intercept it emits an `error` event on the corresponding [`ClientRequest`](https://nodejs.org/api/http.html#http_class_http_clientrequest) instance. Most libraries will handle this by throwing an error.\n\nSee also [`IInterceptOptions`](#IInterceptOptions).\n\n##### `yesno.recording(options?: IInterceptOptions \u0026 IFileOptions): Promise\u003cRecording\u003e`\n\nBegin a new recording. Recording allow you to alternatively spy, record or mock behavior according to the value of the environment variable `YESNO_RECORDING_MODE`. The values and the accompanying behaviors of theses modes are described below.\n\n| Mode   | Value            | Description                                                                                                                 |\n| ------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------- |\n| Spy    | \"spy\"            | Intercept requests \u0026 proxy to destination. Don't save. Equivalent to `yesno.spy()`                                          |\n| Record | \"record\"         | Intercept requests \u0026 proxy to destination. Save to disk on completion. Equivalent to `yesno.spy()` \u0026 `yesno.save()`         |\n| Mock   | \"mock\" (default) | Load mocks from disks. Intercept requests \u0026 respond with mocks. Don't save. Equivalent to `yesno.mock(await yesno.load())`. |\n\n**Example**\n\n```javascript\n// Begin a recording. Load mocks if in \"mock\" mode, otherwise spy.\nconst recording = await yesno.recording({\n  filename: './get-users.json'\n})\n\n// Make our HTTP requests\nawait myApi.getUsers()\n\n// Run assertions\nexpect(yesno.matching(/users/).response()).to.have.property('statusCode', 200)\n\n// Persist intercepted requests if in \"record\" mode, otherwise no-op\nawait recording.complete()\n```\n\n##### `yesno.test(options: IRecordableTest): (name: string, test: () =\u003e Promise\u003cany\u003e) =\u003e void`\n\nA utility method for creating test definitions instrumented with `yesno.recording()`. It accepts any testing method `it` or `test` which accepts a `name` and `test` function as its arguments, along with a directory and optional prefix to use for recording fixtures.\n\n##### `IRecordableTest`\n\n`options.test: (name: string, test: () =\u003e Promise\u003cany\u003e) =\u003e any`: A test function, such as `jest.test` or `mocha.it` which accepts a name and test definition. The test may either be synchronous or return a promise.\n\n`options.it: (name: string, test: () =\u003e Promise\u003cany\u003e) =\u003e any`: Alias for `options.test`\n\n`options.dir: string`: Directory to use for recording\n\n`options.prefix?: string`: _Optional_. Prefix to use for all fixtures. Useful to prevent conflicts with similarly named tests in other files.\n\n**Example**\n\nGiven the below test written with `yesno.recording`....\n\n```javascript\nit('should get users', async () =\u003e {\n  const recording = await yesno.recording({ filename: `${__dirname}/mocks/should-get-users-yesno.json` });\n  await myApi.getUsers();\n  await recording.save()\n})\n```\n\n...we may write it more concisely with `yesno.test` as\n\n```javascript\nconst itRecorded = yesno.test({ it, dir: `${__dirname}/mocks` });\n\nitRecorded('should get users', async () =\u003e {\n  await myApi.getUsers();\n});\n```\n\nWhich removes much of the boilerplate from our test.\n\n##### `yesno.restore(): void`\n\nRestore normal HTTP functionality by disabling Mitm \u0026 restoring any defined stubs. Clears references to any stateful properties such as the defined mocks or intercepted requests.\n\nIf you're using YesNo in a test suite it's advisable to run this method after every test case.\n\n##### `yesno.save(options: IFileOptions \u0026 ISaveOptions): Promise\u003cvoid\u003e`\n\nSave serialized HTTP requests to disk. Unless records are provided directly, yesno will save the currently intercepted requests.\n\nYou may provide a `filename` in the options object _or_ use the name \u0026 directory shorthand to generate a filename from a human readable string.\n\n```javascript\nconst testName = 'should hit the api'\nyesno.save(testName, mocksDir) // =\u003e \"./test/mocks/should-hit-the-api-yesno.json\"\n```\n\nUnless providing records, this method will throw an error if there are any in flight requests to prevent users from accidentally saving before all requests have completed.\n\n##### `IFileOptions`\n\n`options.filename: string`: Full filename (JSON)\n\n##### `ISaveOptions`\n\n`options.records?: ISerializedHttp[]`: Records to save. Defaults to already intercepted requests.\n\n##### `yesno.load(options: IFileOptions): Promise\u003cISerializedHttp[]\u003e`\n\nLoad serialized HTTP requests from a local JSON file.\n\nSee [`IFileOptions`](#ifileoptions).\n\n##### `yesno.matching(filter?: HttpFilter): FilteredHttpCollection`\n\nApply a filter to subsequently access or manipulate matching mocks or intercepted requests.\n\nWe define an `HttpFilter` as: `type HttpFilter = string | RegExp | ISerializedHttpPartialDeepMatch | (serialized: ISerializedHttp) =\u003e boolean`;\n\nThe `filter` is applied to each serialized request to filter results. If the filter is...\n\n- A string: Perform an _exact_ match on URL (port optional)\n- A regular expression: Test against URL (port optional)\n- An object (`ISerializedHttpPartialDeepMatch`): Perform a deep partial comparison against the serialized request\n- A function: A callback that receives the `ISerializedHttp` object and returns a `boolean` value of `true` to indicate match.\n- `undefined`: The entire collection is returned.\n\nExamples:\n\n```javascript\nyesno.matching('https://api.example.com/users'); // Exact match on url\nyesno.matching(/example/); // Any request to Example website\nyesno.matching({ // Any POST requests to Example with status code of 500\n request: { host: 'example.com', method: 'POST' },\n response: { statusCode: 500 }\n});\nyesno.matching((serialized, i) =\u003e {\n if (i === 0) { // First request\n   return true;\n }\n\n const { request } = serialized;\n if (request.body.firstName === request.body.lastName) { // Custom logic\n   return true;\n }\n\n return false;\n});\nyesno.matching().response(); // short-cut to get the response from the one intercepted request\n```\n\n### `FilteredHttpCollection`\n\n##### `collection.mocks(): ISerializedHttp[]`\n\nReturn the mocks defined within the collection.\n\n##### `collection.ignore(): ISerializedHttp`\n\nIgnore any mocked responses for all matching requests. Matching requests will be proxied to the host.\n\nAny matching requested set in this way take precedence over all defined and loaded mocks.\n\n##### `collection.intercepted(): ISerializedHttp[]`\n\nReturn the intercepted requests defined within the collection.\n\n##### `collection.redact(property: string | string[], redactor: Redactor = () =\u003e \"*****\"): void`\n\n`property`: Property or array of properties on serialized requests to redact.\n`redactor`: Callback that receives value and property path on matching requests. Return value will be used as redacted value.\n\nRedact properties on intercepted requests within the collection. Nested properties may be indicated using `.`.\n\n**Example**\n\n```javascript\nawait myApi.getToken(apiKey)\n\n// Replace the auth values with an md5 hash\nyesno.matching(/login/).redact(\n  ['request.headers.authorization', 'response.body.token'],\n  (value, path) =\u003e md5(value)\n)\nawait yesno.save({ filename: 'redacted.json' })\n```\n\n##### `collection.request(): ISerializedHttp`\n\nReturn the request part of the _single_ matching HTTP request.\n\nThrows an error if the collection does not match _one and only one_ request.\n\n**Example**\n\n```javascript\nawait myApi.getUsers(token);\n\nexpect(yesno.matching(/users/).request()).to.have.nested.property('headers.authorization', token)\n```\n\n##### `collection.respond(): ISerializedHttp`\n\nProvide a mock response for all matching requests. Optionally provide a callback to dynamically generate a response for each request.\n\nAny matching responses defined in this way take precedence over normally loaded mocks.\n\n##### `collection.response(): ISerializedHttp`\n\nResponse corollary to `collection.request()`. Return the response part of the _single_ matching HTTP request.\n\nThrows an error if the collection does not match _one and only one_ request.\n\n#### Recording\n\n##### `recording.complete(): Promise\u003cvoid\u003e`\n\nSave the request if we're in record mode. Otherwise no-op.\n\n#### ISerializedHttp\n\n```typescript\ninterface ISerializedHttp {\n readonly __id: string;\n readonly __version: string;\n readonly __timestamp: number;\n readonly __duration: number;\n readonly request: SerializedRequest;\n readonly response: SerializedResponse;\n}\n\nexport interface SerializedResponse {\n readonly body: string | object;\n readonly headers: IncomingHttpHeaders;\n readonly statusCode: number;\n}\n\nexport interface SerializedRequest {\n readonly body?: string | object;\n readonly headers: OutgoingHttpHeaders;\n readonly host: string;\n readonly path: string;\n readonly method: string;\n readonly port: number;\n readonly query?: string;\n readonly protocol: 'http' | 'https';\n}\n```\n\n## Maintenance Status\n\nArchived: This project is no longer maintained by Formidable. We are no longer responding to issues or pull requests unless they relate to security concerns. We encourage interested developers to fork this project and make it their own!\n\n[maintenance-image]: https://img.shields.io/badge/maintenance-archived-red.svg\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFormidableLabs%2Fyesno","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFormidableLabs%2Fyesno","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFormidableLabs%2Fyesno/lists"}