[dotnet] Add examples for BiDi W3C Browsing Context#2735
Conversation
Adds .NET examples for the BiDi Browsing Context module: creating, closing, navigating, and traversing history for browsing contexts, capturing screenshots, printing, setting the viewport, handling user prompts, and subscribing to browsing-context events. Credit to @nvborisenko for the original work in #1940. That PR was written against a pre-release shape of the .NET BiDi API (OpenQA.Selenium.BiDi.Modules.BrowsingContext) that has since been restructured upstream, so it no longer builds. This PR carries the same examples updated for the current OpenQA.Selenium.BiDi.BrowsingContext API (Selenium.WebDriver 4.46.0): flattened namespace, ImmutableArray-backed results, and IEventSource<T>.SubscribeAsync instead of OnXAsync event methods. It also fixes a syntax error in BaseTest.cs, enables UseWebSocketUrl unconditionally so BiDi actually works via BaseChromeTest, and fixes two timing races (HandleUserPrompt, NavigateForward/TraverseHistory) found by running the tests against real Chrome/Firefox rather than just compiling them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR Summary by QodoAdd .NET BiDi BrowsingContext examples and enable WebSocket BiDi mode
AI Description
Diagram
High-Level Assessment
Files changed (19)
|
✅ Deploy Preview for selenium-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Code Review by Qodo
Context used✅ Compliance rules (platform):
10 rules 1. Partial accessibility mismatch
|
…ales) Adds a CSharp tab, referencing the new examples/dotnet/SeleniumDocs/BiDi/ BrowsingContext example files, to every code tabpane in webdriver/bidi/w3c/browsing_context across en, ja, pt-br, and zh-cn. These locales mirror the English page's tabpane structure exactly, so the same gh-codeblock references apply to each. Line ranges were derived by brace-matching each referenced method body and validated against the current file contents, matching the file's existing convention of pointing at just the illustrative body of each method (excluding the signature and braces). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Code review by qodo was updated up to the latest commit 2cdf2b0 |
Fixes real issues flagged by Qodo's automated review, verified against the current commit before applying: - Fix a gh-codeblock line reference broken by this PR's own BaseTest.cs edit: adding `options.UseWebSocketUrl = true;` shifted every subsequent line by one, so the four drivers/_index.*.md pages that reference BaseTest.cs#L48 (the "driver = new ChromeDriver(options);" line) were pointing at a lone closing brace. Updated all four locales to #L49. - Make the BiDi event-subscription examples idempotent: SubscribeAsync handlers used TaskCompletionSource.SetResult, which throws if the same event fires more than once during the subscription window. Switched to TrySetResult (wrapped in a lambda, since TrySetResult's bool return isn't method-group-compatible with the Action<T> the API expects). - Guard CaptureElementScreenshot's node lookup with an assertion before indexing, so a failed locator produces a clear failure message instead of an IndexOutOfRangeException. - Replace the positional `contexts[1]` assertion in GetAllTopLevelBrowsingContexts with a containment check, since GetTreeAsync's ordering isn't a documented contract. Updated the browsing_context.*.md gh-codeblock line ranges for the two files whose line counts changed as a result (CaptureScreenshot.cs, GetTree.cs), across all four locales, and re-verified every dotnet gh-codeblock reference site-wide (736 total) against the actual file contents. Qodo also flagged a "partial accessibility mismatch" (public vs internal partial class declarations) as a compile error requiring action. This is incorrect for this code: `dotnet build` succeeds and all 31 tests pass locally, both before and after this commit; C# allows secondary partial declarations to omit the access modifier without conflict. Not changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Code review by qodo was updated up to the latest commit 550631c |
Qodo's re-review (after the previous fix commit) flagged that
UserPromptClosedEvent waits for the closed event without ever explicitly
closing the prompt, calling it implicit/behavior-dependent.
Tried making it deterministic by explicitly calling HandleUserPromptAsync
after waiting for UserPromptOpened. That actually broke the test:
OpenQA.Selenium.BiDi.BiDiException: no such alert: No dialog is showing.
Chrome's default unhandledPromptBehavior ("dismiss and notify") already
closes the prompt on its own, faster than an explicit BiDi call can act on
it. This is a known, deliberate constraint in this codebase already:
HandleUserPrompt.cs uses Firefox specifically ("temporary use firefox
because of chrome automatically handle prompts") whenever the example
needs to demonstrate an explicit close.
Reverted the explicit-close attempt and documented the actual mechanism in
a comment instead: Chrome's own auto-dismiss is what raises the event
here, with a pointer to HandleUserPrompt.cs for the explicit-close
pattern. Verified the full 31-test suite passes with this change, and
updated the shifted gh-codeblock line reference in all four locales.
Qodo's other two remaining findings on this PR were addressed in the
previous commit's message: "Partial accessibility mismatch" is a false
positive (dotnet build and all tests pass with this exact partial-class
pattern), and "Two browsers started" is a pre-existing structural choice
from the original PR (#1940), not introduced here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Code review by qodo was updated up to the latest commit 1d4d679 |
Implements Qodo's suggested remediation in full this time: subscribe to UserPromptOpened, wait for it, then explicitly call HandleUserPromptAsync, tolerating the case where Chrome's default unhandled-prompt behavior has already closed the dialog (BiDiException: "no such alert"). This demonstrates the explicit-close pattern while staying robust under Chrome's race, verified by running the test 3x plus the full 31-test suite with no flakiness. BiDiException carries no structured error code (just a message), so the catch matches on message text rather than a dedicated exception type. Adding `using OpenQA.Selenium.BiDi;` (needed for BiDiException) shifted every line in the file by one, so both UserPromptOpenedEvent and UserPromptClosedEvent's gh-codeblock references needed updating, across all four locales. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Code review by qodo was updated up to the latest commit 5976832 |
|
Code review by qodo was updated up to the latest commit cb2c9ee |
Matches the Java, Python, and Ruby examples, which all create a dedicated temp subdirectory (Files.createTempDirectory, tempfile.TemporaryDirectory, Dir.mktmpdir) rather than passing the shared OS temp root itself as --profile-root. The shared root is the likely cause of geckodriver exiting immediately on Windows CI (consistently failing on trunk's own scheduled runs, unrelated to any specific PR). Also reorders Cleanup() to quit the driver before deleting the directory, since deleting while Firefox still holds files open in it raced intermittently. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Code review by qodo was updated up to the latest commit cd561d6 |
…y listing
The previous fix still failed on Windows CI with the identical crash
("Driver service process exited unexpectedly before initialization
completed"), and every other FirefoxDriver launch in the same run
succeeded, isolating the problem to the ProfileRoot value itself rather
than to sharing vs. not sharing the OS temp root. Both the original code
and the previous fix left a trailing separator on that path (Windows'
Path.GetTempPath() already ends in one, and the prior fix re-added one
explicitly), which is a known Windows command-line quoting hazard when a
backslash immediately precedes a closing quote.
Stop building a path with a trailing separator, and switch the assertion
to list GetTempDirectory()'s contents and check the profile's leaf
directory name is among them, mirroring Python's
`profile_name in os.listdir(temp_dir)` and Ruby's substring-based check
instead of exact string reconstruction that assumed a specific
separator style.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Code review by qodo was updated up to the latest commit 39ff8cb |
Description
Adds .NET examples for the BiDi Browsing Context module: creating, closing, navigating, and traversing history for browsing contexts, capturing screenshots, printing, setting the viewport, handling user prompts, and subscribing to browsing-context events. Also wires these examples into the
webdriver/bidi/w3c/browsing_contextdocs (aCSharptab in every code sample, acrossen,ja,pt-br, andzh-cn— the translated pages mirror the English page's tabpane structure exactly, so the same references apply to each).Credit to @nvborisenko for the original work in #1940. That PR was written against a pre-release shape of the .NET BiDi API (
OpenQA.Selenium.BiDi.Modules.BrowsingContext) that has since been restructured upstream, so it no longer compiles. This PR carries the same set of examples updated for the currentOpenQA.Selenium.BiDi.BrowsingContextAPI (Selenium.WebDriver4.46.0): flattened namespace,ImmutableArray-backed results, andIEventSource<T>.SubscribeAsyncinstead ofOnXAsyncevent methods. It also:BaseTest.cs(comma instead of semicolon).options.UseWebSocketUrl = trueout of the version-gated branch inBaseTest.cs, sinceBaseChromeTestcallsStartDriver()with no version and the flag would otherwise never be set, so BiDi would never actually be enabled.HandleUserPromptneededUnhandledPromptBehavior.Ignoreon Firefox so the BiDi call could handle the prompt instead of the driver auto-dismissing it, andNavigateForward/TraverseHistoryneeded to poll for the URL sinceTraverseHistoryAsyncdoesn't block until the navigation completes.Note:
gh-codeblockresolves against the GitHub API for thetrunkbranch, so the new doc references will only render real code once this PR itself is merged (a local./build-site.shagainst an unmerged branch can't verify that content, only that the shortcode syntax and paths are well-formed — which I did verify, including brace-matching every referenced line range against the actual method bodies).Motivation and Context
#1940 has been open since September 2024 and no longer builds against the current Selenium.WebDriver release. This PR gets the same example coverage into a mergeable, passing state, wires it into the docs, and does all of this without touching the original PR.
Types of changes
Checklist
All 31 tests in
examples/dotnet/SeleniumDocs/BiDi/BrowsingContextpass locally againstSelenium.WebDriver4.46.0 (verified twice to rule out flakiness)../build-site.shbuilds cleanly with Hugo 0.148.2 (matchingREADME.md's recommended version) across all 4 locales.🤖 Generated with Claude Code