Skip to content

[dotnet] [bidi] Extensible additional command data via options#17258

Draft
nvborisenko wants to merge 1 commit intoSeleniumHQ:trunkfrom
nvborisenko:bidi-command-extensiondata
Draft

[dotnet] [bidi] Extensible additional command data via options#17258
nvborisenko wants to merge 1 commit intoSeleniumHQ:trunkfrom
nvborisenko:bidi-command-extensiondata

Conversation

@nvborisenko
Copy link
Copy Markdown
Member

Spec:

Command = {
  id: js-uint,
  ...,
  Extensible
}

At the same time:

EmptyParams = {
   Extensible
}

🔗 Related Issues

Contributes to #16095

💥 What does this PR do?

This pull request updates the WebDriver BiDi (Bidirectional) command infrastructure to allow passing extension data with command objects. This change adds support for optional extension data (via JsonObject? extensionData) to various command classes and ensures that the extension data from options is consistently passed through when commands are executed. This makes the command system more flexible and extensible for future enhancements or custom data.

These changes collectively improve the extensibility of the BiDi command infrastructure, allowing for richer command customization and future protocol evolution.

🔄 Types of changes

  • New feature (non-breaking change which adds functionality and tests!)

@nvborisenko nvborisenko marked this pull request as draft March 25, 2026 21:36
@selenium-ci selenium-ci added the C-dotnet .NET Bindings label Mar 25, 2026
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add optional extensionData parameter to all BiDi command classes
• Enable passing extension data through command options to commands
• Update base Command class to support JSON extension data serialization
• Add ExtensionData property to CommandOptions base class
• Update all module methods to pass extension data from options to commands

Grey Divider

File Changes

1. dotnet/src/webdriver/BiDi/Command.cs ✨ Enhancement +12/-10

Base Command class refactored for extension data support

dotnet/src/webdriver/BiDi/Command.cs


2. dotnet/src/webdriver/BiDi/CommandOptions.cs ✨ Enhancement +4/-0

Add ExtensionData property to CommandOptions

dotnet/src/webdriver/BiDi/CommandOptions.cs


3. dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs ✨ Enhancement +8/-8

Pass extension data to browser commands

dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs


View more (71)
4. dotnet/src/webdriver/BiDi/Browser/CloseCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to CloseCommand

dotnet/src/webdriver/BiDi/Browser/CloseCommand.cs


5. dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to CreateUserContextCommand

dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs


6. dotnet/src/webdriver/BiDi/Browser/GetClientWindowsCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to GetClientWindowsCommand

dotnet/src/webdriver/BiDi/Browser/GetClientWindowsCommand.cs


7. dotnet/src/webdriver/BiDi/Browser/GetUserContextsCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to GetUserContextsCommand

dotnet/src/webdriver/BiDi/Browser/GetUserContextsCommand.cs


8. dotnet/src/webdriver/BiDi/Browser/RemoveUserContextCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to RemoveUserContextCommand

dotnet/src/webdriver/BiDi/Browser/RemoveUserContextCommand.cs


9. dotnet/src/webdriver/BiDi/Browser/SetDownloadBehaviorCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetDownloadBehaviorCommand

dotnet/src/webdriver/BiDi/Browser/SetDownloadBehaviorCommand.cs


10. dotnet/src/webdriver/BiDi/BrowsingContext/ActivateCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to ActivateCommand

dotnet/src/webdriver/BiDi/BrowsingContext/ActivateCommand.cs


11. dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs ✨ Enhancement +12/-12

Pass extension data to browsing context commands

dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs


12. dotnet/src/webdriver/BiDi/BrowsingContext/CaptureScreenshotCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to CaptureScreenshotCommand

dotnet/src/webdriver/BiDi/BrowsingContext/CaptureScreenshotCommand.cs


13. dotnet/src/webdriver/BiDi/BrowsingContext/CloseCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to CloseCommand

dotnet/src/webdriver/BiDi/BrowsingContext/CloseCommand.cs


14. dotnet/src/webdriver/BiDi/BrowsingContext/CreateCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to CreateCommand

