{"id":18018,"library":"yesno-http","title":"YesNo HTTP Testing for Node.js","description":"YesNo is an HTTP testing library for Node.js designed to intercept, mock, and record outgoing HTTP requests. Utilizing the `Mitm` library, it operates at a low level within the Node.js process, allowing for the inspection and manipulation of actual HTTP traffic generated by an application, rather than simply mocking higher-level request library calls. This approach enables more accurate and robust testing of an application's real-world network behavior. The current version, 0.0.7, is explicitly noted as a beta release, indicating that its API is subject to change and may undergo breaking modifications before reaching its first stable major release. The project is actively maintained, focusing on reaching this 1.0.0 milestone. Key features include spying on requests, easily mocking responses, and recording interactions for future use or to generate test data.","status":"active","version":"0.0.7","language":"javascript","source_language":"en","source_url":"https://github.com/formidablelabs/yesno","tags":["javascript","typescript"],"install":[{"cmd":"npm install yesno-http","lang":"bash","label":"npm"},{"cmd":"yarn add yesno-http","lang":"bash","label":"yarn"},{"cmd":"pnpm add yesno-http","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core dependency for intercepting low-level network traffic; YesNo leverages Mitm to spy on and mock HTTP requests within the Node.js process.","package":"mitm","optional":false}],"imports":[{"note":"While the README uses `require`, the package ships with TypeScript types, implying an ESM-first approach for modern Node.js usage. CommonJS requires named destructuring: `const { yesno } = require('yesno-http');`","wrong":"const yesno = require('yesno-http');","symbol":"yesno","correct":"import { yesno } from 'yesno-http';"},{"note":"This is a TypeScript interface for the intercepted HTTP request format, intended for type-checking, not runtime import.","wrong":"import { ISerializedHttp } from 'yesno-http';","symbol":"ISerializedHttp","correct":"import type { ISerializedHttp } from 'yesno-http';"},{"note":"The `spy()` method is called directly on the imported `yesno` object to begin intercepting requests. It can accept optional configuration.","symbol":"yesno.spy","correct":"yesno.spy();"},{"note":"Crucial for cleaning up after tests. This method restores normal HTTP behavior and clears mocks. It's recommended to call this in an `afterEach` hook.","symbol":"yesno.restore","correct":"yesno.restore();"}],"quickstart":{"code":"const { yesno } = require('yesno-http');\nconst { expect } = require('chai'); // Assuming chai for assertions\nconst http = require('http'); // For a simple HTTP request example\n\n// Simulate a simple API call function\nconst myApi = {\n  getUsers: async () => {\n    return new Promise((resolve, reject) => {\n      http.get('http://api.example.com/users', (res) => {\n        let data = '';\n        res.on('data', (chunk) => { data += chunk; });\n        res.on('end', () => {\n          try {\n            resolve(JSON.parse(data));\n          } catch (e) {\n            reject(e);\n          }\n        });\n      }).on('error', (err) => {\n        reject(err);\n      });\n    });\n  }\n};\n\ndescribe('my-api with YesNo', () => {\n  beforeEach(() => {\n    yesno.spy(); // Intercept requests before each test\n  });\n\n  afterEach(() => {\n    yesno.restore(); // Clean up after each test to prevent interference\n  });\n\n  it('should get users and intercept the request', async () => {\n    // Configure a mock response for 'api.example.com/users'\n    yesno.mock([\n      {\n        url: 'http://api.example.com/users',\n        response: {\n          statusCode: 200,\n          headers: { 'Content-Type': 'application/json' },\n          body: { users: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }] }\n        }\n      }\n    ]);\n\n    const users = await myApi.getUsers();\n    const interceptedRequests = yesno.intercepted(); // Get the intercepted requests\n\n    expect(interceptedRequests).to.have.lengthOf(1);\n    expect(interceptedRequests[0]).to.have.nested.property('url', 'http://api.example.com/users');\n    expect(users).to.deep.eql([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);\n    expect(interceptedRequests[0].response.statusCode).to.equal(200);\n  });\n\n  it('should allow filtering intercepted requests', async () => {\n    yesno.mock([\n      { url: 'http://api.example.com/posts', response: { statusCode: 200, body: [] } },\n      { url: 'http://api.example.com/comments', response: { statusCode: 200, body: [] } }\n    ]);\n\n    await Promise.all([\n      new Promise((resolve) => http.get('http://api.example.com/posts', resolve)),\n      new Promise((resolve) => http.get('http://api.example.com/comments', resolve))\n    ]);\n\n    const postsRequests = yesno.intercepted(/posts/);\n    expect(postsRequests).to.have.lengthOf(1);\n    expect(postsRequests[0].url).to.include('/posts');\n  });\n});","lang":"javascript","description":"This quickstart demonstrates how to set up basic HTTP interception, mock responses, and retrieve specific intercepted requests using `yesno-http` within a test suite. It includes `beforeEach` and `afterEach` hooks for proper setup and teardown."},"warnings":[{"fix":"Consult the latest GitHub README and changelog for any API updates before upgrading. Pin exact versions of `yesno-http` in `package.json` to prevent unexpected breaks.","message":"YesNo is currently in beta (v0.0.7), and its API is explicitly noted as subject to change. Developers should expect potential breaking changes in minor or even patch versions before the first major stable release (1.0.0).","severity":"breaking","affected_versions":">=0.0.0"},{"fix":"Use `yesno.restore()` diligently in `afterEach` hooks to ensure cleanup. For long-running connections or specific ports that should be ignored (e.g., database connections), configure `ignorePorts` in `yesno.spy(options: IInterceptOptions)`.","message":"YesNo uses `Mitm` to intercept *all* outgoing network TCP and HTTP connections from the Node.js process. This can include unexpected traffic from other libraries or even Node.js internals, potentially interfering with other network-related test setups or debugging.","severity":"gotcha","affected_versions":">=0.0.0"},{"fix":"Ensure your test environment is configured to trust the `Mitm` generated certificates if real HTTPS connections are being intercepted and re-encrypted. This often involves setting `NODE_TLS_REJECT_UNAUTHORIZED='0'` in test environments, but use with caution due to security implications, or specifically configuring certificate trust for your testing framework.","message":"When intercepting HTTPS traffic, `Mitm` (and thus YesNo) might encounter issues with self-signed certificates or custom Certificate Authorities, leading to `ERR_CERT_AUTHORITY_INVALID` or similar trust errors.","severity":"gotcha","affected_versions":">=0.0.0"}],"env_vars":null,"last_verified":"2026-04-23T00:00:00.000Z","next_check":"2026-07-22T00:00:00.000Z","problems":[{"fix":"Ensure `yesno.restore()` is called after every test or test suite where `yesno.spy()` is used, typically within an `afterEach` or `afterAll` hook in your test runner.","cause":"The `yesno.spy()` method was called multiple times without a corresponding `yesno.restore()` call in between, leading to `Mitm` attempting to re-enable interception while already active.","error":"Error: Mitm is already enabled!"},{"fix":"Verify that `yesno.spy()` is called *before* the code under test makes its HTTP requests, and `yesno.restore()` is called *after* all asynchronous operations related to the test are finished, often by ensuring the test case is `async/await` and awaits all network operations. Place `yesno.spy()` in `beforeEach` and `yesno.restore()` in `afterEach` for most unit test setups.","cause":"The `yesno.spy()` method was not active when the HTTP request was made, or `yesno.restore()` was called too early, before the asynchronous request completed.","error":"TypeError: Cannot read properties of undefined (reading 'response') or requests not being intercepted."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}