Chapter 07Lesson 04~150 minutes

Keyboard, Pointer, Wheel, and Composite Actions API: Diagnostics, Failure Modes, and Production Practices

Diagnose composite-input failures by preserving first-failure evidence and isolating context, focus, input state, origin, geometry, browser event behavior, and application state—without hiding the cause behind retries, fixed pixels, JavaScript bypasses, or restarts.

DiagnosticsMoveTargetOutOfBoundsInput cleanupContextEvidence

Learning objectives

  • Apply the academy diagnostic sequence to Actions failures before changing the test.
  • Diagnose wrong coordinate origins, leaked modifiers, moving/obscured targets, context mismatches, and event-order differences.
  • Interpret MoveTargetOutOfBoundsException and application-event evidence from an intentionally broken action.
  • Distinguish browser/session startup, action dispatch, AUT/network latency, evidence I/O, and retry cost when discussing performance.
  • Use least-destructive corrections that preserve user semantics instead of JavaScript or giant timeout workarounds.
  • Capture privacy-safe first-failure evidence and clean virtual input state before teardown.

1. Standard diagnostic sequence for Actions incidents

  1. Preserve first-failure evidence: screenshot, current URL/context, focus, target rectangles, status/event log, exception.
  2. Confirm versions: Selenium binding, browser, driver/remote end, Grid if used.
  3. Confirm target/environment/test data: correct loopback fixture or authorized test environment, viewport/platform, synthetic state.
  4. Inspect session/capabilities/context: session ID, current window/frame, active element.
  5. Inspect locator/element/synchronization state: current source/target elements, display/enabled state, rerender/staleness, wait contract.
  6. Inspect AUT/browser evidence: event log, application status, overlay/animation/layout state.
  7. Inspect Grid/CI/resource state if remote: node browser/platform/viewport, queue/resource pressure, artifacts.
  8. Apply the least destructive correction and rerun the smallest controlled scenario.

This order prevents an Actions symptom from immediately becoming “increase duration,” “retry,” or “use JavaScript.”

2. Failure-mode map

The following table organizes the key choices and evidence for Failure-mode map. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Symptom Likely layer Evidence first Least-destructive direction
Pointer lands outside intended control origin/layout/history target rect, viewport, pointer path/event log use element semantic origin or recompute controlled geometry
Text remains shifted/capitalized input state keydown/up log, current sequence balance modifier up; release/reset actions
Target moves during sequence AUT synchronization/layout before/after rect, animation/state flag wait for semantic stable state, then refind target
Click/drag intercepted DOM/layout/interactability screenshot, overlay target, event log wait/close legitimate overlay; do not force JavaScript click
Different event micro-order across browser browser/AUT contract browser capability + event trace + business state assert stable semantic outcome unless event order is contractual
Works in top page but not frame browsing context current context + locator failure/evidence switch to correct context; Chapter 08 covers this deeply

3. Intentionally broken example: wrong coordinate assumption

The following local-only diagnostic deliberately asks the pointer to move far outside a normal viewport. The expected result is typically MoveTargetOutOfBoundsException. Its purpose is to teach interpretation, not a production technique.

import json
from pathlib import Path
from urllib.parse import urlparse

import selenium
from selenium import webdriver
from selenium.common.exceptions import MoveTargetOutOfBoundsException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By

BASE = "http://127.0.0.1:8771/"
if (urlparse(BASE).hostname or "") not in {"127.0.0.1", "localhost", "::1"}:
    raise RuntimeError("Loopback fixture required")

Path("evidence").mkdir(exist_ok=True)
driver = webdriver.Chrome()
actions = ActionChains(driver)
try:
    driver.get(BASE)
    target = driver.find_element(By.ID, "token")
    evidence = {
        "selenium": selenium.__version__,
        "session": driver.session_id,
        "browser": driver.capabilities.get("browserName"),
        "browserVersion": driver.capabilities.get("browserVersion"),
        "target_rect": target.rect,
        "active_id": driver.switch_to.active_element.get_attribute("id"),
    }
    try:
        # INTENTIONALLY BROKEN: offset depends on current pointer and exceeds viewport.
        ActionChains(driver).move_by_offset(5000, 5000).click().perform()
        evidence["unexpected"] = "out-of-bounds action did not fail"
    except MoveTargetOutOfBoundsException as exc:
        evidence["exception"] = type(exc).__name__
        evidence["message_prefix"] = str(exc)[:240]
        driver.save_screenshot("evidence/out-of-bounds.png")
    Path("evidence/out-of-bounds.json").write_text(json.dumps(evidence, indent=2), encoding="utf-8")
finally:
    try:
        actions.reset_actions()
    finally:
        driver.quit()

Interpretation: the failure says the requested pointer movement cannot be dispatched within the allowed browsing-context geometry. It does not mean “Selenium is slow.” Adding a sleep cannot turn an out-of-bounds origin into the correct target.

4. Repair the intent, not the symptom

The following example makes the Repair the intent, not the symptom behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.

from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By

target = driver.find_element(By.ID, "token")
assert target.is_displayed()

# Semantic repair: resolve the current element geometry through WebDriver.
ActionChains(driver).move_to_element(target).click().perform()

If the product requirement is “activate the token,” a normal target.click() may be even better. If the requirement specifically verifies hover/pointer behavior, move_to_element() retains that semantic. The repair should match the test intent.

5. Modifier left pressed: a state leak, not random text corruption

A common diagnostic trap is to press Shift/Control and forget the corresponding key-up. The next sequence inherits session input state. Always balance explicit modifier actions, and defensively release action state on failure.

from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys

actions = ActionChains(driver)
try:
    actions.key_down(Keys.SHIFT).send_keys("abc").key_up(Keys.SHIFT).perform()
finally:
    actions.reset_actions()

If evidence shows a modifier remained down, fix the sequence lifecycle. Recreating the browser after every failure can hide the leak but does not correct the test.

6. Element moves or rerenders during an action

Actions use current element/context geometry at dispatch. Modern UIs may animate, replace, or move an element between lookup and use. A stale reference or unexpected pointer target is therefore often a synchronization/state problem.

Preserve the original target rectangle and screenshot, wait for an application-specific stable state, then locate the current element again. Do not cache a WebElement through a known rerender. Chapter 06’s condition-based synchronization applies here directly.

7. Browser/platform event-order differences

Different engines may expose small event-order/timing differences while producing the same user-visible result. Decide whether the event sequence itself is contractual. For most product tests, assert the stable semantic state—selected item, opened menu, committed value—and preserve event traces only as diagnostics.

If exact event ordering is a product requirement, scope the expectation by browser/platform/version and verify it against the application specification. Do not silently normalize a real incompatibility.

8. Correct sequence, wrong browsing context

Actions are dispatched to the session’s current browsing context. If the intended target is inside a frame and the session remains at the top-level document, a locator may fail before the action, or an unfocused key sequence may reach the wrong document. Preserve the current URL, window handle, active element, and locator/context evidence. Chapter 08 will teach switching windows/frames systematically.

9. Troubleshooting shortcuts that hide causes

  • Blanket retries: can turn deterministic origin/context errors into intermittent-looking noise.
  • Giant sleeps/action pauses: cannot repair wrong identity, origin, or context and inflate suite runtime.
  • JavaScript force-click/state injection: bypasses the WebDriver user-interaction contract.
  • Browser/Grid restart: may erase leaked state/evidence without diagnosing it.
  • TLS disablement: unrelated to Actions and weakens security.
  • Production experiments: unsafe; all failure injection belongs in disposable authorized fixtures.

10. Performance: attribute cost to the correct layer

When an Actions test is slow, separate test-runner overhead, session startup, Grid queue/capacity (if remote), pointer/action duration, AUT/network response, synchronization, evidence I/O, and retries. Changing pointer duration is justified only when the interaction itself needs that timing; it is not a general speed knob.

Measure the smallest scenario first. A single screenshot/event-log write on first failure is usually better evidence than capturing high-volume diagnostics on every passing tick.

11. Summary and next step

Actions incidents are usually explainable through context, input state, origin, target geometry, synchronization, browser behavior, and application state. Preserve those layers before destructive changes, then repair the semantic mismatch.

Knowledge check

Why does a MoveTargetOutOfBoundsException not justify a longer sleep?

What evidence helps diagnose a modifier leak?

Why can restarting the browser make diagnosis worse?

When should event micro-order be asserted cross-browser?

An Actions sequence targets an iframe control but the current context is top-level. What is the least destructive correction?

Next lesson

Checkpoint: prove a robust keyboard + wheel interaction

Lesson 5 builds an accessible priority board, records focus/event evidence, intentionally creates a coordinate error, and rewrites the action around element/state semantics.

Official references and version notes

Version and compatibility note

Version-sensitive behavior was rechecked against current primary documentation on 2026-08-28. Mandatory examples pin Selenium Python 4.47.0, require Python 3.10+, use a supported local Chromium-family browser with the actual browser/driver/session provenance recorded at runtime, and use only loopback fixtures. Wheel and detailed pointer behavior can differ at browser/platform edges; assertions therefore target application/focus/event state rather than incidental pixel coordinates. The examples intentionally avoid low-level private ActionBuilder internals except where public documentation is referenced; normal teaching uses public ActionChains conveniences.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.