dotnet/src/webdriver/BiDi/BrowsingContext/CreateCommand.cs


15. dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to GetTreeCommand

dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs


16. dotnet/src/webdriver/BiDi/BrowsingContext/HandleUserPromptCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to HandleUserPromptCommand

dotnet/src/webdriver/BiDi/BrowsingContext/HandleUserPromptCommand.cs


17. dotnet/src/webdriver/BiDi/BrowsingContext/LocateNodesCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to LocateNodesCommand

dotnet/src/webdriver/BiDi/BrowsingContext/LocateNodesCommand.cs


18. dotnet/src/webdriver/BiDi/BrowsingContext/NavigateCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to NavigateCommand

dotnet/src/webdriver/BiDi/BrowsingContext/NavigateCommand.cs


19. dotnet/src/webdriver/BiDi/BrowsingContext/PrintCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to PrintCommand

dotnet/src/webdriver/BiDi/BrowsingContext/PrintCommand.cs


20. dotnet/src/webdriver/BiDi/BrowsingContext/ReloadCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to ReloadCommand

dotnet/src/webdriver/BiDi/BrowsingContext/ReloadCommand.cs


21. dotnet/src/webdriver/BiDi/BrowsingContext/SetViewportCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetViewportCommand

dotnet/src/webdriver/BiDi/BrowsingContext/SetViewportCommand.cs


22. dotnet/src/webdriver/BiDi/BrowsingContext/TraverseHistoryCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to TraverseHistoryCommand

dotnet/src/webdriver/BiDi/BrowsingContext/TraverseHistoryCommand.cs


23. dotnet/src/webdriver/BiDi/Emulation/EmulationModule.cs ✨ Enhancement +13/-13

Pass extension data to emulation commands

dotnet/src/webdriver/BiDi/Emulation/EmulationModule.cs


24. dotnet/src/webdriver/BiDi/Emulation/SetForcedColorsModeThemeOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetForcedColorsModeThemeOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetForcedColorsModeThemeOverrideCommand.cs


25. dotnet/src/webdriver/BiDi/Emulation/SetGeolocationOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetGeolocationOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetGeolocationOverrideCommand.cs


26. dotnet/src/webdriver/BiDi/Emulation/SetLocaleOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetLocaleOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetLocaleOverrideCommand.cs


27. dotnet/src/webdriver/BiDi/Emulation/SetNetworkConditionsCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetNetworkConditionsCommand

dotnet/src/webdriver/BiDi/Emulation/SetNetworkConditionsCommand.cs


28. dotnet/src/webdriver/BiDi/Emulation/SetScreenOrientationOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetScreenOrientationOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetScreenOrientationOverrideCommand.cs


29. dotnet/src/webdriver/BiDi/Emulation/SetScreenSettingsOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetScreenSettingsOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetScreenSettingsOverrideCommand.cs


30. dotnet/src/webdriver/BiDi/Emulation/SetScriptingEnabledCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetScriptingEnabledCommand

dotnet/src/webdriver/BiDi/Emulation/SetScriptingEnabledCommand.cs


31. dotnet/src/webdriver/BiDi/Emulation/SetScrollbarTypeOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetScrollbarTypeOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetScrollbarTypeOverrideCommand.cs


32. dotnet/src/webdriver/BiDi/Emulation/SetTimezoneOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetTimezoneOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetTimezoneOverrideCommand.cs


33. dotnet/src/webdriver/BiDi/Emulation/SetTouchOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetTouchOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetTouchOverrideCommand.cs


34. dotnet/src/webdriver/BiDi/Emulation/SetUserAgentOverrideCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetUserAgentOverrideCommand

dotnet/src/webdriver/BiDi/Emulation/SetUserAgentOverrideCommand.cs


35. dotnet/src/webdriver/BiDi/Input/InputModule.cs ✨ Enhancement +3/-3

Pass extension data to input commands

dotnet/src/webdriver/BiDi/Input/InputModule.cs


36. dotnet/src/webdriver/BiDi/Input/PerformActionsCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to PerformActionsCommand

dotnet/src/webdriver/BiDi/Input/PerformActionsCommand.cs


