Skip to content

[rb] raise typed WebDriver errors for BiDi from a generated error-code map - #17855

Open
titusfortner wants to merge 4 commits into
SeleniumHQ:trunkfrom
titusfortner:rb-bidi-typed-errors
Open

[rb] raise typed WebDriver errors for BiDi from a generated error-code map#17855
titusfortner wants to merge 4 commits into
SeleniumHQ:trunkfrom
titusfortner:rb-bidi-typed-errors

Conversation

@titusfortner

Copy link
Copy Markdown
Member

🔗 Related Issues

💥 What does this PR do?

  • BiDi commands now raise a typed exception matching the remote end's error code, instead of a generic WebDriverError.
  • The full BiDi error-code set is generated from the shared schema, so it stays in sync with the spec.

🔧 Implementation Notes

  • The 30 codes are generated as a Protocol::ErrorCode map (wire code → Ruby class name) from the CDDL ErrorCode enum; the generated file is pure data and references nothing else.
  • A hand-written pass registers each BiDi-only code (no such node, no such handle, …) as a WebDriverError subclass in Selenium::WebDriver::Error; codes shared with the classic protocol (no such element, invalid argument, …) reuse the existing classic class, so a rescue is identical whether a session ran over BiDi or classic — which matters because the transport is selected silently.
  • Transport resolves a wire code to its class via Protocol::ErrorCode.for, falling back to WebDriverError for anything outside the closed set.

🤖 AI assistance

  • No substantial AI assistance used
  • AI assisted (complete below)
    • Tool(s): Claude Code
    • What was generated: generator/template changes, the generated error-code map, transport wiring, and unit tests
    • I reviewed all AI output and can explain the change

💡 Additional Considerations

  • The current BiDi wrappers (browser/browsing_context/network) still talk raw JSON via send_cmd and don't yet benefit from the typed errors; migrating them onto the generated Protocol layer is follow-up work.

🔄 Types of changes

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

@selenium-ci selenium-ci added C-rb Ruby Bindings B-build Includes scripting, bazel and CI integrations B-devtools Includes everything BiDi or Chrome DevTools related B-support Issue or PR related to support classes labels Aug 1, 2026
@selenium-ci

Copy link
Copy Markdown
Member

Thank you, @titusfortner for this code suggestion.

The support packages contain example code that many users find helpful, but they do not necessarily represent
the best practices for using Selenium, and the Selenium team is not currently merging changes to them.

After reviewing the change, unless it is a critical fix or a feature that is needed for Selenium
to work, we will likely close the PR.

We actively encourage people to add the wrapper and helper code that makes sense for them to their own frameworks.
If you have any questions, please contact us

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Raise typed BiDi WebDriver errors via generated error-code map

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Generate a BiDi ErrorCode → Ruby exception-name map from the shared schema.
• Resolve BiDi wire errors to typed Selenium::WebDriver::Error subclasses (or WebDriverError
 fallback).
• Add generator/templates, staleness checking, signatures, and transport specs for typed error
 raising.
Diagram

graph TD
  S{{"BiDi schema"}} --> G["bidi_generate.rb"] --> TPL["error_code.*.erb"] --> MAP["protocol/error_code.rb"]
  MAP --> REG["bidi/error.rb (register)"] --> ERR["Error::* subclasses"]
  TR["bidi/transport.rb"] --> RES["Protocol::ErrorCode.for"] --> ERR
  CHK["check_generated.rb"] --> MAP
  UT["transport_spec.rb"] --> TR

  subgraph Legend
    direction LR
    _ext{{"External/spec input"}} ~~~ _mod["Runtime module/script"] ~~~ _file["Generated/data file"]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Derive class names at runtime from wire strings
  • ➕ No generated map/artifacts to check in
  • ➕ Less generator/template surface area
  • ➖ Harder to guarantee alignment with the schema’s closed set
  • ➖ More fragile around special-case naming and future spec changes
  • ➖ Still needs registration/const safety and a fallback path
