Skip to content

Conversation

@navin772
Copy link
Member

@navin772 navin772 commented Dec 8, 2025

User description

🔗 Related Issues

💥 What does this PR do?

Adds support for set_network_conditions command in the emulation module - https://w3c.github.io/webdriver-bidi/#command-emulation-setNetworkConditions

🔧 Implementation Notes

💡 Additional Considerations

Only Chrome supports this from 143, Edge might also support from 143 (we have 142 currently in trunk).

🔄 Types of changes

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

PR Type

Enhancement


Description

  • Adds set_network_conditions emulation command for BiDi

  • Supports offline network condition emulation via contexts

  • Supports offline network condition emulation via user contexts

  • Includes comprehensive tests for both context types


Diagram Walkthrough

flowchart LR
  A["Emulation Module"] -->|"add method"| B["set_network_conditions"]
  B -->|"accepts"| C["offline parameter"]
  B -->|"accepts"| D["contexts or user_contexts"]
  C -->|"creates"| E["networkConditions payload"]
  D -->|"validates"| F["mutual exclusivity"]
  E -->|"executes"| G["BiDi command"]
  H["Test Suite"] -->|"validates"| I["offline with contexts"]
  H -->|"validates"| J["offline with user_contexts"]
Loading

File Walkthrough

Relevant files
Enhancement
emulation.py
Add set_network_conditions emulation method                           

py/selenium/webdriver/common/bidi/emulation.py

  • Adds new set_network_conditions method to Emulation class
  • Accepts offline parameter to enable/disable offline mode
  • Accepts either contexts or user_contexts parameters
  • Includes validation to ensure mutual exclusivity and required
    parameters
  • Executes BiDi command with appropriate networkConditions payload
+38/-0   
Tests
bidi_emulation_tests.py
Add network conditions emulation tests                                     

py/test/selenium/webdriver/common/bidi_emulation_tests.py

  • Adds helper function is_online to check navigator.onLine status
  • Adds test for offline conditions with browsing contexts
  • Adds test for offline conditions with user contexts
  • Tests both enabling and disabling offline mode
  • Marks tests as expected to fail on Firefox and Edge
+48/-0   

@selenium-ci selenium-ci added C-py Python Bindings B-devtools Includes everything BiDi or Chrome DevTools related labels Dec 8, 2025
@qodo-code-review
Copy link
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Protocol parameter risk

Description: The code sends None for 'networkConditions' to clear overrides, which may be invalid per
protocol; if the backend echoes or logs parameters unsafely this could cause unexpected
behavior—verify protocol requires explicit clearing to avoid unintended states.
emulation.py [460-465]

Referred Code
if offline:
    params["networkConditions"] = {"type": "offline"}
else:
    # if offline is False or None, then clear the override
    params["networkConditions"] = None
Ticket Compliance
🟡
🎫 #5678
🔴 Investigate and fix repeated "Error: ConnectFailure (Connection refused)" when
instantiating multiple ChromeDriver instances on Ubuntu 16.04 with Chrome 65 /
chromedriver 2.35 and Selenium 3.9.0.
Ensure subsequent ChromeDriver instantiations do not log the ConnectFailure error while
the first instance works.
Provide guidance or code changes that prevent the connection refusal across multiple
sessions.
🟡
🎫 #1234
🔴 Ensure WebDriver 2.48 triggers javascript in link href on click() as it did in 2.47.1
(Firefox 42).
Provide regression fix or behavioral alignment so click() executes href-based JS.
Validate via test that alert is triggered by clicking a link with javascript: in href.
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: The new method executes a critical emulation command without emitting any audit log
entries indicating who triggered it, when, and with what parameters.

