I want to test an API client performing REST requests. The requests look like this:
# vcr/attachments.yml
- method: POST
- path: http://example.org/attachments
- body: { "filename": "foo.jpg", "signature": "6g33jk2C1QQn9EM8Q==" }
- response: 200 OK
- method: POST
- path: http://example.org/attachments
- body: { "filename": "bar.jpg", "signature": "7z44g6aPPk2C17Xf5==" }
- response: 409 Conflict
I'm trying to mock these requests using VCR. In the relevant test, I write:
VCR.use_cassette('attachments', match_requests_on: [:host, :path, :body_as_json]) do
my_record.attach_all(['foo.jpg', 'bar.jpg'])
assert_nil my_record.errors['foo.jpg'] # should succeed with 200
assert_present my_record.errors['bar.jpg'] # should fail with 409
end
The only thing differentiating the two requests in the "filename"="foo.jpg" body parameter, so I need to match on the request body.
But the problem is that the signature parameter is essentially random - or at least cannot be consistently be predicted (e.g. it changes on the CI server). So matching on the whole body is flaky and unreliable.
How can I ensure that VCR will match the proper recorded request, even when the body will never match perfectly?
Of course, the easiest solution would be to just split the cassette in two. Then you can match them one after another:
But if for some reason you can't split the requests (maybe because they need to be batched together), that won't work.
In that case, a more elaborated solution would be to use a custom VCR matcher.
(See up-to-date gist here: https://gist.github.com/kemenaran/2dcc463fdda3e476983bf5500f3524b9)
In your tests, you can then tell VCR to ignore the
signaturepart of the JSON body:VCR will now match against the whole JSON, except the part that may change unpredictably.