2. Use existing classic Error.for_error mapping as the single source of truth
  • ➕ Reuses established mapping/behavior for shared codes
  • ➕ Avoids introducing another mapping layer
  • ➖ BiDi-only codes still need an explicit mechanism
  • ➖ Couples BiDi correctness to classic protocol internals rather than the BiDi schema
  • ➖ Harder to prove spec sync without generation

Recommendation: Keep the current approach: generate the closed-set wire→class-name map from the shared schema and resolve via Protocol::ErrorCode.for with a WebDriverError fallback. It preserves identical rescue semantics for shared error codes across classic vs BiDi transports, while ensuring BiDi-only codes are always present and stay in sync with the spec.

Files changed (13) +315 / -10

Enhancement (11) +294 / -8
error.rbRegister BiDi-only error subclasses and add ErrorCode.for resolver +44/-0

Register BiDi-only error subclasses and add ErrorCode.for resolver

• Introduces a BiDi error integration layer that (1) defines missing Selenium::WebDriver::Error constants for BiDi-only codes and (2) provides Protocol::ErrorCode.for to map a wire code to an exception class with a WebDriverError fallback.

rb/lib/selenium/webdriver/bidi/error.rb

protocol.rbWire protocol load order to include error mapping and registration +3/-0

Wire protocol load order to include error mapping and registration

• Ensures common error infrastructure and the generated ErrorCode map are required as part of BiDi protocol loading, so transport can raise typed exceptions reliably.

rb/lib/selenium/webdriver/bidi/protocol.rb

error_code.rbAdd generated ErrorCode CLASS_NAMES mapping +66/-0

Add generated ErrorCode CLASS_NAMES mapping

• Adds a generated, data-only Protocol::ErrorCode::CLASS_NAMES hash mapping BiDi wire error strings to Ruby exception class names, intended to remain synchronized with the schema.

rb/lib/selenium/webdriver/bidi/protocol/error_code.rb

bidi_generate.rbGenerate protocol/error_code.rb from schema ErrorCode enum +37/-0

Generate protocol/error_code.rb from schema ErrorCode enum

• Extends the generator IR and emit pipeline to produce protocol/error_code.rb and its RBS counterpart from the protocol-root ErrorCode enum, including consistent Ruby class-name derivation rules.

rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb

check_generated.rbDetect staleness of generated ErrorCode module +15/-4

Detect staleness of generated ErrorCode module

• Refactors the staleness check to reuse a parsed Schema instance and adds an explicit comparison for protocol/error_code.rb against the generator’s rendered output.

rb/lib/selenium/webdriver/bidi/support/check_generated.rb

error_code.rb.erbAdd Ruby template for generated ErrorCode map +36/-0

Add Ruby template for generated ErrorCode map

• Introduces a new ERB template to render Protocol::ErrorCode::CLASS_NAMES as a frozen mapping with the standard generated-file header and documentation link.

rb/lib/selenium/webdriver/bidi/support/templates/error_code.rb.erb

error_code.rbs.erbAdd RBS template for generated ErrorCode map +30/-0

Add RBS template for generated ErrorCode map

• Introduces the signature template for the generated ErrorCode module, typing CLASS_NAMES as Hash[String, String] with the standard generated-file header.

rb/lib/selenium/webdriver/bidi/support/templates/error_code.rbs.erb

transport.rbRaise typed exceptions for BiDi error replies +3/-3

Raise typed exceptions for BiDi error replies

• Switches transport error handling from always raising WebDriverError to resolving the error code through Protocol::ErrorCode.for and instantiating the returned exception class, with fallback behavior for unknown codes.

rb/lib/selenium/webdriver/bidi/transport.rb

error.rbsAdd RBS for Protocol::ErrorCode.for +28/-0

Add RBS for Protocol::ErrorCode.for

• Adds a signature file declaring Protocol::ErrorCode.for and its return type shape for typed error resolution.

rb/sig/lib/selenium/webdriver/bidi/error.rbs

error_code.rbsAdd generated RBS for ErrorCode CLASS_NAMES +31/-0

