lundberg / respx

Mock HTTPX with awesome request patterns and response side effects 🦋
https://lundberg.github.io/respx
BSD 3-Clause "New" or "Revised" License
581 stars 38 forks source link

Support multipart encoding in Data pattern #251

Closed ziima closed 4 months ago

ziima commented 4 months ago

Data pattern only handles urlencoded data, not multipart encoded. This is troublesome because by addition of files to the request, the encoding changes and Data pattern fails to match the request.

MWE

import httpx
import respx

with respx.mock() as rsps:
    rsps.post('http://example.org/', data={'answer': '42'})
    httpx.post('http://example.org', data={'answer': '42'})  # OK

with respx.mock() as rsps:
    rsps.post('http://example.org/', data={'answer': '42'})
    httpx.post('http://example.org', data={'answer': '42'}, files={'file': b'content'})
    # >>> respx.models.AllMockedAssertionError: RESPX: <Request('POST', 'http://example.org/')> not mocked!

Related to #115

lundberg commented 4 months ago

Definitely related to a files pattern. I haven't looked at how data changes, but it would be interesting to see if it would be possible to reconstruct without implementing the same logic as httpx has 🤔.

If we can solve this one, both issues would probably be solved, which is great.

lundberg commented 4 months ago

@ziima Thanks for the idea/suggestion in #115 to use the email module for extracting the encoded form data.

The new respx.utils.decode_data will need to be improved to add support for matching files, but should be a lot easier now that the surrounding decoding is in place.

Please try this PR on your code, if possible, to rule out any new bugs 🙏 🤞

lundberg commented 4 months ago

One potential bug is if a regular form text field together with a file without filename and content type text/plain is provided. Not sure, but my gut feeling says that this could get mixed up. If so, I'm not sure how to distinguish them 🤔