37. dotnet/src/webdriver/BiDi/Input/ReleaseActionsCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to ReleaseActionsCommand

dotnet/src/webdriver/BiDi/Input/ReleaseActionsCommand.cs


38. dotnet/src/webdriver/BiDi/Input/SetFilesCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetFilesCommand

dotnet/src/webdriver/BiDi/Input/SetFilesCommand.cs


39. dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to AddDataCollectorCommand

dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs


40. dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to AddInterceptCommand

dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs


41. dotnet/src/webdriver/BiDi/Network/ContinueRequestCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to ContinueRequestCommand

dotnet/src/webdriver/BiDi/Network/ContinueRequestCommand.cs


42. dotnet/src/webdriver/BiDi/Network/ContinueResponseCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to ContinueResponseCommand

dotnet/src/webdriver/BiDi/Network/ContinueResponseCommand.cs


43. dotnet/src/webdriver/BiDi/Network/ContinueWithAuthCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to ContinueWithAuthCommand

dotnet/src/webdriver/BiDi/Network/ContinueWithAuthCommand.cs


44. dotnet/src/webdriver/BiDi/Network/FailRequestCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to FailRequestCommand

dotnet/src/webdriver/BiDi/Network/FailRequestCommand.cs


45. dotnet/src/webdriver/BiDi/Network/GetDataCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to GetDataCommand

dotnet/src/webdriver/BiDi/Network/GetDataCommand.cs


46. dotnet/src/webdriver/BiDi/Network/NetworkModule.cs ✨ Enhancement +14/-14

Pass extension data to network commands

dotnet/src/webdriver/BiDi/Network/NetworkModule.cs


47. dotnet/src/webdriver/BiDi/Network/ProvideResponseCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to ProvideResponseCommand

dotnet/src/webdriver/BiDi/Network/ProvideResponseCommand.cs


48. dotnet/src/webdriver/BiDi/Network/RemoveDataCollectorCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to RemoveDataCollectorCommand

dotnet/src/webdriver/BiDi/Network/RemoveDataCollectorCommand.cs


49. dotnet/src/webdriver/BiDi/Network/RemoveInterceptCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to RemoveInterceptCommand

dotnet/src/webdriver/BiDi/Network/RemoveInterceptCommand.cs


50. dotnet/src/webdriver/BiDi/Network/SetCacheBehaviorCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetCacheBehaviorCommand

dotnet/src/webdriver/BiDi/Network/SetCacheBehaviorCommand.cs


51. dotnet/src/webdriver/BiDi/Network/SetExtraHeadersCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetExtraHeadersCommand

dotnet/src/webdriver/BiDi/Network/SetExtraHeadersCommand.cs


52. dotnet/src/webdriver/BiDi/Permissions/PermissionsModule.cs ✨ Enhancement +1/-1

Pass extension data to permissions commands

dotnet/src/webdriver/BiDi/Permissions/PermissionsModule.cs


53. dotnet/src/webdriver/BiDi/Permissions/SetPermissionCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetPermissionCommand

dotnet/src/webdriver/BiDi/Permissions/SetPermissionCommand.cs


54. dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to AddPreloadScriptCommand

dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs


55. dotnet/src/webdriver/BiDi/Script/CallFunctionCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to CallFunctionCommand

dotnet/src/webdriver/BiDi/Script/CallFunctionCommand.cs


56. dotnet/src/webdriver/BiDi/Script/DisownCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to DisownCommand

dotnet/src/webdriver/BiDi/Script/DisownCommand.cs


57. dotnet/src/webdriver/BiDi/Script/EvaluateCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to EvaluateCommand

dotnet/src/webdriver/BiDi/Script/EvaluateCommand.cs


58. dotnet/src/webdriver/BiDi/Script/GetRealmsCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to GetRealmsCommand

dotnet/src/webdriver/BiDi/Script/GetRealmsCommand.cs


59. dotnet/src/webdriver/BiDi/Script/RemovePreloadScriptCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to RemovePreloadScriptCommand

dotnet/src/webdriver/BiDi/Script/RemovePreloadScriptCommand.cs