Add generated RBS for ErrorCode CLASS_NAMES

• Adds the generated RBS for the protocol ErrorCode module, exposing the CLASS_NAMES hash type to type checking.

rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs

transport.rbsUpdate transport signature for error_for helper +1/-1

Update transport signature for error_for helper

• Updates the transport signature to reflect the new error_for method returning a WebDriverError instance rather than a string message helper.

rb/sig/lib/selenium/webdriver/bidi/transport.rbs

Tests (1) +18 / -2
transport_spec.rbTest typed error raising for shared, BiDi-only, and unknown codes +18/-2

Test typed error raising for shared, BiDi-only, and unknown codes

• Expands unit coverage to assert that shared codes raise the existing classic error class, BiDi-only codes raise newly registered subclasses, and unrecognized codes fall back to WebDriverError.

rb/spec/unit/selenium/webdriver/bidi/transport_spec.rb

Other (1) +3 / -0
BUILD.bazelInclude new error_code templates in Bazel targets +3/-0

Include new error_code templates in Bazel targets

• Adds the new Ruby/RBS error-code templates to the rb_binary data and to the BiDi generation test data, ensuring Bazel runfiles include the templates needed for generation and checks.

rb/lib/selenium/webdriver/BUILD.bazel

@qodo-code-review

qodo-code-review Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. RBS redeclares classic errors ✓ Resolved 📘 Rule violation ≡ Correctness
Description
The generated BiDi protocol/error_code.rbs re-declares classic Selenium::WebDriver::Error::*
classes with a superclass, even though those classes are already declared in common/error.rbs.
This risks RBS/Steep duplicate-declaration errors and breaks typed consumers of the public error
API.
Code

rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs[R33-52]

+    module Error
+      class InvalidArgumentError < WebDriverError
+      end
+      class InvalidSelectorError < WebDriverError
+      end
+      class InvalidSessionIdError < WebDriverError
+      end
+      class InvalidWebExtensionError < WebDriverError
+      end
+      class MoveTargetOutOfBoundsError < WebDriverError
+      end
+      class NoSuchAlertError < WebDriverError
+      end
+      class NoSuchNetworkCollectorError < WebDriverError
+      end
+      class NoSuchElementError < WebDriverError
+      end
+      class NoSuchFrameError < WebDriverError
+      end
+      class NoSuchHandleError < WebDriverError
Evidence
The template emits class <%= name %> < WebDriverError for every error code, resulting in
protocol/error_code.rbs declaring shared classic errors like NoSuchFrameError again with a
superclass. Those same classes are already declared in
rb/sig/lib/selenium/webdriver/common/error.rbs, so this is a public type-signature conflict for
consumers.

AGENTS.md: Preserve Public API/ABI Compatibility and Follow Deprecation Policy for Removals
rb/lib/selenium/webdriver/bidi/support/templates/error_code.rbs.erb[30-36]
rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs[33-52]
rb/sig/lib/selenium/webdriver/common/error.rbs[30-40]

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

## Issue description
`rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs` declares many error classes that already exist in `rb/sig/lib/selenium/webdriver/common/error.rbs` (e.g., `NoSuchFrameError`, `InvalidArgumentError`). In RBS, reopening an existing class should not repeat the superclass, and redeclaring can cause type-check failures.

## Issue Context
The template `rb/lib/selenium/webdriver/bidi/support/templates/error_code.rbs.erb` currently emits `class <%= name %> < WebDriverError` for every code, including codes shared with the classic protocol.

## Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/support/templates/error_code.rbs.erb[30-36]
- rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs[30-94]

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



Remediation recommended

2. Unfixable stale-check guidance 🐞 Bug ☼ Reliability ⭐ New
Description
If the schema ever has no ErrorCode values, error_module_current? treats any existing
protocol/error_code.rb as stale, but check! still instructs only regeneration; regeneration
won’t remove the file because the generator skips emitting the error module when codes is empty.
This can leave developers stuck in a failing generated-code check until they manually delete stale
error_code.rb (and likely the corresponding .rbs).
Code

