Repository navigation
v0.2.0
Added
-
One endpoint per probe:
/health(liveness, and deliberately independent of the Grid),/started(startup),/ready(readiness, which is the one that asks the Grid) and/info(version, mount, what it is wired to). All four answer at the root as well as under the prefix. -
outlinemaps the page — every element worth acting on, with a selector checked to match exactly one, and whether it can be used. -
A failed click says why, and what to do: a hidden ancestor, something on top of it, no size, off-screen, disabled.
-
A flow can say what must be true.
assertruns JavaScript that has to come backtrue, and fails with the message you wrote. -
Two prompts a person can pick.
repair_flowfixes a flow against the page it now fails on;build_flowwalks a task by hand and saves what worked. -
A failed run says where to read and which prompt repairs it.
-
press_keytakes the browser's key names, single characters and combinations —ArrowLeft,/,Control+a,Shift+Tab. -
dragdrags an element onto another, or by an offset —drag(selector={"css": ".card"}, to={"css": ".done"})ordrag(selector={"css": "input[type=range]"}, by_x=120). Real pointer input, so range sliders respond, and on Chrome it drives native HTML5 drag-and-drop as well. -
interacttakesglide— the pointer travels in steps instead of jumping, for interfaces that watch movement rather than arrival. -
asserttakesstable_for— the answer must still be true that many seconds later, which is what a guard needs and what asking until true cannot give it. -
upload_filetakeskept, the name of a filekeep_filekept — download an export from one site and upload it to another without the bytes passing through you. -
open_session(fresh=true)opens on a blank page instead of returning to the one your session was last on.
Changed
-
The server's instructions name the embedded skill, so a client is told where the how-to lives when it connects rather than after its first failure. Omitted when the skill is not being served.
-
BREAKING:
ROUTE_PREFIXmounts the whole server, and defaults to/. Every tree is fixed beneath it —/browser,/flows,/files,/admin,/mcp,/openapi.yaml— where it used to rename/browserwhile everything else stayed put. -
The admin UI is at the server root, with its views after the hash (
#/sessions/<name>), so a view survives a reload and can be linked to./adminredirects there and remains the API the page calls. -
BREAKING: every session is named by its caller. Add
?session=<name>to the URL or send anX-Session-Keyheader; sending both, or neither, is refused. There is nosession_idon any tool, in any request body, or in any result — call again with the same name to get the same browser back. -
BREAKING: the HTTP surface is REST.
GET /flows/{name},PUTto save it,DELETEto remove it,POST /flows/{name}/runsto run it;POST /browseropens your browser,DELETE /browserends it,GET /browsersays what you are holding; a mouse action is a path —POST /browser/interact/click. Files areGET /filesandPUT /files/{name}/kept. -
BREAKING:
xpathandcssare oneselector.interact(selector={"css": "button.go"}), anddragtakesselectorandto. Exactly one of the two, never both — and never a fallback from one to the other. -
SAVED_SESSIONSis gone, along with the two session modes it switched between. There is one contract now. -
A browser opened over HTTP is a session like any other — it appears in the admin list, slides its TTL, and is reopened where it left off after the Grid reaps it.
-
Screenshots are kept with the session's files by default, and come back with a link anyone can open — signed and time-limited when the server has a token, a plain path when authentication is off.
screenshot(save=false)opts out, and a page that refuses the download returnsfile_errorwith the image. -
BREAKING: a stored file is now described the way
session_filesdescribes one —createdinstead ofcreationTime, pluscontent_type,image,kept,urlandabsolute_url. Affects thefileinscreenshotandsave_pdfresults. -
Tools list their fixed choices in their schemas — every
interact,dialogandframeaction, andopen_session's browsers — so a client can show them, and a flow naming one that does not exist is refused when it is saved. -
Every mouse gesture moves the pointer onto the element first, so after a click the pointer is on what you clicked and a
:hovermenu stays open across it. The click itself is unchanged, so a covered target is still refused. -
outlinesays what reveals a hidden element, not just what blocks it —revealed_bycarries the trigger's selector andopen_withsays whether to click it or hover it. -
A run report says where each step went when the page changed, without
verbose. -
A saved flow that starts on whatever page you happen to be on is warned about — not refused.
Fixed
-
An unreachable Grid no longer writes its credentials into the log. The URL is stripped from every failure message and from the traceback, not only from the one failure known to quote it.
-
A flow step that captures a file says where it went. A screenshot's link is in the run report without needing
return: true— a capture nobody can find cannot show anyone what it saw. -
The admin flow panel shows a selector as one expression —
css button.go— instead of a raw JSON object. -
The Grid's URL no longer appears with its credentials in
/readyor/info, which answer to anyone. -
A click on a page that repaints itself is no longer racy — the element is found again and the action retried once, rather than failing with a stale reference. Found by the admin page's own session list, which refreshes every two seconds.
-
The admin page lists sessions again on Redis — it went blank once any browser had been pointed at something.
-
A screenshot of a page the browser will not download from no longer costs fifteen seconds. It says so straight away and still returns the image.
-
A saved file is named for what it actually is —
screenshot(filename="chart.pdf")is stored as a PNG. -
A hover onto something the pointer was already on did nothing and reported success. The pointer now steps aside first, and the result says
nudged. -
The advice for a hidden menu said "hover" even when the page said it opens on click. It reads
aria-expandednow and says which. -
outlineno longer offers a selector built from a container's concatenated descendant text, and no longer skips an<a>for having nohref. -
An unkept file says what would keep it —
keep_withon every entry whose link dies with the browser. -
A glide to something below the fold works. It used to send coordinates outside the window, which WebDriver refuses, and the whole move was lost.
-
A drag step with no element or no destination is refused when it is saved, rather than at run time.
-
upload_filenaming a kept file that is not there answers 400, like naming apaththat is not there — not 500. -
POST /browser/uploadtakessession, naming the library a kept file belongs to — the same way/files/keepalready does, so a file kept into a named session can be uploaded back out of it. -
A drag that failed because the browser had gone says so — 404 with the fix, instead of 400 blaming the element's shape.
-
A drag whose source is taller than the window works. The pointer's position is now where WebDriver actually puts it — the element's in-view center — rather than the center of a rectangle running off the screen.
-
A flow that uploads a kept file reads it from the library the run belongs to, not from the shared
globalone. -
assertrefuses astable_forit cannot read instead of silently dropping the stability check, and no longer accepts an answer a slow script returned afterwait_timeouthad passed.
What's Changed
- ci(deps): Bump actions/upload-artifact from 5 to 7 by @dependabot[bot] in #24
- Tools show their choices, and press_key takes what a browser calls a key by @kferrone in #25
- assert: a flow can say what must be true by @kferrone in #26
- Every screenshot is saved, and the link is what you hand a person by @kferrone in #28
- outline: what is on the page, and whether it can be used by @kferrone in #29
- Two prompts a person can pick, and a failed run that names one by @kferrone in #30
- The pointer the server remembers, and the last of the pilot reports by @kferrone in #31
- JavaScript in js/, Copilot's third pass, and the session design by @kferrone in #32
- The server flies its own admin page, and the list is back by @kferrone in #33
- One named session, a RESTful HTTP surface, and one selector by @kferrone in #34
- ROUTE_PREFIX mounts the whole server, the UI moves to its root, and one endpoint per probe by @kferrone in #35
- The refit: rooms in the package, one way to answer a request by @kferrone in #36
Full Changelog: v0.1.0...v0.2.0
Container image
The image is what this repo ships, and what the cluster runs:
docker pull kubed/selenium-flow:v0.2.0Python package
Not on PyPI. The wheel and sdist are attached to this release:
pip install https://github.com/kubed-io/selenium-flow/releases/download/v0.2.0/kubed_selenium_flow-0.2.0-py3-none-any.whlOr straight from the tag:
pip install git+https://github.com/kubed-io/selenium-flow.git@v0.2.0