[ Bug]: [py] browser.set_client_window_state nests the rect state under "state" instead of sending sibling params
Description
driver.browser.set_client_window_state() builds a non-conformant wire message whenever the window state is given as a rect rather than a named string. It nests the whole rect state under the state key, where the spec requires state to be the string "normal" and width / height / x / y to be siblings of clientWindow in the params map.
Because the rect object is the only way to pass a size or position, there is currently no working way to set a client window rect from Python.
Root cause
The spec splices the variant into the enclosing params map with a CDDL group choice, so the variant's members are siblings, not a nested value:
browser.SetClientWindowStateParameters = {
clientWindow: browser.ClientWindow,
(browser.ClientWindowNamedState // browser.ClientWindowRectState)
}
browser.ClientWindowNamedState = (
state: "fullscreen" / "maximized" / "minimized"
)
browser.ClientWindowRectState = (
state: "normal",
? width: js-uint,
? height: js-uint,
? x: js-int,
? y: js-int,
)The hand-written method treats the group choice as a nested object instead — py/private/bidi_enhancements_manifest.py:186-199, emitted to selenium/webdriver/common/bidi/browser.py:337:
state_param = state
if hasattr(state, '__dataclass_fields__'):
state_param = {k: v for k, v in state.__dict__.items() if v is not None}
params = {
"clientWindow": client_window,
"state": state_param, # <- the whole rect ends up here
}Reproducible code
from selenium.webdriver.common.bidi.browser import ClientWindowRectState
windows = driver.browser.get_client_windows()
driver.browser.set_client_window_state(
client_window=windows[0].client_window,
state=ClientWindowRectState(width=800, height=600),
)Sent:
{"clientWindow": "...", "state": {"state": "normal", "width": 800, "height": 600}}Required:
{"clientWindow": "...", "state": "normal", "width": 800, "height": 600}state is an object where the spec requires a string, so a conformant browser rejects the command with invalid argument.
A plain dict is documented as accepted too (state: ... - A dict representing the state) and fails the same way — it isn't a dataclass, so it is passed through and nested verbatim.
What does work
The named-string path is fine: state="fullscreen" / "maximized" / "minimized" produce {"clientWindow": ..., "state": "maximized"}.
state="normal" also works, and produces a valid ClientWindowRectState with every optional member omitted — it just can't carry a rect.
Notes
- Untested. There is no coverage for
set_client_window_stateanywhere underpy/test/, which is why this has gone unnoticed. - The generated low-level layer already models this correctly.
selenium/webdriver/common/_bidi/browser.pyemitsSetClientWindowStateParametersClientWindowRectStatewithclient_window,state(baked"normal",init=False),width,height,x,yall as siblings, and aUniondiscriminated onstate. So the fix can either flatten the params by hand or delegate to_bidi, depending on where the #17670 transition lands. - Confirmed against the pinned CDDL in this repo (
browser.SetClientWindowStateParameters). Not yet confirmed against a live browser — the wire shape is wrong regardless, but the exact error a given browser returns is unverified.
Cross-binding
Worth checking whether the other bindings flatten the group choice correctly before fixing only Python.
Source: SeleniumHQ/selenium