rb/lib/selenium/webdriver/bidi/support/check_generated.rb[R44-52]

+  # Whether the checked-in protocol/error_code.rb matches what the generator would render now. With
+  # no error codes nothing is generated, so an existing file is stale and must be removed.
+  def self.error_module_current?(schema, protocol_dir)
+    codes = error_code_map(schema)
+    path = File.join(protocol_dir, 'error_code.rb')
+    return !File.exist?(path) if codes.empty?
+
+    mod = ErrorModule.new(filename: 'error_code', codes: codes)
+    File.exist?(path) && File.read(path) == render(mod, File.join(__dir__, 'templates', 'error_code.rb.erb'))
Evidence
error_module_current? marks an existing error_code.rb as stale when there are no codes. But the
checker’s output only recommends regeneration, while the generator skips generating (and thus will
not remove) error_code.rb/.rbs when codes is empty, so following the printed instruction
cannot resolve the failure.

rb/lib/selenium/webdriver/bidi/support/check_generated.rb[32-41]
rb/lib/selenium/webdriver/bidi/support/check_generated.rb[44-53]
rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb[1146-1155]

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

### Issue description
When the schema’s `ErrorCode` enum becomes empty, `check_generated` will fail if a previously-generated `protocol/error_code.rb` still exists, but the script only prints a regeneration command. The generator explicitly returns early when there are no codes, so regeneration cannot remove the stale files.

### Issue Context
This manifests when the schema changes from having `ErrorCode` values to having none (or when a stale `error_code.rb`/`error_code.rbs` is present). The check should either:
- explicitly instruct the user to delete the stale artifacts, and/or
- have the generator proactively remove previously-generated artifacts when `codes.empty?`.

### Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/support/check_generated.rb[32-41]
- rb/lib/selenium/webdriver/bidi/support/check_generated.rb[44-53]
- rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb[1146-1155]

### Suggested change
1) In `check!`, if `error_code_map(schema).empty?` and `protocol/error_code.rb` exists, print an additional warning like: “Schema has no ErrorCode values; delete protocol/error_code.rb (and sig/.../error_code.rbs)”.

AND/OR

2) In `emit_error_module`, when `codes.empty?`, delete any existing generated `error_code.rb` and `error_code.rbs` at the target locations so `bazel run ...:bidi-generate` fully remediates the state.

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


3. Missing RBS for new errors 🐞 Bug ⚙ Maintainability
Description
This PR dynamically defines new Selenium::WebDriver::Error::* exception classes for BiDi-only codes
(e.g., NoSuchNodeError), but the shipped RBS only declares the classic error constants, so typed
users cannot reference these new exceptions without signature gaps.
Code

rb/lib/selenium/webdriver/bidi/error.rb[R26-29]

+      # Register each BiDi-only code as a WebDriverError subclass; shared codes keep their classic class.
+      BiDi::Protocol::ErrorCode::CLASS_NAMES.each_value do |name|
+        const_set(name, Class.new(WebDriverError)) unless const_defined?(name, false)
+      end
Evidence
The PR introduces runtime registration of exception constants based on the generated CLASS_NAMES
map, which includes BiDi-only class names like NoSuchNodeError, but the existing common/error.rbs
ends without declaring those constants.

rb/lib/selenium/webdriver/bidi/error.rb[23-30]
rb/lib/selenium/webdriver/bidi/protocol/error_code.rb[23-61]
rb/sig/lib/selenium/webdriver/common/error.rbs[18-127]

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

### Issue description
BiDi-only error codes are registered as new `Selenium::WebDriver::Error` subclasses at runtime, but the RBS for `Selenium::WebDriver::Error` does not declare these new constants. This makes the new typed-error API incomplete for Steep/RBS users.

### Issue Context
`bidi/protocol/error_code.rb` enumerates BiDi error code -> class name mappings including several names not present in `rb/sig/lib/selenium/webdriver/common/error.rbs`.

### Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/error.rb[25-29]
- rb/sig/lib/selenium/webdriver/common/error.rbs[18-127]

### Suggested fix
Add RBS declarations for the BiDi-only error classes under `module Selenium::WebDriver::Error` (either by extending `common/error.rbs` or adding a new `rb/sig/...` file that reopens the module).

At minimum, declare the BiDi-only classes from the generated map that are not already present, e.g.:
- `InvalidWebExtensionError`
- `NoSuchNetworkCollectorError`
- `NoSuchHandleError`
- `NoSuchHistoryEntryError`
- `NoSuchInterceptError`
- `NoSuchNetworkDataError`
- `NoSuchNodeError`
- `NoSuchRequestError`
- `NoSuchScreencastError`
- `NoSuchScriptError`
- `NoSuchStoragePartitionError`
- `NoSuchUserContextError`
- `NoSuchWebExtensionError`
- `UnableToCloseBrowserError`
- `UnableToSetFileInputError`
- `UnavailableNetworkDataError`
- `UnderspecifiedStoragePartitionError`

All should be `class X < WebDriverError; end`.

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


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Previous review results

Review updated until commit 8ec33ab ⚖️ Balanced

Results up to commit 91b4086 ⚖️ Balanced


🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Missing RBS for new errors 🐞 Bug ⚙ Maintainability
Description
This PR dynamically defines new Selenium::WebDriver::Error::* exception classes for BiDi-only codes
(e.g., NoSuchNodeError), but the shipped RBS only declares the classic error constants, so typed
users cannot reference these new exceptions without signature gaps.
Code

rb/lib/selenium/webdriver/bidi/error.rb[R26-29]

+      # Register each BiDi-only code as a WebDriverError subclass; shared codes keep their classic class.
+      BiDi::Protocol::ErrorCode::CLASS_NAMES.each_value do |name|
+        const_set(name, Class.new(WebDriverError)) unless const_defined?(name, false)
+      end
Evidence
The PR introduces runtime registration of exception constants based on the generated CLASS_NAMES
map, which includes BiDi-only class names like NoSuchNodeError, but the existing common/error.rbs
ends without declaring those constants.

rb/lib/selenium/webdriver/bidi/error.rb[23-30]
rb/lib/selenium/webdriver/bidi/protocol/error_code.rb[23-61]
rb/sig/lib/selenium/webdriver/common/error.rbs[18-127]

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

### Issue description
BiDi-only error codes are registered as new `Selenium::WebDriver::Error` subclasses at runtime, but the RBS for `Selenium::WebDriver::Error` does not declare these new constants. This makes the new typed-error API incomplete for Steep/RBS users.

### Issue Context
`bidi/protocol/error_code.rb` enumerates BiDi error code -> class name mappings including several names not present in `rb/sig/lib/selenium/webdriver/common/error.rbs`.

### Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/error.rb[25-29]
- rb/sig/lib/selenium/webdriver/common/error.rbs[18-127]

### Suggested fix
Add RBS declarations for the BiDi-only error classes under `module Selenium::WebDriver::Error` (either by extending `common/error.rbs` or adding a new `rb/sig/...` file that reopens the module).

At minimum, declare the BiDi-only classes from the generated map that are not already present, e.g.:
- `InvalidWebExtensionError`
- `NoSuchNetworkCollectorError`
- `NoSuchHandleError`
- `NoSuchHistoryEntryError`
- `NoSuchInterceptError`
- `NoSuchNetworkDataError`
- `NoSuchNodeError`
- `NoSuchRequestError`
- `NoSuchScreencastError`
- `NoSuchScriptError`
- `NoSuchStoragePartitionError`
- `NoSuchUserContextError`
- `NoSuchWebExtensionError`
- `UnableToCloseBrowserError`
- `UnableToSetFileInputError`
- `UnavailableNetworkDataError`
- `UnderspecifiedStoragePartitionError`

All should be `class X < WebDriverError; end`.

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