60. dotnet/src/webdriver/BiDi/Script/ScriptModule.cs ✨ Enhancement +6/-6

Pass extension data to script commands

dotnet/src/webdriver/BiDi/Script/ScriptModule.cs


61. dotnet/src/webdriver/BiDi/Session/EndCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to EndCommand

dotnet/src/webdriver/BiDi/Session/EndCommand.cs


62. dotnet/src/webdriver/BiDi/Session/NewCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to NewCommand

dotnet/src/webdriver/BiDi/Session/NewCommand.cs


63. dotnet/src/webdriver/BiDi/Session/SessionModule.cs ✨ Enhancement +5/-5

Pass extension data to session commands

dotnet/src/webdriver/BiDi/Session/SessionModule.cs


64. dotnet/src/webdriver/BiDi/Session/StatusCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to StatusCommand

dotnet/src/webdriver/BiDi/Session/StatusCommand.cs


65. dotnet/src/webdriver/BiDi/Session/SubscribeCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SubscribeCommand

dotnet/src/webdriver/BiDi/Session/SubscribeCommand.cs


66. dotnet/src/webdriver/BiDi/Session/UnsubscribeCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to UnsubscribeCommand

dotnet/src/webdriver/BiDi/Session/UnsubscribeCommand.cs


67. dotnet/src/webdriver/BiDi/Storage/DeleteCookiesCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to DeleteCookiesCommand

dotnet/src/webdriver/BiDi/Storage/DeleteCookiesCommand.cs


68. dotnet/src/webdriver/BiDi/Storage/GetCookiesCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to GetCookiesCommand

dotnet/src/webdriver/BiDi/Storage/GetCookiesCommand.cs


69. dotnet/src/webdriver/BiDi/Storage/SetCookieCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to SetCookieCommand

dotnet/src/webdriver/BiDi/Storage/SetCookieCommand.cs


70. dotnet/src/webdriver/BiDi/Storage/StorageModule.cs ✨ Enhancement +3/-3

Pass extension data to storage commands

dotnet/src/webdriver/BiDi/Storage/StorageModule.cs


71. dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to InstallCommand

dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs


72. dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs ✨ Enhancement +4/-2

Add extensionData parameter to UninstallCommand

dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs


73. dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs ✨ Enhancement +2/-2

Pass extension data to web extension commands

dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs


74. dotnet/test/common/BiDi/Session/SessionTests.cs 🧪 Tests +21/-0

Add test for extension data support

dotnet/test/common/BiDi/Session/SessionTests.cs


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review bot commented Mar 25, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1) 📎 Requirement gaps (1) 📐 Spec deviations (0)

Grey Divider


Action required

1. Command ctor signature changed 📘 Rule violation ⚙ Maintainability
Description
The public abstract Command base type removed the prior protected Command(string method)
constructor and now requires an additional extensionData parameter, which is a source-breaking
change for any consumer-defined derived commands. This violates the requirement to maintain
backward-compatible public API/ABI or deprecate before removal.
Code

dotnet/src/webdriver/BiDi/Command.cs[R26-36]

+public abstract class Command(string method, IDictionary<string, JsonElement>? extensionData)
{
-    protected Command(string method)
-    {
-        Method = method;
-    }
+    [JsonPropertyOrder(0)]
+    public long Id { get; internal set; }

    [JsonPropertyOrder(1)]
-    public string Method { get; }
+    public string Method { get; } = method;

-    [JsonPropertyOrder(0)]
-    public long Id { get; internal set; }
+    [JsonExtensionData]
+    // IMPORTANT: The name is different from ctor parameter to avoid collision with the JsonExtensionData attribute.
+    public IDictionary<string, JsonElement>? JsonExtensionData { get; } = extensionData;
Evidence
PR Compliance ID 13 requires backward-compatible public APIs. The diff shows Command changed from
a parameterless base constructor accepting only method to a new primary constructor requiring
extensionData, without keeping the previous constructor for existing derived types.

AGENTS.md
dotnet/src/webdriver/BiDi/Command.cs[26-36]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The public `OpenQA.Selenium.BiDi.Command` base type changed constructor shape (removed `protected Command(string method)`), which is a breaking change for consumers who derive their own commands.

## Issue Context
This PR adds extension data support. Keep that support while preserving backward-compatible construction for existing derived types.

## Fix Focus Areas
- dotnet/src/webdriver/BiDi/Command.cs[26-36]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. ExtensionData exposes mutable state 📎 Requirement gap ⛯ Reliability
Description
CommandOptions.ExtensionData is JsonObject, which remains mutable after construction, and tests
demonstrate mutating it post-instantiation. This violates the requirement that public options types
be immutable from the consumer’s perspective.
Code

dotnet/src/webdriver/BiDi/CommandOptions.cs[R24-28]

public abstract record CommandOptions
{
    public TimeSpan? Timeout { get; init; }
+
+    public JsonObject? ExtensionData { get; init; } = [];
Evidence
PR Compliance ID 8 requires options types to be immutable. The diff adds an init-only property, but
the value is a mutable JsonObject (and is mutated in the added test), so consumer-visible state
can change after construction.

Command options immutability: Options types are immutable (e.g., records with init-only properties)
dotnet/src/webdriver/BiDi/CommandOptions.cs[24-28]
dotnet/test/common/BiDi/Session/SessionTests.cs[63-71]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`CommandOptions.ExtensionData` is a mutable `JsonObject`, allowing mutation after options construction (even with an `init` property). This violates the immutability requirement for command options.

## Issue Context
The PR adds extensible command data, but the options surface should not expose mutable state. Consider switching to an immutable/read-only representation (e.g., `IReadOnlyDictionary<string, JsonElement>` backed by `ImmutableDictionary`) and/or copying/freezing data on construction.

## Fix Focus Areas
- dotnet/src/webdriver/BiDi/CommandOptions.cs[24-28]
- dotnet/test/common/BiDi/Session/SessionTests.cs[63-71]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Misleading nullable ExtensionData 🐞 Bug ⚙ Maintainability
Description
CommandOptions.ExtensionData is declared as JsonObject? but is initialized to an empty object
and used as non-null (indexing without checks), creating avoidable nullable warnings and making
ExtensionData = null a footgun (NRE on mutation). This is inconsistent API semantics for a public
options type.
Code

dotnet/src/webdriver/BiDi/CommandOptions.cs[R24-29]

public abstract record CommandOptions
{
    public TimeSpan? Timeout { get; init; }
+
+    public JsonObject? ExtensionData { get; init; } = [];
}
Evidence
The public API advertises that ExtensionData may be null, but also provides a non-null default
instance and consumers in-repo mutate it without null checks, indicating it is intended to be
non-null in normal use.

dotnet/src/webdriver/BiDi/CommandOptions.cs[24-29]
dotnet/test/common/BiDi/Session/SessionTests.cs[56-71]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`CommandOptions.ExtensionData` is typed as nullable (`JsonObject?`) but is initialized to a new empty object and is used as non-null throughout usage patterns (including tests). This causes nullable-analysis friction for users and allows a trivial NRE if a caller assigns `null` then tries to add entries.

### Issue Context
The feature is intended to make it easy to add extension properties via object/collection initializers and direct indexing.

### Fix Focus Areas
- dotnet/src/webdriver/BiDi/CommandOptions.cs[24-29]
- dotnet/test/common/BiDi/Session/SessionTests.cs[56-71]

### Recommended change
- Change the property to be non-nullable: `public JsonObject ExtensionData { get; init; } = new();` (or `= [];` if you want to keep collection-expression style).
- If you must support explicitly disabling it, prefer an empty object over `null` and document that `ExtensionData` is always non-null.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

4. Empty extension data deserialization 🐞 Bug ➹ Performance
Description
Command<TParameters, TResult> converts JsonObject extension data via
Deserialize<Dictionary<string, JsonElement>>() whenever a non-null options object is supplied,
even when the extension data is just the default empty object. This adds avoidable allocations/CPU
for common calls that pass options only to set Timeout.
Code

dotnet/src/webdriver/BiDi/Command.cs[R39-40]

+internal abstract class Command<TParameters, TResult>(TParameters parameters, string method, JsonObject? extensionData)
+    : Command(method, extensionData?.Deserialize<Dictionary<string, JsonElement>>())
Evidence
The command base always deserializes extension data when it is non-null. Since
CommandOptions.ExtensionData defaults to an empty JsonObject, supplying any options instance
(even without adding extension members) causes the deserialize path to run, as demonstrated by the
timeout-only test pattern.

dotnet/src/webdriver/BiDi/Command.cs[39-46]
dotnet/src/webdriver/BiDi/CommandOptions.cs[24-29]
dotnet/test/common/BiDi/Session/SessionTests.cs[38-44]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Commands currently deserialize extension data whenever `extensionData != null`. Because options default `ExtensionData` to an empty object, callers passing options for unrelated reasons (e.g., timeout) still incur JSON deserialization and allocations.

### Issue Context
This runs in the hot path for every command execution and is triggered by typical usage like `new StatusOptions { Timeout = ... }`.

### Fix Focus Areas
- dotnet/src/webdriver/BiDi/Command.cs[39-46]
- dotnet/src/webdriver/BiDi/CommandOptions.cs[24-29]

### Recommended change
- Treat empty `JsonObject` as “no extension data”:
 - In `Command<TParameters, TResult>` ctor, use something like:
   - `var dict = (extensionData is null || extensionData.Count == 0) ? null : extensionData.Deserialize<Dictionary<string, JsonElement>>();`
   - pass `dict` to the base `Command`.
- Optionally consider storing extension data in a form that avoids deserialize-to-`JsonElement` altogether if feasible with `[JsonExtensionData]`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +26 to +36
public abstract class Command(string method, IDictionary<string, JsonElement>? extensionData)
{
protected Command(string method)
{
Method = method;
}
[JsonPropertyOrder(0)]
public long Id { get; internal set; }

[JsonPropertyOrder(1)]
public string Method { get; }
public string Method { get; } = method;

[JsonPropertyOrder(0)]
public long Id { get; internal set; }
[JsonExtensionData]
// IMPORTANT: The name is different from ctor parameter to avoid collision with the JsonExtensionData attribute.
public IDictionary<string, JsonElement>? JsonExtensionData { get; } = extensionData;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

1. command ctor signature changed 📘 Rule violation ⚙ Maintainability

The public abstract Command base type removed the prior protected Command(string method)
constructor and now requires an additional extensionData parameter, which is a source-breaking
change for any consumer-defined derived commands. This violates the requirement to maintain
backward-compatible public API/ABI or deprecate before removal.
Agent Prompt
## Issue description
The public `OpenQA.Selenium.BiDi.Command` base type changed constructor shape (removed `protected Command(string method)`), which is a breaking change for consumers who derive their own commands.

## Issue Context
This PR adds extension data support. Keep that support while preserving backward-compatible construction for existing derived types.

## Fix Focus Areas
- dotnet/src/webdriver/BiDi/Command.cs[26-36]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 24 to +28
public abstract record CommandOptions
{
public TimeSpan? Timeout { get; init; }

public JsonObject? ExtensionData { get; init; } = [];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

2. extensiondata exposes mutable state 📎 Requirement gap ⛯ Reliability

CommandOptions.ExtensionData is JsonObject, which remains mutable after construction, and tests
demonstrate mutating it post-instantiation. This violates the requirement that public options types
be immutable from the consumer’s perspective.
Agent Prompt
## Issue description
`CommandOptions.ExtensionData` is a mutable `JsonObject`, allowing mutation after options construction (even with an `init` property). This violates the immutability requirement for command options.

## Issue Context
The PR adds extensible command data, but the options surface should not expose mutable state. Consider switching to an immutable/read-only representation (e.g., `IReadOnlyDictionary<string, JsonElement>` backed by `ImmutableDictionary`) and/or copying/freezing data on construction.

## Fix Focus Areas
- dotnet/src/webdriver/BiDi/CommandOptions.cs[24-28]
- dotnet/test/common/BiDi/Session/SessionTests.cs[63-71]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-dotnet .NET Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants