selenium icon indicating copy to clipboard operation
selenium copied to clipboard

[rb] Set window state rb bidi

Open aguspe opened this issue 1 month ago • 1 comments

💥 What does this PR do?

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

🔧 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!)

aguspe avatar Dec 07 '25 20:12 aguspe

CLA assistant check
All committers have signed the CLA.

CLAassistant avatar Dec 07 '25 20:12 CLAassistant

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 <!-- /create_ticket --create_ticket=true -->
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 --update_compliance=true -->
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

qodo-code-review[bot] avatar Dec 10 '25 21:12 qodo-code-review[bot]

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 <!-- /improve --apply_suggestion=0 -->
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 <!-- /improve --apply_suggestion=1 -->
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 <!-- /improve --apply_suggestion=2 -->
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 <!-- /improve_multi --more_suggestions=true -->

qodo-code-review[bot] avatar Dec 10 '25 21:12 qodo-code-review[bot]