Results up to commit 056b5d2 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. RBS redeclares classic errors ✓ Resolved 📘 Rule violation ≡ Correctness
Description
The generated BiDi protocol/error_code.rbs re-declares classic Selenium::WebDriver::Error::*
classes with a superclass, even though those classes are already declared in common/error.rbs.
This risks RBS/Steep duplicate-declaration errors and breaks typed consumers of the public error
API.
Code

rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs[R33-52]

+    module Error
+      class InvalidArgumentError < WebDriverError
+      end
+      class InvalidSelectorError < WebDriverError
+      end
+      class InvalidSessionIdError < WebDriverError
+      end
+      class InvalidWebExtensionError < WebDriverError
+      end
+      class MoveTargetOutOfBoundsError < WebDriverError
+      end
+      class NoSuchAlertError < WebDriverError
+      end
+      class NoSuchNetworkCollectorError < WebDriverError
+      end
+      class NoSuchElementError < WebDriverError
+      end
+      class NoSuchFrameError < WebDriverError
+      end
+      class NoSuchHandleError < WebDriverError
Evidence
The template emits class <%= name %> < WebDriverError for every error code, resulting in
protocol/error_code.rbs declaring shared classic errors like NoSuchFrameError again with a
superclass. Those same classes are already declared in
rb/sig/lib/selenium/webdriver/common/error.rbs, so this is a public type-signature conflict for
consumers.

AGENTS.md: Preserve Public API/ABI Compatibility and Follow Deprecation Policy for Removals
rb/lib/selenium/webdriver/bidi/support/templates/error_code.rbs.erb[30-36]
rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs[33-52]
rb/sig/lib/selenium/webdriver/common/error.rbs[30-40]

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

## Issue description
`rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs` declares many error classes that already exist in `rb/sig/lib/selenium/webdriver/common/error.rbs` (e.g., `NoSuchFrameError`, `InvalidArgumentError`). In RBS, reopening an existing class should not repeat the superclass, and redeclaring can cause type-check failures.

## Issue Context
The template `rb/lib/selenium/webdriver/bidi/support/templates/error_code.rbs.erb` currently emits `class <%= name %> < WebDriverError` for every code, including codes shared with the classic protocol.

## Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/support/templates/error_code.rbs.erb[30-36]
- rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs[30-94]

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


Results up to commit 39c008b ⚖️ Balanced


No changes from previous review

Qodo Logo

Comment thread rb/lib/selenium/webdriver/bidi/error.rb
Comment thread rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 056b5d2

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 39c008b

Copilot AI left a comment

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.

Pull request overview

This PR updates the Ruby BiDi “generated Protocol” transport to raise typed Selenium::WebDriver::Error subclasses based on the BiDi wire error code, using a generated wire-code → Ruby-class mapping so the set stays in sync with the shared schema.

Changes:

  • Generate BiDi::Protocol::ErrorCode::CLASS_NAMES (wire error code → Ruby exception class name) from the BiDi schema, plus matching RBS signatures.
  • Register BiDi-only error codes as Selenium::WebDriver::Error::WebDriverError subclasses while reusing existing classic error classes for shared codes.
  • Update BiDi::Transport to raise a typed exception resolved via Protocol::ErrorCode.for, with unit coverage for shared, BiDi-only, and unknown codes.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