Referred Code
def set_network_conditions(
    self,
    offline: bool | None = None,
    contexts: list[str] | None = None,
    user_contexts: list[str] | None = None,
) -> None:
    """Set network conditions for the given contexts or user contexts.

    Args:
        offline: True to emulate offline network conditions, False or None to disable.
        contexts: List of browsing context IDs to apply the conditions to.
        user_contexts: List of user context IDs to apply the conditions to.

    Raises:
        ValueError: If both contexts and user_contexts are provided, or if neither
            contexts nor user_contexts are provided.
    """
    if contexts is not None and user_contexts is not None:
        raise ValueError("Cannot specify both contexts and user_contexts")

    if contexts is None and user_contexts is None:


 ... (clipped 16 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:
Input validation: The method validates mutual exclusivity but does not validate types/emptiness of lists or
handle execution failures from the BiDi command with contextual errors.

Referred Code
if contexts is not None and user_contexts is not None:
    raise ValueError("Cannot specify both contexts and user_contexts")

if contexts is None and user_contexts is None:
    raise ValueError("Must specify either contexts or user_contexts")

params: dict[str, Any] = {}

if offline:
    params["networkConditions"] = {"type": "offline"}
else:
    # if offline is False or None, then clear the override
    params["networkConditions"] = None

if contexts is not None:
    params["contexts"] = contexts
elif user_contexts is not None:
    params["userContexts"] = user_contexts

self.conn.execute(command_builder("emulation.setNetworkConditions", params))

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:
Weak validation: External inputs like context IDs are passed through without validation or sanitization,
and there is no safeguard against empty lists or invalid identifiers before sending to the
backend.

Referred Code
if contexts is not None and user_contexts is not None:
    raise ValueError("Cannot specify both contexts and user_contexts")

if contexts is None and user_contexts is None:
    raise ValueError("Must specify either contexts or user_contexts")

params: dict[str, Any] = {}

if offline:
    params["networkConditions"] = {"type": "offline"}
else:
    # if offline is False or None, then clear the override
    params["networkConditions"] = None

if contexts is not None:
    params["contexts"] = contexts
elif user_contexts is not None:
    params["userContexts"] = user_contexts

self.conn.execute(command_builder("emulation.setNetworkConditions", params))

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

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

@qodo-code-review
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Implement the full network conditions spec

The set_network_conditions method should be extended to support the full
WebDriver BiDi specification, which includes emulating various network speeds
with specific latency and throughput, not just the 'offline' state.

Examples:

py/selenium/webdriver/common/bidi/emulation.py [435-471]
    def set_network_conditions(
        self,
        offline: bool | None = None,
        contexts: list[str] | None = None,
        user_contexts: list[str] | None = None,
    ) -> None:
        """Set network conditions for the given contexts or user contexts.

        Args:
            offline: True to emulate offline network conditions, False or None to disable.

 ... (clipped 27 lines)

Solution Walkthrough:

Before:

class Emulation:
    def set_network_conditions(
        self,
        offline: bool | None = None,
        contexts: list[str] | None = None,
        user_contexts: list[str] | None = None,
    ) -> None:
        # ...
        params: dict[str, Any] = {}

        if offline:
            params["networkConditions"] = {"type": "offline"}
        else:
            # if offline is False or None, then clear the override
            params["networkConditions"] = None
        # ...
        self.conn.execute(command_builder("emulation.setNetworkConditions", params))

After:

class Emulation:
    def set_network_conditions(
        self,
        offline: bool = False,
        latency: int | None = None,
        download_throughput: int | None = None,
        upload_throughput: int | None = None,
        contexts: list[str] | None = None,
        user_contexts: list[str] | None = None,
    ) -> None:
        # ...
        params: dict[str, Any] = {}
        if offline:
            params["networkConditions"] = {"type": "offline"}
        elif latency is not None or download_throughput is not None or upload_throughput is not None:
            conditions = {"type": "network"}
            if latency is not None: conditions["latency"] = latency
            # ... add other throughput values
            params["networkConditions"] = conditions
        else:
            params["networkConditions"] = None
        # ...
        self.conn.execute(command_builder("emulation.setNetworkConditions", params))
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the PR only partially implements the WebDriver BiDi spec for set_network_conditions, omitting network speed and latency emulation, which is a significant part of the feature.

Medium
Learned
best practice
Always cleanup network overrides

Wrap the network conditions override with try/finally and reset in finally to
guarantee cleanup even if assertions fail.

py/test/selenium/webdriver/common/bidi_emulation_tests.py [584-598]

 @pytest.mark.xfail_firefox
 @pytest.mark.xfail_edge
 def test_set_network_conditions_offline_with_context(driver, pages):
     context_id = driver.current_window_handle
     driver.browsing_context.navigate(context_id, pages.url("formPage.html"), wait="complete")
 
     assert is_online(driver, context_id) is True
 
-    # Set offline
-    driver.emulation.set_network_conditions(offline=True, contexts=[context_id])
-    assert is_online(driver, context_id) is False
+    try:
+        # Set offline
+        driver.emulation.set_network_conditions(offline=True, contexts=[context_id])
+        assert is_online(driver, context_id) is False
+    finally:
+        # Always reset
+        driver.emulation.set_network_conditions(offline=None, contexts=[context_id])
 
-    # Reset
-    driver.emulation.set_network_conditions(offline=None, contexts=[context_id])
     assert is_online(driver, context_id) is True
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Pattern 1: Ensure external contexts/resources are cleaned up using try/finally to prevent leaks.

Low
General
Improve method signature for clarity

To improve clarity and avoid unexpected side effects, change the offline
parameter in set_network_conditions to be a required boolean instead of bool |
None.

py/selenium/webdriver/common/bidi/emulation.py [460-464]

 if offline:
     params["networkConditions"] = {"type": "offline"}
 else:
-    # if offline is False or None, then clear the override
+    # if offline is False, then clear the override
     params["networkConditions"] = None
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that offline=False and offline=None have the same behavior, which could be confusing. Making offline a required boolean would improve API clarity, but the current implementation is consistent with other methods in the same class where None is used to clear an override.

Low
Use explicit boolean for test clarity

In the test test_set_network_conditions_offline_with_context, use offline=False
instead of offline=None to explicitly reset the network conditions, which
improves test readability.

py/test/selenium/webdriver/common/bidi_emulation_tests.py [596-598]

 # Reset
-driver.emulation.set_network_conditions(offline=None, contexts=[context_id])
+driver.emulation.set_network_conditions(offline=False, contexts=[context_id])
 assert is_online(driver, context_id) is True
  • Apply / Chat
Suggestion importance[1-10]: 4

__

Why: The suggestion to use offline=False instead of offline=None for resetting network conditions is a valid point for improving test clarity and explicitness, though the current implementation with None is functionally correct.

Low
  • More

@navin772 navin772 requested a review from cgoldberg December 8, 2025 07:45
Copy link
Member

@cgoldberg cgoldberg left a comment

Choose a reason for hiding this comment

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

Nice.

The AI bot had some good suggestions. To summarize:

  • Change the default and type hint for offline to False (offline=False)
  • Add a try/finally to the tests, so it always resets even if the test fails

Also, do browsers support latency and download/upload throughput conditions? If so, we should add those.

Is CI failing because we don't have Chrome 143 yet?

@navin772
Copy link
Member Author

navin772 commented Dec 8, 2025

Also, do browsers support latency and download/upload throughput conditions? If so, we should add those.

They will support these in the future, currently as per spec, only offline is supported.

Is CI failing because we don't have Chrome 143 yet?

Only the windows CI is failing because they are not using the pinned browser, they use default gh actions chrome browser which is currently at 142, we had this issue earlier too. Once github has 143 as latest browser, the CI will pass.

@navin772
Copy link
Member Author

navin772 commented Dec 8, 2025

Change the default and type hint for offline to False (offline=False)

Actually, the spec doesn't allows a boolean value, I added it for API simplicity, type: "offline" is what we send, I abstracted it to a boolean.
None resets to default.

@cgoldberg do you see any issue with this approach?

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-py Python Bindings Review effort 2/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants