Skip to content

Commit 62d46aa

Browse files
authored
Merge pull request Colin-b#33 from Colin-b/develop
Release 0.10.1
2 parents 9a42c1d + 6dddd90 commit 62d46aa

File tree

6 files changed

+83
-10
lines changed

6 files changed

+83
-10
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [0.10.1] - 2020-11-25
10+
### Fixed
11+
- Order of different parameters does not matters anymore for URL matching. It does however still matter for a same parameter.
12+
913
## [0.10.0] - 2020-10-06
1014
### Added
1115
- Document how to assert that no requests were issued.
@@ -119,7 +123,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
119123
### Added
120124
- First release, should be considered as unstable for now as design might change.
121125

122-
[Unreleased]: https://github.com/Colin-b/pytest_httpx/compare/v0.10.0...HEAD
126+
[Unreleased]: https://github.com/Colin-b/pytest_httpx/compare/v0.10.1...HEAD
127+
[0.10.1]: https://github.com/Colin-b/pytest_httpx/compare/v0.10.0...v0.10.1
123128
[0.10.0]: https://github.com/Colin-b/pytest_httpx/compare/v0.9.0...v0.10.0
124129
[0.9.0]: https://github.com/Colin-b/pytest_httpx/compare/v0.8.0...v0.9.0
125130
[0.8.0]: https://github.com/Colin-b/pytest_httpx/compare/v0.7.0...v0.8.0

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<a href="https://travis-ci.com/Colin-b/pytest_httpx"><img alt="Build status" src="https://api.travis-ci.com/Colin-b/pytest_httpx.svg?branch=master"></a>
66
<a href="https://travis-ci.com/Colin-b/pytest_httpx"><img alt="Coverage" src="https://img.shields.io/badge/coverage-100%25-brightgreen"></a>
77
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
8-
<a href="https://travis-ci.com/Colin-b/pytest_httpx"><img alt="Number of tests" src="https://img.shields.io/badge/tests-131 passed-blue"></a>
8+
<a href="https://travis-ci.com/Colin-b/pytest_httpx"><img alt="Number of tests" src="https://img.shields.io/badge/tests-135 passed-blue"></a>
99
<a href="https://pypi.org/project/pytest-httpx/"><img alt="Number of downloads" src="https://img.shields.io/pypi/dm/pytest_httpx"></a>
1010
</p>
1111

@@ -82,17 +82,19 @@ You can add criteria so that response will be sent only in case of a more specif
8282

8383
Matching is performed on the full URL, query parameters included.
8484

85+
Order of parameters in the query string does not matter, however order of values do matter if the same parameter is provided more than once.
86+
8587
```python
8688
import httpx
8789
from pytest_httpx import HTTPXMock
8890

8991

9092
def test_url(httpx_mock: HTTPXMock):
91-
httpx_mock.add_response(url="http://test_url")
93+
httpx_mock.add_response(url="http://test_url?a=1&b=2")
9294

9395
with httpx.Client() as client:
94-
response1 = client.delete("http://test_url")
95-
response2 = client.get("http://test_url")
96+
response1 = client.delete("http://test_url?a=1&b=2")
97+
response2 = client.get("http://test_url?b=2&a=1")
9698
```
9799

98100
#### Matching on HTTP method

pytest_httpx/_httpx_mock.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import re
22
from typing import List, Union, Optional, Callable, Tuple, Pattern, Any
3+
from urllib.parse import parse_qs
34

45
import httpcore
56
import httpx
@@ -35,7 +36,7 @@ def __init__(
3536
match_content: bytes = None,
3637
):
3738
self.nb_calls = 0
38-
self.url = url
39+
self.url = httpx.URL(url) if url and isinstance(url, str) else url
3940
self.method = method.upper() if method else method
4041
self.headers = match_headers
4142
self.content = match_content
@@ -58,10 +59,15 @@ def _url_match(self, request: httpx.Request) -> bool:
5859
):
5960
return self.url.match(str(request.url)) is not None
6061

61-
if isinstance(self.url, httpx.URL):
62-
return self.url == request.url
62+
# Compare query parameters apart as order of parameters should not matter
63+
request_qs = parse_qs(request.url.query)
64+
qs = parse_qs(self.url.query)
6365

64-
return self.url == str(request.url)
66+
# Remove the query parameters from the original URL to compare everything besides query parameters
67+
request_url = request.url.copy_with(query=None)
68+
url = self.url.copy_with(query=None)
69+
70+
return (request_qs == qs) and (url == request_url)
6571

6672
def _method_match(self, request: httpx.Request) -> bool:
6773
if not self.method:

pytest_httpx/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
# Major should be incremented in case there is a breaking change. (eg: 2.5.8 -> 3.0.0)
44
# Minor should be incremented in case there is an enhancement. (eg: 2.5.8 -> 2.6.0)
55
# Patch should be incremented in case there is a bug fix. (eg: 2.5.8 -> 2.5.9)
6-
__version__ = "0.10.0"
6+
__version__ = "0.10.1"

tests/test_httpx_async.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ async def test_url_matching(httpx_mock: HTTPXMock):
4141
assert response.content == b""
4242

4343

44+
@pytest.mark.asyncio
45+
async def test_url_query_string_matching(httpx_mock: HTTPXMock):
46+
httpx_mock.add_response(url="http://test_url?a=1&b=2")
47+
48+
async with httpx.AsyncClient() as client:
49+
response = await client.post("http://test_url?a=1&b=2")
50+
assert response.content == b""
51+
52+
# Parameters order should not matter
53+
response = await client.get("http://test_url?b=2&a=1")
54+
assert response.content == b""
55+
56+
4457
@pytest.mark.asyncio
4558
async def test_url_not_matching(httpx_mock: HTTPXMock):
4659
httpx_mock.add_response(url="http://test_url")
@@ -58,6 +71,24 @@ async def test_url_not_matching(httpx_mock: HTTPXMock):
5871
httpx_mock.reset(assert_all_responses_were_requested=False)
5972

6073

74+
@pytest.mark.asyncio
75+
async def test_url_query_string_not_matching(httpx_mock: HTTPXMock):
76+
httpx_mock.add_response(url="http://test_url?a=1&a=2")
77+
78+
async with httpx.AsyncClient() as client:
79+
with pytest.raises(httpx.TimeoutException) as exception_info:
80+
# Same parameter order matters as it corresponds to a list on server side
81+
await client.get("http://test_url?a=2&a=1")
82+
assert (
83+
str(exception_info.value)
84+
== """No response can be found for GET request on http://test_url?a=2&a=1 amongst:
85+
Match all requests on http://test_url?a=1&a=2"""
86+
)
87+
88+
# Clean up responses to avoid assertion failure
89+
httpx_mock.reset(assert_all_responses_were_requested=False)
90+
91+
6192
@pytest.mark.asyncio
6293
async def test_method_matching(httpx_mock: HTTPXMock):
6394
httpx_mock.add_response(method="get")

tests/test_httpx_sync.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ def test_url_matching(httpx_mock: HTTPXMock):
3838
assert response.content == b""
3939

4040

41+
def test_url_query_string_matching(httpx_mock: HTTPXMock):
42+
httpx_mock.add_response(url="http://test_url?a=1&b=2")
43+
44+
with httpx.Client() as client:
45+
response = client.post("http://test_url?a=1&b=2")
46+
assert response.content == b""
47+
48+
# Parameters order should not matter
49+
response = client.get("http://test_url?b=2&a=1")
50+
assert response.content == b""
51+
52+
4153
def test_url_not_matching(httpx_mock: HTTPXMock):
4254
httpx_mock.add_response(url="http://test_url")
4355

@@ -54,6 +66,23 @@ def test_url_not_matching(httpx_mock: HTTPXMock):
5466
httpx_mock.reset(assert_all_responses_were_requested=False)
5567

5668

69+
def test_url_query_string_not_matching(httpx_mock: HTTPXMock):
70+
httpx_mock.add_response(url="http://test_url?a=1&a=2")
71+
72+
with httpx.Client() as client:
73+
with pytest.raises(httpx.TimeoutException) as exception_info:
74+
# Same parameter order matters as it corresponds to a list on server side
75+
client.get("http://test_url?a=2&a=1")
76+
assert (
77+
str(exception_info.value)
78+
== """No response can be found for GET request on http://test_url?a=2&a=1 amongst:
79+
Match all requests on http://test_url?a=1&a=2"""
80+
)
81+
82+
# Clean up responses to avoid assertion failure
83+
httpx_mock.reset(assert_all_responses_were_requested=False)
84+
85+
5786
def test_method_matching(httpx_mock: HTTPXMock):
5887
httpx_mock.add_response(method="get")
5988

0 commit comments

Comments
 (0)