rb/spec/unit/selenium/webdriver/bidi/transport_spec.rb Asserts typed exceptions for shared codes, BiDi-only codes, and fallback behavior.
rb/sig/lib/selenium/webdriver/bidi/transport.rbs Updates signature to reflect error_for returning an exception instance.
rb/sig/lib/selenium/webdriver/bidi/protocol/error_code.rbs Adds generated RBS for the ErrorCode map and BiDi-only error subclasses.
rb/sig/lib/selenium/webdriver/bidi/error.rbs Declares the Protocol::ErrorCode.for method for typed error resolution.
rb/lib/selenium/webdriver/BUILD.bazel Wires new templates/data into the generator and verification test.
rb/lib/selenium/webdriver/bidi/transport.rb Raises typed errors via Protocol::ErrorCode.for instead of a generic WebDriverError.
rb/lib/selenium/webdriver/bidi/support/templates/error_code.rbs.erb Template for generated RBS for error-code map + BiDi-only error classes.
rb/lib/selenium/webdriver/bidi/support/templates/error_code.rb.erb Template for generated Ruby error-code map.
rb/lib/selenium/webdriver/bidi/support/check_generated.rb Extends generated-code freshness checks to include error_code.rb.
rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb Adds schema → error-code map generation and emits protocol/error_code.{rb,rbs}.
rb/lib/selenium/webdriver/bidi/protocol/error_code.rb Generated wire-code → Ruby-class mapping.
rb/lib/selenium/webdriver/bidi/protocol.rb Requires classic errors + new BiDi error-code map + BiDi error registrations.
rb/lib/selenium/webdriver/bidi/error.rb Registers BiDi-only error subclasses and implements Protocol::ErrorCode.for.

class BiDi
module Protocol
module ErrorCode
def self.for: (String? code) -> singleton(::Selenium::WebDriver::Error::WebDriverError)
Comment on lines +44 to +52
# Whether the checked-in protocol/error_code.rb matches what the generator would render now.
def self.error_module_current?(schema, protocol_dir)
codes = error_code_map(schema)
path = File.join(protocol_dir, 'error_code.rb')
return codes.empty? unless File.exist?(path)

mod = ErrorModule.new(filename: 'error_code', codes: codes)
File.read(path) == render(mod, File.join(__dir__, 'templates', 'error_code.rb.erb'))
end
Comment on lines +44 to +52
# Whether the checked-in protocol/error_code.rb matches what the generator would render now. With
# no error codes nothing is generated, so an existing file is stale and must be removed.
def self.error_module_current?(schema, protocol_dir)
codes = error_code_map(schema)
path = File.join(protocol_dir, 'error_code.rb')
return !File.exist?(path) if codes.empty?

mod = ErrorModule.new(filename: 'error_code', codes: codes)
File.exist?(path) && File.read(path) == render(mod, File.join(__dir__, 'templates', 'error_code.rb.erb'))

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.

Remediation recommended

1. Unfixable stale-check guidance 🐞 Bug ☼ Reliability

If the schema ever has no ErrorCode values, error_module_current? treats any existing
protocol/error_code.rb as stale, but check! still instructs only regeneration; regeneration
won’t remove the file because the generator skips emitting the error module when codes is empty.
This can leave developers stuck in a failing generated-code check until they manually delete stale
error_code.rb (and likely the corresponding .rbs).
Agent Prompt
### Issue description
When the schema’s `ErrorCode` enum becomes empty, `check_generated` will fail if a previously-generated `protocol/error_code.rb` still exists, but the script only prints a regeneration command. The generator explicitly returns early when there are no codes, so regeneration cannot remove the stale files.

### Issue Context
This manifests when the schema changes from having `ErrorCode` values to having none (or when a stale `error_code.rb`/`error_code.rbs` is present). The check should either:
- explicitly instruct the user to delete the stale artifacts, and/or
- have the generator proactively remove previously-generated artifacts when `codes.empty?`.

### Fix Focus Areas
- rb/lib/selenium/webdriver/bidi/support/check_generated.rb[32-41]
- rb/lib/selenium/webdriver/bidi/support/check_generated.rb[44-53]
- rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb[1146-1155]

### Suggested change
1) In `check!`, if `error_code_map(schema).empty?` and `protocol/error_code.rb` exists, print an additional warning like: “Schema has no ErrorCode values; delete protocol/error_code.rb (and sig/.../error_code.rbs)”.

AND/OR

2) In `emit_error_module`, when `codes.empty?`, delete any existing generated `error_code.rb` and `error_code.rbs` at the target locations so `bazel run ...:bidi-generate` fully remediates the state.

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

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 8ec33ab

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

Labels

B-build Includes scripting, bazel and CI integrations B-devtools Includes everything BiDi or Chrome DevTools related B-support Issue or PR related to support classes C-rb Ruby Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants