Skip to main content

tests/cassettes.py

1"""
2pytest fixtures for working with vcrpy to record HTTP requests.
4This allows us to record HTTP interactions as YAML files, so they can
5be "played back" later -- e.g. in automated tests or GitHub Actions.
6This means our tests are working with real responses, but don't
7depend on the original service being up and running.
9This establishes a couple of conventions for where cassettes are stored
10and how they're named.
12See https://vcrpy.readthedocs.io/
13"""
15from collections.abc import Iterator
17import pytest
18import vcr
19from vcr.cassette import Cassette
22__all__ = ["cassette_name", "vcr_cassette"]
25def get_cassette_name(request: pytest.FixtureRequest) -> str:
26 """
27 Return the name of a cassette for vcr.py.
29 The name can be made up of (up to) three parts:
31 - the name of the test class
32 - the name of the test function
33 - the ID of the test case in @pytest.mark.parametrize
35 """
36 name = request.node.name
38 # This is to catch cases where e.g. we try to include a complete
39 # HTTP URL in a cassette name, which creates very messy folders in
40 # the fixtures directory.
41 if any(char in name for char in ":/"):
42 raise ValueError(
43 "Illegal characters in VCR cassette name - "
44 "please set a test ID with pytest.param(…, id='…')"
45 )
47 if request.cls is not None:
48 return f"{request.cls.__name__}.{name}.yml"
49 else:
50 return f"{name}.yml"
53@pytest.fixture
54def cassette_name(request: pytest.FixtureRequest) -> str:
55 """
56 Return the filename of a VCR cassette to use in tests.
58 This is useful when you need some custom vcr.py options, and
59 can't use the prebuilt `vcr_cassette` fixture.
60 """
61 return get_cassette_name(request)
64@pytest.fixture
65def vcr_cassette(cassette_name: str) -> Iterator[Cassette]:
66 """
67 Create a VCR cassette for use in tests.
69 Tests will record their HTTP interactions as "cassettes" using vcr.py,
70 which can be replayed offline (e.g. in CI tests).
71 """
72 with vcr.use_cassette(
73 cassette_name,
74 cassette_library_dir="tests/fixtures/cassettes",
75 decode_compressed_response=True,
76 ) as cassette:
77 yield cassette