chore(roll): update driver to ac7cdd4bd, port new APIs, add tests#3102
Open
Skn0tt wants to merge 5 commits into
Open
chore(roll): update driver to ac7cdd4bd, port new APIs, add tests#3102Skn0tt wants to merge 5 commits into
Skn0tt wants to merge 5 commits into
Conversation
Driver SHA: ac7cdd4bdf15f90fe7229243be6b35a53e0296d1 (v1.61.0-next) New APIs: - APIResponse.security_details / .server_addr - Credentials class (WebAuthn) + BrowserContext.credentials - WebStorage class + Page.local_storage / .session_storage - Screencast.start(size=), .show_actions(cursor=), ScreencastFrame.timestamp - BrowserType.connect_over_cdp(artifacts_dir=) Also: - Stop forcing options-bag properties to required=False in documentation_provider.py (Credentials.create(rp_id=) was the only case affected) - Update rolling skill to use driver/playwright-src - 37 new tests (async + sync)
Skn0tt
commented
Jun 10, 2026
| option = self_or_override(option) | ||
| option_name = to_snake_case(name_or_alias(option)) | ||
| option["name"] = option_name | ||
| option["required"] = False |
Member
Author
There was a problem hiding this comment.
in credentials.create(rp_id), this was making rp_id optional, which is incorrect.
There was a problem hiding this comment.
Pull request overview
Rolls the bundled Playwright driver to a new upstream commit (ac7cdd4b…, v1.61.0-next) and ports newly added upstream APIs into the Python implementation, generated surfaces, and test suite.
Changes:
- Ported new API surface:
APIResponse.security_details()/.server_addr(), WebAuthnCredentialsviaBrowserContext.credentials,WebStorageviaPage.local_storage/.session_storage, and new Screencast options/fields (start(size=),show_actions(cursor=),ScreencastFrame.timestamp). - Extended CDP connection API with
BrowserType.connect_over_cdp(artifacts_dir=)and updated API generation inputs/types (ScreencastSize,VirtualCredential). - Updated driver pin + docs, and adjusted documentation generation to stop forcing all options-bag properties to optional.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/sync/test_screencast.py | Adds sync tests for new Screencast size/cursor/timestamp APIs. |
| tests/sync/test_page_web_storage.py | New sync tests for Page.local_storage / session_storage WebStorage access. |
| tests/sync/test_browsercontext_credentials.py | New sync tests for BrowserContext.credentials WebAuthn seeding APIs. |
| tests/async/test_screencast.py | Adds async tests for new Screencast size/cursor/timestamp APIs. |
| tests/async/test_page_web_storage.py | New async tests for Page.local_storage / session_storage WebStorage access. |
| tests/async/test_browsercontext_credentials.py | New async tests for BrowserContext.credentials WebAuthn seeding APIs. |
| scripts/generate_api.py | Updates API generation imports/registrations for newly ported impl classes and structures. |
| scripts/documentation_provider.py | Stops force-marking options-bag properties as optional (fixes requiredness for rp_id). |
| scripts/build_driver.sh | Updates driver source reference comment to main (driver pin still enforced via DRIVER_SHA). |
| README.md | Updates embedded browser version markers to match the rolled driver. |
| playwright/sync_api/_generated.py | Regenerates sync surface: adds new APIs, types, and doc updates. |
| playwright/sync_api/init.py | Re-exports new public TypedDict structures (ScreencastSize, VirtualCredential). |
| playwright/async_api/_generated.py | Regenerates async surface: adds new APIs, types, and doc updates. |
| playwright/async_api/init.py | Re-exports new public TypedDict structures (ScreencastSize, VirtualCredential). |
| playwright/_impl/_web_storage.py | Introduces WebStorage channel wrapper implementation. |
| playwright/_impl/_screencast.py | Adds Screencast size/cursor params and propagates timestamp into frames. |
| playwright/_impl/_page.py | Adds local_storage / session_storage properties backed by WebStorage instances. |
| playwright/_impl/_fetch.py | Exposes APIResponse.security_details() / .server_addr() from initializer data. |
| playwright/_impl/_credentials.py | Introduces Credentials channel wrapper implementation for WebAuthn. |
| playwright/_impl/_browser_type.py | Adds artifactsDir plumb-through for CDP connect. |
| playwright/_impl/_browser_context.py | Adds credentials property backed by new Credentials impl. |
| playwright/_impl/_api_structures.py | Adds ScreencastSize and VirtualCredential structures; extends ScreencastFrame with timestamp. |
| DRIVER_SHA | Updates pinned upstream driver commit hash. |
| .claude/skills/playwright-roll/SKILL.md | Updates roll skill docs to reference driver/playwright-src checkout path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+69
to
+75
| def test_show_actions_should_accept_cursor_param(page: Page) -> None: | ||
| page.screencast.start(on_frame=lambda f: None) | ||
| with page.screencast.show_actions(duration=100, cursor="pointer"): | ||
| pass | ||
| with page.screencast.show_actions(duration=100, cursor="none"): | ||
| pass | ||
| page.screencast.stop() |
Comment on lines
+56
to
+66
| def test_start_should_accept_size_param(page: Page, server: Server) -> None: | ||
| received: list = [] | ||
| size: ScreencastSize = {"width": 800, "height": 600} | ||
| page.screencast.start(on_frame=lambda f: received.append(f), size=size) | ||
| page.goto(server.EMPTY_PAGE) | ||
| page.screenshot() | ||
| deadline = time.time() + 10 | ||
| while not received and time.time() < deadline: | ||
| page.wait_for_timeout(100) | ||
| page.screencast.stop() | ||
| assert len(received) >= 1 |
Comment on lines
+78
to
+88
| def test_frames_should_include_timestamp(page: Page, server: Server) -> None: | ||
| received: list = [] | ||
| page.screencast.start(on_frame=lambda f: received.append(f)) | ||
| page.goto(server.EMPTY_PAGE) | ||
| page.screenshot() | ||
| deadline = time.time() + 10 | ||
| while not received and time.time() < deadline: | ||
| page.wait_for_timeout(100) | ||
| page.screencast.stop() | ||
| assert len(received) >= 1 | ||
| assert received[0]["timestamp"] > 0 |
Comment on lines
+75
to
+89
| async def test_start_should_accept_size_param(page: Page, server: Server) -> None: | ||
| received: list = [] | ||
| event = asyncio.Event() | ||
|
|
||
| def on_frame(frame: ScreencastFrame) -> None: | ||
| received.append(frame) | ||
| event.set() | ||
|
|
||
| size: ScreencastSize = {"width": 800, "height": 600} | ||
| await page.screencast.start(on_frame=on_frame, size=size) | ||
| await page.goto(server.EMPTY_PAGE) | ||
| await page.screenshot() | ||
| await asyncio.wait_for(event.wait(), timeout=10) | ||
| await page.screencast.stop() | ||
| assert len(received) >= 1 |
Comment on lines
+103
to
+117
| async def test_frames_should_include_timestamp(page: Page, server: Server) -> None: | ||
| received: list = [] | ||
| event = asyncio.Event() | ||
|
|
||
| def on_frame(frame: ScreencastFrame) -> None: | ||
| received.append(frame) | ||
| event.set() | ||
|
|
||
| await page.screencast.start(on_frame=on_frame) | ||
| await page.goto(server.EMPTY_PAGE) | ||
| await page.screenshot() | ||
| await asyncio.wait_for(event.wait(), timeout=10) | ||
| await page.screencast.stop() | ||
| assert len(received) >= 1 | ||
| assert received[0]["timestamp"] > 0 |
Comment on lines
+27
to
+31
| async def test_local_storage_set_and_get_item(page: Page, server: Server) -> None: | ||
| await page.goto(server.EMPTY_PAGE) | ||
| await page.evaluate("() => localStorage.setItem('foo', 'bar')") | ||
| value = await page.local_storage.get_item("foo") | ||
| assert value == "bar" |
Comment on lines
+34
to
+41
| async def test_local_storage_items(page: Page, server: Server) -> None: | ||
| await page.goto(server.EMPTY_PAGE) | ||
| await page.evaluate("() => localStorage.setItem('a', '1')") | ||
| await page.evaluate("() => localStorage.setItem('b', '2')") | ||
| items = await page.local_storage.items() | ||
| assert len(items) == 2 | ||
| assert {"name": "a", "value": "1"} in items | ||
| assert {"name": "b", "value": "2"} in items |
Comment on lines
+60
to
+64
| async def test_session_storage_set_and_get_item(page: Page, server: Server) -> None: | ||
| await page.goto(server.EMPTY_PAGE) | ||
| await page.evaluate("() => sessionStorage.setItem('foo', 'bar')") | ||
| value = await page.session_storage.get_item("foo") | ||
| assert value == "bar" |
Comment on lines
+31
to
+39
| result = creds.create( | ||
| rp_id="localhost", | ||
| id="test-credential-id", | ||
| private_key="private-key-data", | ||
| public_key="public-key-data", | ||
| ) | ||
| assert result["id"] == "test-credential-id" | ||
| assert result["rpId"] == "localhost" | ||
|
|
Comment on lines
+34
to
+42
| result = await creds.create( | ||
| rp_id="localhost", | ||
| id="test-credential-id", | ||
| private_key="private-key-data", | ||
| public_key="public-key-data", | ||
| ) | ||
| assert result["id"] == "test-credential-id" | ||
| assert result["rpId"] == "localhost" | ||
|
|
- WebStorage tests: seed via dedicated API (set_item) instead of evaluate - Credentials tests: use auto-generated keys instead of fake placeholders - Screencast tests: replace size+timestamp test with upstream's onFrame receives viewport size; add ensureSomeFrames pattern; remove inconsistent try/finally cleanup
…change
Upstream commit ac7cdd4bd changed FrameExpectResult from {matches, received}
to void — expect returns nothing on success and throws ExpectError on failure.
Updates:
- _assertions.py: _expect_impl now catches driver Error and uses its message
directly; removes unused parse_value and FrameExpectResult imports.
- _frame.py: guard against None result from _expect channel call; change
return type to dict (callers don't use typed fields anymore).
- _locator.py: change _expect return type to dict for consistency.
- tests/{sync,async}/test_assertions.py: update 21 error-message assertions to
match the new upstream format (e.g. 'LocatorAssertions.to_have_text: Expect
failed\nCall log:\n - Expect "to_have_text" with timeout 300ms\n…' instead
of the old Python-formatted "Locator expected to …" / "Actual value: …").
Upstream stopped recording "Wait for event" as separate trace actions. Remove the corresponding patterns from the two trace viewer tests so they match the actual 5 (context managers) and 1 (load state) actions now produced by the driver.
WebKit may report viewportWidth=1002 (instead of 1000) on the first screencast frame. Use `any()` check instead of iterating all frames, and increase rAF cycles from 3 to 100 for more reliable frame generation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This rolls the driver to
ac7cdd4bdf15f90fe7229243be6b35a53e0296d1(latest main, v1.61.0-next) and ports the new upstream APIs:APIResponse.security_details/.server_addrCredentialsclass (WebAuthn) +BrowserContext.credentialsWebStorageclass +Page.local_storage/.session_storageScreencast.start(size=),.show_actions(cursor=),ScreencastFrame.timestampBrowserType.connect_over_cdp(artifacts_dir=)Also removes the
option["required"] = Falseline indocumentation_provider.pythat was forcing all options-bag properties to optional.Credentials.create(rp_id=)was the only case affected — it's now correctly required.The rolling skill is updated to reference
driver/playwright-srcinstead of~/code/playwright.37 new tests (async + sync).