Skip to content

Run controls and rerun for Python #324

Description

@vishnuv688

Part of #277

Split out of #289, which bundled two capabilities: making the dashboard's run
controls work at all, and preserving a run to diff against a rerun. This is the
first half, and it is the larger one — #289 keeps the preserve-and-diff scope and
now depends on this.

RUN_CAPABILITIES in constants.py hard-codes every control off:

RUN_CAPABILITIES = {"canRunSuites": False, "canRunTests": False, "canRunAll": False}

so Run / Rerun / Run-all are refused outright, and the adapter sends neither a
launch nor a rerun command. Its own comment says to revisit this with the
Preserve-and-Rerun work.

runner.ts already has a non-wdio launch path — #spawnGeneric runs an
arbitrary command from payload.rerunCommand, falling back to launchCommand
which is what Nightwatch and Selenium-JS use.

packages/selenium-devtools/src/rerunManager.ts is the closest prior art: it
captures the launch command from argv and builds a rerun template carrying a
per-runner filter flag (--grep, --testNamePattern, -t, --name). Python
needs one runner, and pytest's selector is not a flag but a nodeid
(file.py::Class::test), which is exact rather than a name match. It must also
strip an inherited selector from argv the way FILTER_FLAG_ALIASES does, or a
second rerun stacks selectors.

Corrections to this issue, from implementing it

Two claims written here before the work started turned out to be wrong.

"The backend needs no changes" is wrong. #resolveGenericCommand
substitutes its only slot, {{testName}}, through escapeFilterRegex, because
every runner that consumes it filters by regex (mocha --grep, jest
--testNamePattern, cucumber --name). A pytest nodeid is matched literally,
so the escaped form selects nothing: measured, pytest 'test_thing\.py::test_a'
collects nothing and exits 0, which reads as a rerun that ran and passed.
The backend needs a second slot that is substituted verbatim — filled from the
payload's uid, shell-quoted, never escaped.

The "known constraint from #297" below is wrong. A rerun does not travel
down the worker socket at all: POST /api/tests/run spawns a fresh process, and
the socket carries only clientConnected / clientDisconnected. The single
workerSocket slot therefore affects which process the dashboard's state
belongs to under pytest -n, not where a rerun is routed — and a rerun is
spawned as a single process regardless. Superseded text kept below for history.

Rerun requests travel OUTBOUND down the backend's single workerSocket, and
workerSocket = socket keeps only the most recent connect. Under pytest -n
every worker plus the controller connects, so a rerun request reaches whichever
process connected last rather than the one owning the test. Either handle it or
document it; do not discover it in #289.

Acceptance criteria

A failing test can be rerun from the dashboard for both pytest and a plain
script, or the control is refused with a stated reason where it cannot be
serviced. The run capabilities the adapter advertises match what it can actually
do. A test asserts the rerun command built for a pytest nodeid, and that a second
rerun does not stack selectors.

Depends on #282 and #287 (both closed).

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestselenium-devtools-pyPython Selenium adapter for the DevTools dashboard

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions