{"_id":"socket-vcr-test","_rev":"8-412a9f5480ca51cc5b18a38dd5278b8c","name":"socket-vcr-test","dist-tags":{"latest":"2.1.0"},"versions":{"1.3.0-fix-gzip":{"name":"socket-vcr-test","version":"1.3.0-fix-gzip","keywords":["http","mocking","record","vcr","testing"],"author":{"name":"epignosisx"},"license":"MIT","_id":"socket-vcr-test@1.3.0-fix-gzip","maintainers":[{"name":"raynos","email":"raynos2@gmail.com"}],"homepage":"https://github.com/epignosisx/vcr-test#readme","bugs":{"url":"https://github.com/epignosisx/vcr-test/issues"},"dist":{"shasum":"b47e6ea38377c02fa2e8ec6d40e37ace5d97315e","tarball":"https://registry.npmjs.org/socket-vcr-test/-/socket-vcr-test-1.3.0-fix-gzip.tgz","fileCount":3,"integrity":"sha512-VSQnPRZDpqzhhnL/uozshbsADNG/EwpDuNMhMpNVgZUsUjBuWn16xfMrosaACKAiaJkrbNKaYSR0mz4iEYVExw==","signatures":[{"sig":"MEUCIQDkUNjdahOQpdmL3z4Omr/h02mx1s3G7z51j/xfUMzyyAIgUCFpeSU9ekoTViVEgnDH/7H9n7pwLyUqDs9w2phcMIo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":10061},"main":"dist/index.js","gitHead":"fef2a88941ae3591c02986f9b4ead6f489b7420a","scripts":{"test":"vitest","build":"tsc"},"_npmUser":{"name":"raynos","actor":{"name":"raynos","type":"user","email":"raynos2@gmail.com"},"email":"raynos2@gmail.com"},"repository":{"url":"git+https://github.com/epignosisx/vcr-test.git"},"_npmVersion":"10.9.2","description":"Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.","directories":{},"_nodeVersion":"22.15.0","dependencies":{"yaml":"2.8.0","@mswjs/interceptors":"0.23.0"},"_hasShrinkwrap":false,"devDependencies":{"axios":"1.10.0","vitest":"3.2.4","typescript":"5.0.4","@types/node":"24.0.3","@vitest/coverage-v8":"3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/socket-vcr-test_1.3.0-fix-gzip_1751021901975_0.02147047323694573","host":"s3://npm-registry-packages-npm-production"}},"1.3.0-fix-gzip2":{"name":"socket-vcr-test","version":"1.3.0-fix-gzip2","keywords":["http","mocking","record","vcr","testing"],"author":{"name":"epignosisx"},"license":"MIT","_id":"socket-vcr-test@1.3.0-fix-gzip2","maintainers":[{"name":"raynos","email":"raynos2@gmail.com"}],"homepage":"https://github.com/epignosisx/vcr-test#readme","bugs":{"url":"https://github.com/epignosisx/vcr-test/issues"},"dist":{"shasum":"4a8c98d9dbdf181c66b674fdff825e6b432afe4b","tarball":"https://registry.npmjs.org/socket-vcr-test/-/socket-vcr-test-1.3.0-fix-gzip2.tgz","fileCount":21,"integrity":"sha512-c6KIsFs4Ovgff4kLLJ9xLz5W3cQkglyqcm8NTVJ20KsdofYzlqg0NpDkNNAcW0SFIbJjscNUJu4dCtVfCTd0/Q==","signatures":[{"sig":"MEQCIHvNJgNQUWC7K+ZW4VxrU6FC0R4eRS3bMz6IGbFnLqP1AiARzcTHSt2VtIMZi37+qcLgFmwF85GxWn9MKnhy/x06Gg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41131},"main":"dist/index.js","types":"./dist/index.d.ts","gitHead":"47856e9673498024b1843496b64b1d0f9446fe6f","scripts":{"test":"vitest","build":"tsc"},"_npmUser":{"name":"raynos","actor":{"name":"raynos","type":"user","email":"raynos2@gmail.com"},"email":"raynos2@gmail.com"},"repository":{"url":"git+https://github.com/epignosisx/vcr-test.git"},"_npmVersion":"10.9.2","description":"Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.","directories":{},"_nodeVersion":"22.15.0","dependencies":{"yaml":"2.8.0","@mswjs/interceptors":"0.23.0"},"_hasShrinkwrap":false,"devDependencies":{"axios":"1.10.0","vitest":"3.2.4","typescript":"5.0.4","@types/node":"24.0.3","@vitest/coverage-v8":"3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/socket-vcr-test_1.3.0-fix-gzip2_1751023361076_0.21459769564046183","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"socket-vcr-test","version":"2.0.0","keywords":["http","mocking","record","vcr","testing"],"author":{"name":"epignosisx"},"license":"MIT","_id":"socket-vcr-test@2.0.0","maintainers":[{"name":"bret","email":"bcomnes@gmail.com"},{"name":"raynos","email":"raynos2@gmail.com"},{"name":"jhiesey","email":"john@hiesey.com"}],"homepage":"https://github.com/SocketDev/vcr-test#readme","bugs":{"url":"https://github.com/SocketDev/vcr-test/issues"},"dist":{"shasum":"7fb7c608bb6a9f602bd6e6eb1dca4094c4569598","tarball":"https://registry.npmjs.org/socket-vcr-test/-/socket-vcr-test-2.0.0.tgz","fileCount":21,"integrity":"sha512-gGhpJIVJleRPyge9ubVX247KtDXaI74EVg5F97ERxivVuaPGYyeyTEj1mrottkuLZ5170Zeej7XTL4eL1Igo4w==","signatures":[{"sig":"MEUCIGPaun692Nz59j4XG2Npibe0McZUrUPjFXchi4L6mXw8AiEArSvNz5q3vUntaKVNhM8nnfR2WSg7Jcigx9tjHHyv78c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41276},"main":"dist/index.js","types":"./dist/index.d.ts","gitHead":"433dcf7266dd4a1ba05e161faeb532719176c243","scripts":{"test":"tap src/**/*.spec.ts"},"_npmUser":{"name":"raynos","email":"raynos2@gmail.com"},"repository":{"url":"git+https://github.com/SocketDev/vcr-test.git"},"_npmVersion":"10.9.2","description":"Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.","directories":{},"_nodeVersion":"22.17.0","dependencies":{"yaml":"^2.8.0","@mswjs/interceptors":"0.23.0"},"_hasShrinkwrap":false,"devDependencies":{"tap":"^19.2.5","@types/node":"24.0.3"},"_npmOperationalInternal":{"tmp":"tmp/socket-vcr-test_2.0.0_1754566260878_0.387987051151899","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"socket-vcr-test","version":"2.0.1","keywords":["http","mocking","record","vcr","testing"],"author":{"name":"epignosisx"},"license":"MIT","_id":"socket-vcr-test@2.0.1","maintainers":[{"name":"bret","email":"bcomnes@gmail.com"},{"name":"raynos","email":"raynos2@gmail.com"},{"name":"jhiesey","email":"john@hiesey.com"},{"name":"mixmix","email":"mix@protozoa.nz"}],"homepage":"https://github.com/SocketDev/vcr-test#readme","bugs":{"url":"https://github.com/SocketDev/vcr-test/issues"},"dist":{"shasum":"eb62a6f0097ff38c06ac67ee4689c1993352fc15","tarball":"https://registry.npmjs.org/socket-vcr-test/-/socket-vcr-test-2.0.1.tgz","fileCount":28,"integrity":"sha512-5qGeABVzEIrstO0Gz8Xzi1ViUF4+mUOduAVoVc0AkV+VYHyMGTbci9duxJZ+4z8OwhsyuI0lZEKnNwZ5BZrTEA==","signatures":[{"sig":"MEUCIQCJAmKhThvmaOSyBNPnWFADiSvemLdSwe9OK7yUK8WzBgIgXhKeTGrSVbGLeRQBUYCfMfry5BEBAYe/ukW/wrJqpI0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118277},"main":"dist/index.js","types":"./dist/index.d.ts","gitHead":"f05001081acbf9e78380211b7b79b5cd4cbdc5d7","scripts":{"test":"tap src/**/*.spec.ts","build":"tsc"},"_npmUser":{"name":"mixmix","email":"mix@protozoa.nz"},"repository":{"url":"git+https://github.com/SocketDev/vcr-test.git"},"_npmVersion":"10.9.3","description":"Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.","directories":{},"_nodeVersion":"22.18.0","dependencies":{"yaml":"^2.8.0","@mswjs/interceptors":"0.23.0"},"_hasShrinkwrap":false,"devDependencies":{"tap":"^19.2.5","typescript":"5.0.4","@types/node":"24.0.3"},"_npmOperationalInternal":{"tmp":"tmp/socket-vcr-test_2.0.1_1754962686326_0.46267588442927443","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"socket-vcr-test","version":"2.1.0","description":"Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.","keywords":["http","mocking","record","vcr","testing"],"main":"dist/index.js","scripts":{"test":"tap src/**/*.spec.ts","build":"tsc"},"author":{"name":"epignosisx"},"repository":{"url":"git+https://github.com/SocketDev/vcr-test.git"},"license":"MIT","devDependencies":{"@types/node":"24.0.3","tap":"^19.2.5","typescript":"5.0.4"},"dependencies":{"@mswjs/interceptors":"0.23.0","yaml":"^2.8.0"},"gitHead":"8f2e84ddb81dbbf68bee954ee11519fa5fcd8b07","types":"./dist/index.d.ts","_id":"socket-vcr-test@2.1.0","bugs":{"url":"https://github.com/SocketDev/vcr-test/issues"},"homepage":"https://github.com/SocketDev/vcr-test#readme","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-TS2KFJitKzFB6ptsvPycXgoyMp4/+zgPAH9Xll6ituSC5vUrvRoi7p+LMrOOUtJVU5h3c+G/Umv7n3rLaPUe2A==","shasum":"13221a9e20f9f9359e7368b08f95b5b25e622bec","tarball":"https://registry.npmjs.org/socket-vcr-test/-/socket-vcr-test-2.1.0.tgz","fileCount":28,"unpackedSize":123484,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIG0JRIR/Y2nXg2ZOGFr7DqMOGSZK52dWnIS8FshseoWAAiEA2QI2E+7PSfEblZ6ty92/pbz3t0C+07GaXTf71qwGuoE="}]},"_npmUser":{"name":"mixmix","email":"mix@protozoa.nz"},"directories":{},"maintainers":[{"name":"bret","email":"bcomnes@gmail.com"},{"name":"raynos","email":"raynos2@gmail.com"},{"name":"jhiesey","email":"john@hiesey.com"},{"name":"mixmix","email":"mix@protozoa.nz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/socket-vcr-test_2.1.0_1781666867822_0.3700785539348932"},"_hasShrinkwrap":false}},"time":{"created":"2025-06-27T10:58:21.975Z","modified":"2026-06-17T03:27:48.090Z","1.3.0-fix-gzip":"2025-06-27T10:58:22.147Z","1.3.0-fix-gzip2":"2025-06-27T11:22:41.264Z","2.0.0":"2025-08-07T11:31:01.062Z","2.0.1":"2025-08-12T01:38:06.570Z","2.1.0":"2026-06-17T03:27:47.973Z"},"bugs":{"url":"https://github.com/SocketDev/vcr-test/issues"},"author":{"name":"epignosisx"},"license":"MIT","homepage":"https://github.com/SocketDev/vcr-test#readme","keywords":["http","mocking","record","vcr","testing"],"repository":{"url":"git+https://github.com/SocketDev/vcr-test.git"},"description":"Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.","maintainers":[{"name":"bret","email":"bcomnes@gmail.com"},{"name":"raynos","email":"raynos2@gmail.com"},{"name":"jhiesey","email":"john@hiesey.com"},{"name":"mixmix","email":"mix@protozoa.nz"}],"readme":"# socket-vcr-test\n\nRecord your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.\n\nThis is a fork of [epignosisx/vcr-test](https://github.com/epignosisx/vcr-test)\n<!-- TODO: description about how this deviates + why -->\n\n## Installation\n\n```bash\nnpm install socket-vcr-test --save-dev\n# or\npnpm add socket-vcr-test --save-dev\n```\n\n## Usage\nA cassette contains all the HTTP traffic generated by your code. The first time the test runs, it should make live HTTP calls. `vcr-test`` will take care of recording the HTTP traffic and storing it. Future test runs replay the recorded traffic.\n\n```ts\nimport { join } from 'node:path';\nimport { VCR, FileStorage } from 'socket-vcr-test';\nimport { api } from './my-api'\n\ndescribe('some suite', () => {\n  it('some test', async () => {\n    // Configure VCR\n    const vcr = new VCR(new FileStorage(join(__dirname, '__cassettes__')));\n\n    // Intercept HTTP traffic\n    await vcr.useCassette('cassette_name', async () => {\n      const result = await api.myAwesomeApiCall();\n\n      // Your regular assertions\n      expect(result).toBeDefined();\n    });\n  })\n})\n```\n\n### Terminology\n\n- Cassette: a file containing the recorded HTTP interactions.\n- HTTP Interaction: a HTTP Request and Response tuple\n\n## Recording Modes\nVCR supports different recording modes:\n\n1. `once`: Record the HTTP interactions if the cassette has not been recorded; otherwise, playback the HTTP interactions. This is the default. Helpful when a new feature has been developed and you want to record once and playback in the future.\n2. `none`: Do not record any HTTP interactions; play them all back. Similar to `once` except it will not try to make live calls even when the cassette does not exist.\n3. `update`: Records new HTTP interactions, plays back the recorded ones, deletes the rest. Useful when there is a change in one of the HTTP interactions like a new field in the request or response. This mode will try to preserve the cassette as much as possible.\n4. `all` Record every HTTP interactions; do not play any back. Useful for one-time checks against the real endpoints.\n\n```ts\nimport { VCR, RecordMode } from 'socket-vcr-test';\n\nconst vcr = new VCR(...);\nvcr.mode = RecordMode.update;\n\nawait vcr.useCassette(...);\n```\n\n\n## Extensibility\n\n### Request masking\nYour API calls might include sensitive data that you do not want to record in a cassette (API Keys, bearer tokens, etc). You can assign a request masker by:\n\n```ts\nimport { VCR } from 'socket-vcr-test';\nconst vcr = new VCR(...);\nvcr.requestMasker = (req) => {\n  req.headers['authorization'] = 'masked';\n};\n```\n\n### Request matching\nVCR will try to find a match in a cassette that matches on url, headers, and body. However, you may want to change this behavior to ignore certain headers and perform custom body checks.\n\nThe default request matcher allows you to change some of its behavior:\n\n```ts\nimport { VCR, DefaultRequestMatcher } from 'socket-vcr-test';\n\nconst vcr = new VCR(...);\n\nconst matcher = new DefaultRequestMatcher();\n\n// the request headers will not be compared against recorded HTTP traffic.\nmatcher.compareHeaders = false; \n\n// the request body will not be compared against recorded HTTP traffic.\nmatcher.compareBody = false;\n\n// This will ignore specific headers when doing request matching\nmatcher.ignoreHeaders.add('timestamp');\nmatcher.ignoreHeaders.add('content-length');\n\n// Assign to VCR\nvcr.matcher = matcher;\n```\n\nAlternatively, you can extend the default request matcher:\n\n```ts\nimport { DefaultRequestMatcher } from 'socket-vcr-test';\n\nclass MyCustomRequestMatcher extends DefaultRequestMatcher {\n  public bodiesEqual(recorded: HttpRequest, request: HttpRequest): boolean {\n    // custom body matching logic\n  }\n\n  public headersEqual(recorded: HttpRequest, request: HttpRequest): boolean {\n    // custom headers matching logic\n  }\n\n  public urlEqual(recorded: HttpRequest, request: HttpRequest): boolean {\n    // custom url matching logic\n  }\n\n  public methodEqual(recorded: HttpRequest, request: HttpRequest): boolean {\n    // custom method matching logic\n  }\n}\n\nconst vcr = new VCR(...);\nvcr.matcher = new MyCustomRequestMatcher();\n```\n\nIf you have more advanced matching needs you can implement your own Request Matcher:\n\n```ts\n/**\n * Matches an app request against a list of HTTP interactions previously recorded\n */\nexport interface IRequestMatcher {\n  /**\n   * Finds the index of the recorded HTTP interaction that matches a given request\n   * @param {HttpInteraction[]} calls recorded HTTP interactions\n   * @param {HttpRequest} request app request\n   * @returns {number} the index of the match or -1 if not found\n   */\n  indexOf(calls: HttpInteraction[], request: HttpRequest): number;\n}\n\nexport class MyCustomRequestMatcher implements IRequestMatcher {\n  ...\n}\n```\n\nand assign the custom implementation like this:\n\n```ts\nconst vcr = new VCR(...);\nvcr.matcher = new MyCustomRequestMatcher();\n```\n\nFor more details refer to the [DefaultRequestMatcher](https://github.com/SocketDev/socket-vcr-test/blob/main/src/default-request-matcher.ts) implementation.\n\n### Storage\nThe library comes with a File storage implementation that saves files in YAML for readibility. However, you may prefer to save the cassettes in a database and in JSON. You can change the storage and file format by creating a different storage implementation.\n\nThis is the interface you need to satisfy:\n\n```ts\n/**\n * Cassette storage\n */\nexport interface ICassetteStorage {\n  /**\n   * Loads a cassette from storage or undefined if not found.\n   * @param {string} name cassette name\n   * @returns {Promise<HttpInteraction[] | undefined>}\n   */\n  load(name: string): Promise<HttpInteraction[] | undefined>;\n\n  /**\n   * Saves HTTP traffic to a cassette with the specified name\n   * @param {string} name cassette name\n   * @param {HttpInteraction[]} interactions HTTP traffic\n   * @returns {Promise<void>}\n   */\n  save(name: string, interactions: HttpInteraction[]): Promise<void>;\n}\n```\n\nThen just initialize VCR with your implementation:\n\n```ts\nconst vcr = new VCR(new DatabaseStorage());\n```\n\nFor more details refer to the [FileStorage](https://github.com/SocketDev/socket-vcr-test/blob/main/src/file-storage.ts) implementation.\n\n### Request pass-through\nYou may want certain requests to never be recorded. You can do it this way:\n\n```ts\nimport { VCR } from 'socket-vcr-test';\nconst vcr = new VCR(...);\nvcr.requestPassThrough = (req) => {\n  return req.url.startsWith('https://example.com');\n};\n```\n\n### Body storage encoding\nBodies are stored in the cassette as readable text by default, but binary payloads (images, archives, executables, etc.) are base64-encoded so they survive the round-trip without corruption. VCR decides which encoding to use from the body's `content-type` (and `content-encoding`) headers.\n\nThe default policy, `defaultBase64EncodeBody`, stores a body as **text** only when its content-type is a recognised text type (`text/*`, `application/json`, `application/xml`, the `+json` / `+xml` structured-syntax suffixes, `application/x-www-form-urlencoded`, etc.) and **base64-encodes** everything else. This way the safe failure mode is \"readable text stored as base64\" rather than \"binary corrupted into text\".\n\nIf you need different behavior — for example, a custom API content-type that is actually text, or forcing a type to be base64-encoded — assign your own policy. It returns `true` to base64-encode the body:\n\n```ts\nimport { VCR, defaultBase64EncodeBody } from 'socket-vcr-test';\n\nconst vcr = new VCR(...);\n\n// Wrap the default and add your own rules.\n// `contentType` and `contentEncoding` are pre-extracted from the headers;\n// `headers` (a `Headers` instance for live traffic, or a plain record for a\n// recorded interaction) are also passed in case you need other header values.\nvcr.base64EncodeBody = (contentType, contentEncoding, headers) => {\n  // Force our custom protobuf type to be base64-encoded...\n  if (contentType.startsWith('application/x-acme-proto')) {\n    return true;\n  }\n\n  // ...and fall back to the built-in policy for everything else.\n  return defaultBase64EncodeBody(contentType, contentEncoding, headers);\n};\n```\n\nThe policy runs on **both** recording and playback, so it must make the same decision in each phase — otherwise a body stored as base64 could be replayed as text (or vice versa). Keep it stable for a given cassette.\n\n## FAQ\n### How can I pretty print JSON bodies?\n\nHere is a custom Cassette Storage implementatation that adds a new field with the formatted request and response body. It does not modify the real bodies to keep 100% fidelity with what the app sends and receives.\n\n```ts\nclass PrettifiedFileStorage extends FileStorage {\n  override save(name: string, interactions: HttpInteraction[]): Promise<void> {\n    for (const int of interactions) {\n      let contentType = int.request.headers['content-type'];\n      if (contentType?.startsWith('application/json')) {\n        try {\n          // @ts-expect-error dynamically adding field\n          int.request.bodyf = JSON.stringify(JSON.parse(int.request.body), null, 2);\n        } catch (err) {\n          console.error('Failed to prettify request body', err);\n        }\n      }\n\n      contentType = int.response.headers['content-type'];\n      if (contentType?.startsWith('application/json')) {\n        try {\n          // @ts-expect-error dynamically adding field\n          int.response.bodyf = JSON.stringify(JSON.parse(int.response.body), null, 2);\n        } catch (err) {\n          console.error('Failed to prettify response body', err);\n        }\n      }\n    }\n\n    return super.save(name, interactions);\n  }\n}\n\nconst vcr = new VCR(new PrettifiedFileStorage(...));\n```\n\n### How do I update an existing cassette because of a change?\nThe simplest way is to just delete the cassette and re-record it making all live calls. However, this may be tricky if the is some HTTP call is dynamic and you would not get the exact same data you were testing for. Here are some other options:\n\n1. Change the cassette manually, after all it is just YAML. Make sure to update the `Content-Length` header if the body changes!\n2. Change VCR's `mode` to `update`, run the test, then change back. This will make live calls for the requests that were not found in the cassette.\n","readmeFilename":"README.md"}