Skip to content

Conversation

@aguspe
Copy link
Contributor

@aguspe aguspe commented Dec 7, 2025

User description

💥 What does this PR do?

This PR adds support for the set window method specified on the BiDi implementation for the ruby bindings

The command is not implemented yet, so I couldn't fully tested but I looked at what we have in other bindings and is a start

🔧 Implementation Notes

I decided to create a window class, so the user can update one or more window properties easily

🔄 Types of changes

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

PR Type

Enhancement


Description

  • Refactors Window from Struct to dedicated class with BiDi integration

  • Adds window state management methods (maximize, minimize, fullscreen, resize)

  • Implements browser.setClientWindowState BiDi command support

  • Adds comprehensive test coverage for window state operations


Diagram Walkthrough

flowchart LR
  A["Browser class"] -->|requires| B["Window class"]
  B -->|calls| C["browser.setClientWindowState"]
  B -->|provides| D["State methods<br/>maximize/minimize/fullscreen/resize"]
  D -->|updates| E["Window attributes<br/>state/width/height/x/y"]
Loading

File Walkthrough

Relevant files
Enhancement
browser.rb
Refactor Window class and add window accessor                       

rb/lib/selenium/webdriver/bidi/browser.rb

  • Extracts Window from inline Struct to separate class file
  • Adds @window instance variable for caching active window
  • Implements window method to retrieve active or first window
  • Updates windows method to instantiate Window with BiDi reference
+8/-6     
window.rb
New Window class with state management methods                     

rb/lib/selenium/webdriver/bidi/browser/window.rb

  • Creates new Window class with full attribute management
  • Implements set_state method for BiDi browser.setClientWindowState
    command
  • Adds convenience methods: maximize, minimize, fullscreen, resize
  • Includes private update_attributes for state synchronization
+80/-0   
Tests
browser_spec.rb
Add window state operation tests                                                 

rb/spec/integration/selenium/webdriver/bidi/browser_spec.rb

  • Adds test for maximize window operation
  • Adds test for minimize window operation
  • Adds test for fullscreen window operation
  • Adds test for resize window with dimensions
  • Adds test for set_state with position parameters
  • All tests skipped for Chrome, Edge, Firefox until BiDi implementation
    available
+51/-0   
Documentation
browser.rbs
Update Browser type signatures                                                     

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

  • Adds @window instance variable type annotation
  • Removes inline Window type alias
  • Adds windows method signature returning Window array
  • Adds window method signature returning optional Window
  • Updates user_contexts return type to Hash with array
  • Updates remove_user_context return type annotation
+7/-4     
window.rbs
Add Window class type definitions                                               

rb/sig/lib/selenium/webdriver/bidi/browser/window.rbs

  • Defines Window class type signatures with attributes
  • Specifies reader/accessor properties for window dimensions and state
  • Documents all public methods with parameter and return types
  • Includes private method signatures for internal state updates
+45/-0   

@CLAassistant
Copy link

CLAassistant commented Dec 7, 2025

CLA assistant check
All committers have signed the CLA.

@selenium-ci selenium-ci added C-rb Ruby Bindings B-devtools Includes everything BiDi or Chrome DevTools related labels Dec 7, 2025
Copy link
Contributor

Copilot AI left a comment

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 implements the BiDi setClientWindowState method for Ruby bindings, adding window state management functionality. The implementation introduces a new Window class to handle window operations like maximizing, minimizing, fullscreen, and resizing.

Key changes:

  • Created a new Window class to encapsulate window state and operations
  • Added methods for window state manipulation (maximize, minimize, fullscreen, resize)
  • Integrated the new Window class into the Browser class, replacing the previous Struct-based implementation

Reviewed changes

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

Show a summary per file
File Description
rb/lib/selenium/webdriver/bidi/browser/window.rb New Window class implementation with state management methods
rb/lib/selenium/webdriver/bidi/browser.rb Updated to use new Window class and added window() method for retrieving active window
rb/sig/lib/selenium/webdriver/bidi/browser/window.rbs Type signature definitions for the new Window class
rb/sig/lib/selenium/webdriver/bidi/browser.rbs Updated type signatures to reflect Browser class changes
rb/spec/integration/selenium/webdriver/bidi/browser_spec.rb Added integration tests for window state operations
rb/Rakefile Modified bazel build command (appears incomplete)
rb/.vscode/settings.json Added VSCode Ruby LSP configuration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@aguspe aguspe force-pushed the rb_bidi_set_client_window_state branch from 7accf10 to e3b55a2 Compare December 10, 2025 21:25
@aguspe aguspe marked this pull request as ready for review December 10, 2025 21:34
@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Dec 10, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logs: New critical window state changes (maximize/minimize/fullscreen/resize) are executed
without emitting any audit/log entries identifying actor, timestamp, action, and outcome.

Referred Code
def set_state(state:, width: nil, height: nil, x: nil, y: nil)
  params = {clientWindow: @handle, state: state.to_s, width: width, height: height, x: x, y: y}.compact

  response = @bidi.send_cmd('browser.setClientWindowState', **params)
  update_attributes(state: state, width: width, height: height, x: x, y: y)
  response
end

def maximize
  set_state(state: :maximized)
end

def minimize
  set_state(state: :minimized)
end

def fullscreen
  set_state(state: :fullscreen)
end

def resize(width:, height:, x: nil, y: nil)


 ... (clipped 2 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Unhandled errors: Calls to send BiDi commands and state updates lack validation and error handling for
nil/invalid inputs and failed responses.

Referred Code
def set_state(state:, width: nil, height: nil, x: nil, y: nil)
  params = {clientWindow: @handle, state: state.to_s, width: width, height: height, x: x, y: y}.compact

  response = @bidi.send_cmd('browser.setClientWindowState', **params)
  update_attributes(state: state, width: width, height: height, x: x, y: y)
  response
end

def maximize
  set_state(state: :maximized)
end

def minimize
  set_state(state: :minimized)
end

def fullscreen
  set_state(state: :fullscreen)
end

def resize(width:, height:, x: nil, y: nil)


 ... (clipped 12 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Missing validation: External inputs to window state setters (width/height/x/y/state) are accepted and
forwarded without explicit validation or bounds checking.

Referred Code
def set_state(state:, width: nil, height: nil, x: nil, y: nil)
  params = {clientWindow: @handle, state: state.to_s, width: width, height: height, x: x, y: y}.compact

  response = @bidi.send_cmd('browser.setClientWindowState', **params)
  update_attributes(state: state, width: width, height: height, x: x, y: y)
  response
end

def maximize
  set_state(state: :maximized)
end

def minimize
  set_state(state: :minimized)
end

def fullscreen
  set_state(state: :fullscreen)
end

def resize(width:, height:, x: nil, y: nil)


 ... (clipped 2 lines)

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Dec 10, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Refresh window state after modification

After calling browser.setClientWindowState, refresh the Window object's
attributes by fetching the latest data from the browser instead of relying on
the input parameters. This ensures the object's state is consistent with the
actual window state.

rb/lib/selenium/webdriver/bidi/browser/window.rb [43-49]

 def set_state(state:, width: nil, height: nil, x: nil, y: nil)
   params = {clientWindow: @handle, state: state.to_s, width: width, height: height, x: x, y: y}.compact
 
   response = @bidi.send_cmd('browser.setClientWindowState', **params)
-  update_attributes(state: state, width: width, height: height, x: x, y: y)
+  refresh
   response
 end
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies that optimistically updating attributes in set_state leads to an inconsistent object state, especially for operations like maximize. Proposing to refresh the state from the browser is a critical fix for ensuring data integrity.

High
Replace optimistic update with state refresh

Replace the update_attributes method with a refresh method. This new method
should fetch the latest window data from the browser to ensure the Window
object's attributes are always synchronized with the actual browser window
state.

rb/lib/selenium/webdriver/bidi/browser/window.rb [67-75]

 private
 
-def update_attributes(state:, width:, height:, x:, y:)
-  @state = state.to_sym
-  @width = width.to_i if width
-  @height = height.to_i if height
-  @x = x.to_i if x
-  @y = y.to_i if y
+def refresh
+  response = @bidi.send_cmd('browser.getClientWindows')
+  win_data = response['clientWindows'].find { |win| win['clientWindow'] == @handle }
+
+  return unless win_data
+
+  @active = win_data['active']
+  @height = win_data['height'].to_i
+  @width = win_data['width'].to_i
+  @x = win_data['x'].to_i
+  @y = win_data['y'].to_i
+  @state = win_data['state'].to_sym
 end
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: This suggestion provides a robust implementation for fixing the inconsistent state issue by replacing the optimistic update_attributes method with a refresh method that fetches live data from the browser, which is a superior design for maintaining data integrity.

High
Remove caching to prevent stale data

Remove memoization from the window method to prevent returning a stale window
object. The method should always fetch the current list of windows to find the
active one on each call.

rb/lib/selenium/webdriver/bidi/browser.rb [67-69]

 def window
-  @window ||= windows.find(&:active?) || windows.first
+  wins = windows
+  wins.find(&:active?) || wins.first
 end
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a bug where caching the window object via @window ||= ... can lead to returning stale data if the active window changes. Removing the caching is crucial for the method's correctness.

Medium
High-level
Window state is updated optimistically

The Window object's state is updated optimistically with the requested values,
not the actual state returned by the browser. To prevent state discrepancies,
the object's state should be re-fetched from the browser after any modification.

Examples:

rb/lib/selenium/webdriver/bidi/browser/window.rb [43-49]
          def set_state(state:, width: nil, height: nil, x: nil, y: nil)
            params = {clientWindow: @handle, state: state.to_s, width: width, height: height, x: x, y: y}.compact

            response = @bidi.send_cmd('browser.setClientWindowState', **params)
            update_attributes(state: state, width: width, height: height, x: x, y: y)
            response
          end

Solution Walkthrough:

Before:

class Window
  def set_state(state:, width: nil, height: nil, ...)
    # Send command to browser to change window state
    @bidi.send_cmd('browser.setClientWindowState', ...)

    # Optimistically update local state with requested values
    update_attributes(state: state, width: width, height: height, ...)
  end

  private

  def update_attributes(state:, width:, height:, ...)
    @state = state.to_sym
    @width = width.to_i if width
    # ... and so on for other attributes
  end
end

After:

class Window
  def set_state(state:, width: nil, height: nil, ...)
    # Send command to browser to change window state
    @bidi.send_cmd('browser.setClientWindowState', ...)

    # Re-fetch the actual window state from the browser
    refresh_state
  end

  private

  def refresh_state
    response = @bidi.send_cmd('browser.getClientWindows')
    win_data = response['clientWindows'].find { |w| w['clientWindow'] == @handle }
    update_from_browser_data(win_data)
  end
end
Suggestion importance[1-10]: 8

__

Why: This is a valid and significant design suggestion that correctly identifies a potential for state inconsistency, which could lead to subtle bugs.

Medium
  • Update

@aguspe aguspe force-pushed the rb_bidi_set_client_window_state branch from 0345b23 to 4b690c0 Compare December 10, 2025 21:46
@aguspe aguspe self-assigned this Dec 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-devtools Includes everything BiDi or Chrome DevTools related C-rb Ruby Bindings Review effort 2/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants