Skip to content

Commit 5076dab

Browse files
authored
tests: added missing interception tests (microsoft#122)
1 parent 8c937ba commit 5076dab

13 files changed

+316
-10
lines changed

local-requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ pytest-asyncio==0.14.0
33
pytest-cov==2.10.0
44
pytest-sugar==0.9.4
55
pytest-xdist==1.33.0
6+
pixelmatch==0.2.1
7+
Pillow==7.2.0
68
mypy==0.782
79
setuptools==49.1.0
810
twisted==20.3.0

playwright/async_api.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ async def fulfill(
376376
status: int = None,
377377
headers: typing.Union[typing.Dict[str, str]] = None,
378378
body: typing.Union[str, bytes] = None,
379+
path: typing.Union[str, pathlib.Path] = None,
379380
contentType: str = None,
380381
) -> NoneType:
381382
"""Route.fulfill
@@ -392,12 +393,18 @@ async def fulfill(
392393
Optional response headers. Header values will be converted to a string.
393394
body : Optional[str, bytes]
394395
Optional response body.
396+
path : Optional[str, pathlib.Path]
397+
Optional file path to respond with. The content type will be inferred from file extension. If `path` is a relative path, then it is resolved relative to current working directory.
395398
contentType : Optional[str]
396399
If set, equals to setting `Content-Type` response header.
397400
"""
398401
return mapping.from_maybe_impl(
399402
await self._impl_obj.fulfill(
400-
status=status, headers=headers, body=body, contentType=contentType
403+
status=status,
404+
headers=headers,
405+
body=body,
406+
path=path,
407+
contentType=contentType,
401408
)
402409
)
403410

playwright/impl_to_api_mapping.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import inspect
1516
from typing import Any, Callable, Dict, List, Optional
1617
from weakref import WeakKeyDictionary
1718

@@ -80,7 +81,10 @@ def wrap_handler(self, handler: Callable[..., None]) -> Callable[..., None]:
8081
return self._instances[handler]
8182

8283
def wrapper(*args: Any) -> Any:
83-
return handler(*list(map(lambda a: self.from_maybe_impl(a), args)))
84+
arg_count = len(inspect.signature(handler).parameters)
85+
return handler(
86+
*list(map(lambda a: self.from_maybe_impl(a), args))[:arg_count]
87+
)
8488

8589
self._instances[handler] = wrapper
8690
return wrapper

playwright/network.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
import base64
1616
import json
17+
import mimetypes
18+
from pathlib import Path
1719
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast
1820

1921
from playwright.connection import ChannelOwner, from_channel, from_nullable_channel
@@ -100,22 +102,36 @@ async def fulfill(
100102
status: int = None,
101103
headers: Dict[str, str] = None,
102104
body: Union[str, bytes] = None,
105+
path: Union[str, Path] = None,
103106
contentType: str = None,
104107
) -> None:
105108
params = locals_to_params(locals())
106-
if contentType:
107-
if headers is None:
108-
headers = {}
109-
headers["Content-Type"] = contentType
110-
del params["contentType"]
111-
if headers:
112-
params["headers"] = serialize_headers(headers)
109+
length = 0
113110
if isinstance(body, str):
114111
params["body"] = body
115112
params["isBase64"] = False
113+
length = len(body.encode())
116114
elif isinstance(body, bytes):
117115
params["body"] = base64.b64encode(body).decode()
118116
params["isBase64"] = True
117+
length = len(body)
118+
elif path:
119+
del params["path"]
120+
file_content = Path(path).read_bytes()
121+
params["body"] = base64.b64encode(file_content).decode()
122+
params["isBase64"] = True
123+
length = len(file_content)
124+
125+
headers = {k.lower(): str(v) for k, v in params.get("headers", {}).items()}
126+
if params.get("contentType"):
127+
headers["content-type"] = params["contentType"]
128+
elif path:
129+
headers["content-type"] = (
130+
mimetypes.guess_type(str(Path(path)))[0] or "application/octet-stream"
131+
)
132+
if length and "content-length" not in headers:
133+
headers["content-length"] = str(length)
134+
params["headers"] = serialize_headers(headers)
119135
await self._channel.send("fulfill", params)
120136

121137
async def continue_(

playwright/sync_api.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ def fulfill(
378378
status: int = None,
379379
headers: typing.Union[typing.Dict[str, str]] = None,
380380
body: typing.Union[str, bytes] = None,
381+
path: typing.Union[str, pathlib.Path] = None,
381382
contentType: str = None,
382383
) -> NoneType:
383384
"""Route.fulfill
@@ -394,13 +395,19 @@ def fulfill(
394395
Optional response headers. Header values will be converted to a string.
395396
body : Optional[str, bytes]
396397
Optional response body.
398+
path : Optional[str, pathlib.Path]
399+
Optional file path to respond with. The content type will be inferred from file extension. If `path` is a relative path, then it is resolved relative to current working directory.
397400
contentType : Optional[str]
398401
If set, equals to setting `Content-Type` response header.
399402
"""
400403
return mapping.from_maybe_impl(
401404
self._sync(
402405
self._impl_obj.fulfill(
403-
status=status, headers=headers, body=body, contentType=contentType
406+
status=status,
407+
headers=headers,
408+
body=body,
409+
path=path,
410+
contentType=contentType,
404411
)
405412
)
406413
)

tests/conftest.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@
1313
# limitations under the License.
1414

1515
import asyncio
16+
import io
1617
import sys
1718

1819
import pytest
20+
from PIL import Image
21+
from pixelmatch import pixelmatch
22+
from pixelmatch.contrib.PIL import from_PIL_to_raw_data
1923

2024
from playwright import async_playwright
25+
from playwright.path_utils import get_file_dirname
2126

2227
from .server import test_server
2328
from .utils import utils as utils_object
2429

30+
_dirname = get_file_dirname()
2531

2632
# Will mark all the tests as async
2733
def pytest_collection_modifyitems(items):
@@ -213,3 +219,25 @@ def pytest_addoption(parser):
213219
default=False,
214220
help="Run tests in headful mode.",
215221
)
222+
223+
224+
@pytest.fixture(scope="session")
225+
def assert_to_be_golden(browser_name: str):
226+
def compare(received_raw: bytes, golden_name: str):
227+
golden_file = (_dirname / f"golden-{browser_name}" / golden_name).read_bytes()
228+
received_image = Image.open(io.BytesIO(received_raw))
229+
golden_image = Image.open(io.BytesIO(golden_file))
230+
231+
if golden_image.size != received_image.size:
232+
pytest.fail("Image size differs to golden image")
233+
return
234+
diff_pixels = pixelmatch(
235+
from_PIL_to_raw_data(received_image),
236+
from_PIL_to_raw_data(golden_image),
237+
golden_image.size[0],
238+
golden_image.size[1],
239+
threshold=0.2,
240+
)
241+
assert diff_pixels == 0
242+
243+
return compare
6.63 KB
Loading

tests/golden-chromium/mock-svg.png

257 Bytes
Loading
5.86 KB
Loading

tests/golden-firefox/mock-svg.png

206 Bytes
Loading
6.63 KB
Loading

tests/golden-webkit/mock-svg.png

323 Bytes
Loading

0 commit comments

Comments
 (0)