Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions playwright/async_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
MousePosition,
PdfMargins,
ProxyServer,
RecordHarOptions,
RequestFailure,
ResourceTiming,
SelectOption,
Expand Down Expand Up @@ -5820,6 +5821,7 @@ async def newContext(
defaultBrowserType: str = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> "BrowserContext":
"""Browser.newContext

Expand Down Expand Up @@ -5864,6 +5866,8 @@ async def newContext(
Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. Make sure to await `browserContext.close` for videos to be saved.
videoSize : Optional[{"width": int, "height": int}]
Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
recordHar : Optional[{"omitContent": Optional[bool], "path": str}]
Enables HAR recording for all pages into `har.path` file. If not specified, the HAR is not recorded. Make sure to await `browserContext.close` for the HAR to be saved.

Returns
-------
Expand Down Expand Up @@ -5891,6 +5895,7 @@ async def newContext(
defaultBrowserType=defaultBrowserType,
videosPath=videosPath,
videoSize=videoSize,
recordHar=recordHar,
)
)

Expand All @@ -5916,6 +5921,7 @@ async def newPage(
defaultBrowserType: str = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> "Page":
"""Browser.newPage

Expand Down Expand Up @@ -5961,6 +5967,8 @@ async def newPage(
Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. Make sure to await `page.close` for videos to be saved.
videoSize : Optional[{"width": int, "height": int}]
Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
recordHar : Optional[{"omitContent": Optional[bool], "path": str}]
Enables HAR recording for all pages into `har.path` file. If not specified, the HAR is not recorded. Make sure to await `page.close` for the HAR to be saved.

Returns
-------
Expand Down Expand Up @@ -5988,6 +5996,7 @@ async def newPage(
defaultBrowserType=defaultBrowserType,
videosPath=videosPath,
videoSize=videoSize,
recordHar=recordHar,
)
)

Expand Down Expand Up @@ -6154,6 +6163,7 @@ async def launchPersistentContext(
chromiumSandbox: bool = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> "BrowserContext":
"""BrowserType.launchPersistentContext

Expand Down Expand Up @@ -6228,6 +6238,8 @@ async def launchPersistentContext(
Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. Make sure to await `browserContext.close` for videos to be saved.
videoSize : Optional[{"width": int, "height": int}]
Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
recordHar : Optional[{"omitContent": Optional[bool], "path": str}]
Enables HAR recording for all the pages into `har.path` file. If not specified, HAR is not recorded. Make sure to await `page.close` for HAR to be saved.

Returns
-------
Expand Down Expand Up @@ -6270,6 +6282,7 @@ async def launchPersistentContext(
chromiumSandbox=chromiumSandbox,
videosPath=videosPath,
videoSize=videoSize,
recordHar=recordHar,
)
)

Expand Down
3 changes: 3 additions & 0 deletions playwright/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
Credentials,
Geolocation,
IntSize,
RecordHarOptions,
locals_to_params,
)
from playwright.network import serialize_headers
Expand Down Expand Up @@ -88,6 +89,7 @@ async def newContext(
defaultBrowserType: str = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> BrowserContext:
params = locals_to_params(locals())
# Python is strict in which variables gets passed to methods. We get this
Expand Down Expand Up @@ -128,6 +130,7 @@ async def newPage(
defaultBrowserType: str = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> Page:
params = locals_to_params(locals())
# Python is strict in which variables gets passed to methods. We get this
Expand Down
2 changes: 2 additions & 0 deletions playwright/browser_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
Geolocation,
IntSize,
ProxyServer,
RecordHarOptions,
locals_to_params,
not_installed_error,
)
Expand Down Expand Up @@ -108,6 +109,7 @@ async def launchPersistentContext(
chromiumSandbox: bool = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> BrowserContext:
userDataDir = str(Path(userDataDir))
params = locals_to_params(locals())
Expand Down
5 changes: 5 additions & 0 deletions playwright/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ class PdfMargins(TypedDict):
left: Optional[Union[str, int]]


class RecordHarOptions(TypedDict):
omitContent: Optional[bool]
path: str


DeviceDescriptor = TypedDict(
"DeviceDescriptor",
{
Expand Down
13 changes: 13 additions & 0 deletions playwright/sync_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
MousePosition,
PdfMargins,
ProxyServer,
RecordHarOptions,
RequestFailure,
ResourceTiming,
SelectOption,
Expand Down Expand Up @@ -6056,6 +6057,7 @@ def newContext(
defaultBrowserType: str = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> "BrowserContext":
"""Browser.newContext

Expand Down Expand Up @@ -6100,6 +6102,8 @@ def newContext(
Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. Make sure to await `browserContext.close` for videos to be saved.
videoSize : Optional[{"width": int, "height": int}]
Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
recordHar : Optional[{"omitContent": Optional[bool], "path": str}]
Enables HAR recording for all pages into `har.path` file. If not specified, the HAR is not recorded. Make sure to await `browserContext.close` for the HAR to be saved.

Returns
-------
Expand Down Expand Up @@ -6128,6 +6132,7 @@ def newContext(
defaultBrowserType=defaultBrowserType,
videosPath=videosPath,
videoSize=videoSize,
recordHar=recordHar,
)
)
)
Expand All @@ -6154,6 +6159,7 @@ def newPage(
defaultBrowserType: str = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> "Page":
"""Browser.newPage

Expand Down Expand Up @@ -6199,6 +6205,8 @@ def newPage(
Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. Make sure to await `page.close` for videos to be saved.
videoSize : Optional[{"width": int, "height": int}]
Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
recordHar : Optional[{"omitContent": Optional[bool], "path": str}]
Enables HAR recording for all pages into `har.path` file. If not specified, the HAR is not recorded. Make sure to await `page.close` for the HAR to be saved.

Returns
-------
Expand Down Expand Up @@ -6227,6 +6235,7 @@ def newPage(
defaultBrowserType=defaultBrowserType,
videosPath=videosPath,
videoSize=videoSize,
recordHar=recordHar,
)
)
)
Expand Down Expand Up @@ -6396,6 +6405,7 @@ def launchPersistentContext(
chromiumSandbox: bool = None,
videosPath: str = None,
videoSize: IntSize = None,
recordHar: RecordHarOptions = None,
) -> "BrowserContext":
"""BrowserType.launchPersistentContext

Expand Down Expand Up @@ -6470,6 +6480,8 @@ def launchPersistentContext(
Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. Make sure to await `browserContext.close` for videos to be saved.
videoSize : Optional[{"width": int, "height": int}]
Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size.
recordHar : Optional[{"omitContent": Optional[bool], "path": str}]
Enables HAR recording for all the pages into `har.path` file. If not specified, HAR is not recorded. Make sure to await `page.close` for HAR to be saved.

Returns
-------
Expand Down Expand Up @@ -6513,6 +6525,7 @@ def launchPersistentContext(
chromiumSandbox=chromiumSandbox,
videosPath=videosPath,
videoSize=videoSize,
recordHar=recordHar,
)
)
)
Expand Down
3 changes: 0 additions & 3 deletions scripts/expected_api_mismatch.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,4 @@ Parameter not implemented: BrowserContext.waitForEvent(optionsOrPredicate=)
# 1.6 Todo
Parameter not implemented: Browser.newPage(proxy=)
Parameter not implemented: Browser.newContext(proxy=)
Parameter not implemented: Browser.newPage(recordHar=)
Parameter not implemented: Browser.newContext(recordHar=)
Method not implemented: WebSocket.url
Parameter not implemented: BrowserType.launchPersistentContext(recordHar=)
2 changes: 1 addition & 1 deletion scripts/generate_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def return_value(value: Any) -> List[str]:
from playwright.element_handle import ElementHandle as ElementHandleImpl
from playwright.file_chooser import FileChooser as FileChooserImpl
from playwright.frame import Frame as FrameImpl
from playwright.helper import ConsoleMessageLocation, Credentials, MousePosition, Error, FilePayload, SelectOption, RequestFailure, Viewport, DeviceDescriptor, IntSize, FloatRect, Geolocation, ProxyServer, PdfMargins, ResourceTiming
from playwright.helper import ConsoleMessageLocation, Credentials, MousePosition, Error, FilePayload, SelectOption, RequestFailure, Viewport, DeviceDescriptor, IntSize, FloatRect, Geolocation, ProxyServer, PdfMargins, ResourceTiming, RecordHarOptions
from playwright.input import Keyboard as KeyboardImpl, Mouse as MouseImpl, Touchscreen as TouchscreenImpl
from playwright.js_handle import JSHandle as JSHandleImpl
from playwright.network import Request as RequestImpl, Response as ResponseImpl, Route as RouteImpl
Expand Down
3 changes: 3 additions & 0 deletions tests/assets/har.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<title>HAR Page</title>
<link rel='stylesheet' href='./one-style.css'>
<div>hello, world!</div>
62 changes: 62 additions & 0 deletions tests/async/test_har.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright (c) Microsoft Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import base64
import json
import os


async def test_should_work(browser, server, tmpdir):
path = os.path.join(tmpdir, "log.har")
context = await browser.newContext(recordHar={"path": path})
page = await context.newPage()
await page.goto(server.EMPTY_PAGE)
await context.close()
with open(path) as f:
data = json.load(f)
assert "log" in data


async def test_should_omit_content(browser, server, tmpdir):
path = os.path.join(tmpdir, "log.har")
context = await browser.newContext(recordHar={"path": path, "omitContent": True})
page = await context.newPage()
await page.goto(server.PREFIX + "/har.html")
await context.close()
with open(path) as f:
data = json.load(f)
assert "log" in data
log = data["log"]

content1 = log["entries"][0]["response"]["content"]
assert "text" not in content1


async def test_should_include_content(browser, server, tmpdir):
path = os.path.join(tmpdir, "log.har")
context = await browser.newContext(recordHar={"path": path})
page = await context.newPage()
await page.goto(server.PREFIX + "/har.html")
await context.close()
with open(path) as f:
data = json.load(f)
assert "log" in data
log = data["log"]

content1 = log["entries"][0]["response"]["content"]
print(content1)
assert content1["encoding"] == "base64"
assert content1["mimeType"] == "text/html"
s = base64.b64decode(content1["text"]).decode()
assert "HAR Page" in s
1 change: 1 addition & 0 deletions tests/async/test_interception.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import asyncio
import json

Expand Down
14 changes: 14 additions & 0 deletions tests/async/test_issues.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# Copyright (c) Microsoft Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest


Expand Down
62 changes: 62 additions & 0 deletions tests/sync/test_har.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright (c) Microsoft Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import base64
import json
import os


def test_should_work(browser, server, tmpdir):
path = os.path.join(tmpdir, "log.har")
context = browser.newContext(recordHar={"path": path})
page = context.newPage()
page.goto(server.EMPTY_PAGE)
context.close()
with open(path) as f:
data = json.load(f)
assert "log" in data


def test_should_omit_content(browser, server, tmpdir):
path = os.path.join(tmpdir, "log.har")
context = browser.newContext(recordHar={"path": path, "omitContent": True})
page = context.newPage()
page.goto(server.PREFIX + "/har.html")
context.close()
with open(path) as f:
data = json.load(f)
assert "log" in data
log = data["log"]

content1 = log["entries"][0]["response"]["content"]
assert "text" not in content1


def test_should_include_content(browser, server, tmpdir):
path = os.path.join(tmpdir, "log.har")
context = browser.newContext(recordHar={"path": path})
page = context.newPage()
page.goto(server.PREFIX + "/har.html")
context.close()
with open(path) as f:
data = json.load(f)
assert "log" in data
log = data["log"]

content1 = log["entries"][0]["response"]["content"]
print(content1)
assert content1["encoding"] == "base64"
assert content1["mimeType"] == "text/html"
s = base64.b64decode(content1["text"]).decode()
assert "HAR Page" in s