Skip to content

[py]: fix WebView2 and target issues related to CDP and BiDi #16140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 11, 2025

Conversation

nxs7
Copy link
Contributor

@nxs7 nxs7 commented Aug 7, 2025

User description

💥 What does this PR do?

This PR addresses two issues related to the CDP and BiDi functionalities in the selenium.webdriver.remote.webdriver.WebDriver class.

  • WebView2 Identification
    • In WebDriver._get_cdp_details, the current implementation does not properly account for WebView2 when determining whether the browser is Edge. This causes crashes when using CDP or BiDi features with WebView2-based applications.
  • Target locating
    • In WebDriver.start_devtools and WebDriver.bidi_connection, the current implementation hard codes the attachment to the first target returned by the CDP method Target.getTargets, resulting in the following two issues:
      • If multiple pages are open, a random page is attached;
      • If only one page is open but it contains service workers or iframes, one of these may be attached instead, causing crashes in subsequent CDP method calls.

Minimal reproduction code for target locating:
Case 1: Multiple pages

from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.google.com/")
driver.switch_to.new_window()
driver.get("https://www.facebook.com/")
devtools, connection = driver.start_devtools()
current_index, entries = connection.execute(devtools.page.get_navigation_history())
print(entries[current_index].url) # Randomly prints "https://www.google.com/" or "https://www.facebook.com/"
driver.quit()

Case 2: Single page with service workers or iframes

from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.youtube.com/")
devtools, connection = driver.start_devtools()
connection.execute(devtools.page.get_navigation_history()) # May crash with "method not found" error
driver.quit()

🔧 Implementation Notes

To address the target locating issue, this PR iterates through the targets returned, matching the target ID with the handle of the current window.

💡 Additional Considerations

In future implementations, the start_devtools and bidi_connection may receive an optional parameter specifying the window handle, enabling more precise attachment to a specific window.

🔄 Types of changes

  • Bug fix (backwards compatible)

PR Type

Bug fix


Description

  • Fix WebView2 browser identification in CDP connection setup

  • Fix target selection to use current window handle instead of first target

  • Prevent crashes when multiple pages or service workers are present

  • Ensure correct target attachment for CDP and BiDi connections


Diagram Walkthrough

flowchart LR
  A["WebDriver CDP/BiDi Request"] --> B["Get Available Targets"]
  B --> C["Match Target ID with Current Window Handle"]
  C --> D["Attach to Correct Target"]
  E["WebView2 Detection"] --> F["Use ms:edgeOptions for WebView2"]
Loading

File Walkthrough

Relevant files
Bug fix
webdriver.py
Fix target selection and WebView2 support                               

py/selenium/webdriver/remote/webdriver.py

  • Replace hardcoded first target selection with window handle matching
  • Add WebView2 browser name check for Edge options
  • Apply fix to both start_devtools and bidi_connection methods
+9/-3     

@CLAassistant
Copy link

CLAassistant commented Aug 7, 2025

CLA assistant check
All committers have signed the CLA.

@selenium-ci selenium-ci added the C-py Python Bindings label Aug 7, 2025
Copy link
Contributor

qodo-merge-pro bot commented Aug 7, 2025

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The target matching logic may fail if no target matches the current window handle, leaving target_id undefined and causing a NameError when passed to attach_to_target. A fallback mechanism or error handling should be considered.

for target in targets:
    if target.target_id == self.current_window_handle:
        target_id = target.target_id
        break
Logic Error

The conditional logic for Edge browser detection is malformed. The elif condition should include the assignment to debugger_address within its block, but the current structure places it outside the conditional.

elif self.caps.get("browserName") == "MicrosoftEdge" or self.caps.get("browserName") == "webview2":
    debugger_address = self.caps.get("ms:edgeOptions").get("debuggerAddress")

Copy link
Contributor

qodo-merge-pro bot commented Aug 7, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Add fallback for undefined target_id

Add a fallback mechanism when no target matches the current window handle.
Without this, target_id could remain undefined if no matching target is found,
leading to a runtime error.

py/selenium/webdriver/remote/webdriver.py [1214-1217]

+target_id = None
 for target in targets:
     if target.target_id == self.current_window_handle:
         target_id = target.target_id
         break
+if target_id is None:
+    target_id = targets[0].target_id if targets else None
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a potential UnboundLocalError if no matching target is found in the loop, which would leave target_id undefined and cause a runtime error.

Medium
  • Update

@navin772
Copy link
Member

navin772 commented Aug 7, 2025

@nxs7 Thanks for the contribution! The changes look good, have you tested this with webview2 and does it works as intended? How can I test it?

@nxs7
Copy link
Contributor Author

nxs7 commented Aug 7, 2025

Hello. Given that you're a Selenium developer, I hope it's not too bold to assume you already have Visual Studio with C# installed :)

Microsoft provides several WebView2 samples, including the MicrosoftEdge/WebView2Samples repository. Please clone the repository and navigate to either GettingStartedGuides/WPF_GettingStarted or GettingStartedGuides/WinForms_GettingStarted, then build the project. You may want to update the target framework first, as it is somewhat outdated.

After building the application, you can use the following code to reproduce the issue.

from selenium import webdriver
options = webdriver.EdgeOptions()
options.use_webview = True
options.binary_location = <path_to_your_application>
driver = webdriver.Edge(options=options)
driver.start_devtools() # Crashes with "variable not associated with value" error
driver.quit()

@navin772
Copy link
Member

navin772 commented Aug 11, 2025

@nxs7 I was able to get this working on a windows machine and with your fix, the mentioned error is no longer present.

But I wasn't able to get start_devtools to work with webview2 completely, it got stuck/hanged at this line:

targets = self._websocket_connection.execute(self._devtools.target.get_targets())

After digging a bit, I found that the websocket connection was getting closed (this behavior was flaky), adding a few retries did solve it. Note that this happens only with webview2 and not normal chrome/edge devtools connection.

Did you noticed any such issues with selenium and webview2?

@nxs7
Copy link
Contributor Author

nxs7 commented Aug 11, 2025

Nope, I've tested this on multiple machines with both WPF_GettingStarted and WinForms_GettingStarted, as well as several other real-world WebView2 applications. In all cases, the start_devtools returned successfully, and I was able to use the returned devtools and connection to execute CDP methods and get correct results. Could you try testing it on different machines to see if the issue persists?

@navin772
Copy link
Member

It is now working consistently after a restart! Spent a good amount of time debugging the previous error :(

Copy link
Member

@navin772 navin772 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@navin772 navin772 requested a review from cgoldberg August 11, 2025 13:49
Copy link
Contributor

@cgoldberg cgoldberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 tiny nitpick requested... other than that LGTM.

@nxs7 please make that small change and we will merge this.
thanks!

@navin772 navin772 merged commit 2bf42e9 into SeleniumHQ:trunk Aug 11, 2025
17 of 18 checks passed
@nxs7 nxs7 deleted the py_cdp_fix branch August 12, 2025 02:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants