Claude Code Plugins

Community-maintained marketplace

Feedback

VCR.py HTTP recording for Python tests. Use when testing Python code making HTTP requests, recording API responses for replay, or creating deterministic tests for external services.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name vcr-http-recording
description VCR.py HTTP recording for Python tests. Use when testing Python code making HTTP requests, recording API responses for replay, or creating deterministic tests for external services.

VCR.py HTTP Recording

Record and replay HTTP interactions for Python tests.

When to Use

  • External API testing
  • Deterministic HTTP tests
  • Avoiding live API calls in CI
  • LLM API response recording

Basic Setup

# conftest.py
import pytest

@pytest.fixture(scope="module")
def vcr_config():
    return {
        "cassette_library_dir": "tests/cassettes",
        "record_mode": "once",
        "match_on": ["uri", "method"],
        "filter_headers": ["authorization", "x-api-key"],
        "filter_query_parameters": ["api_key", "token"],
    }

Basic Usage

import pytest

@pytest.mark.vcr()
def test_fetch_user():
    response = requests.get("https://api.example.com/users/1")

    assert response.status_code == 200
    assert response.json()["name"] == "John Doe"

@pytest.mark.vcr("custom_cassette.yaml")
def test_with_custom_cassette():
    response = requests.get("https://api.example.com/data")
    assert response.status_code == 200

Async Support

import pytest
from httpx import AsyncClient

@pytest.mark.asyncio
@pytest.mark.vcr()
async def test_async_api_call():
    async with AsyncClient() as client:
        response = await client.get("https://api.example.com/data")

    assert response.status_code == 200
    assert "items" in response.json()

Recording Modes

@pytest.fixture(scope="module")
def vcr_config():
    import os

    # CI: never record, only replay
    if os.environ.get("CI"):
        record_mode = "none"
    else:
        record_mode = "new_episodes"

    return {"record_mode": record_mode}
Mode Behavior
once Record if missing, then replay
new_episodes Record new, replay existing
none Never record (CI)
all Always record (refresh)

Filtering Sensitive Data

def filter_request_body(request):
    """Redact sensitive data from request body."""
    import json
    if request.body:
        try:
            body = json.loads(request.body)
            if "password" in body:
                body["password"] = "REDACTED"
            if "api_key" in body:
                body["api_key"] = "REDACTED"
            request.body = json.dumps(body)
        except json.JSONDecodeError:
            pass
    return request

@pytest.fixture(scope="module")
def vcr_config():
    return {
        "filter_headers": ["authorization", "x-api-key"],
        "before_record_request": filter_request_body,
    }

LLM API Testing

def llm_request_matcher(r1, r2):
    """Match LLM requests ignoring dynamic fields."""
    import json

    if r1.uri != r2.uri or r1.method != r2.method:
        return False

    body1 = json.loads(r1.body)
    body2 = json.loads(r2.body)

    # Ignore dynamic fields
    for field in ["request_id", "timestamp"]:
        body1.pop(field, None)
        body2.pop(field, None)

    return body1 == body2

@pytest.fixture(scope="module")
def vcr_config():
    return {
        "custom_matchers": [llm_request_matcher],
    }

Cassette File Example

# tests/cassettes/test_fetch_user.yaml
interactions:
- request:
    body: null
    headers:
      Content-Type: application/json
    method: GET
    uri: https://api.example.com/users/1
  response:
    body:
      string: '{"id": 1, "name": "John Doe"}'
    status:
      code: 200
version: 1

Key Decisions

Decision Recommendation
Record mode once for dev, none for CI
Cassette format YAML (readable)
Sensitive data Always filter headers/body
Custom matchers Use for LLM APIs

Common Mistakes

  • Committing cassettes with real API keys
  • Using all mode in CI (makes live calls)
  • Not filtering sensitive data
  • Missing cassettes in git

Related Skills

  • msw-mocking - Frontend equivalent
  • integration-testing - API testing patterns
  • llm-testing - LLM-specific patterns