Skip to content

v0.2.0

Choose a tag to compare

@kubed-io kubed-io released this 16 Sep 02:54
· 48 commits to main since this release
d5bf435

Publish
Image Builder
Tests
Quality

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.

  • outline maps 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. assert runs JavaScript that has to come back true, and fails with the message you wrote.

  • Two prompts a person can pick. repair_flow fixes a flow against the page it now fails on; build_flow walks a task by hand and saves what worked.

  • A failed run says where to read and which prompt repairs it.

  • press_key takes the browser's key names, single characters and combinations — ArrowLeft, /, Control+a, Shift+Tab.

  • drag drags an element onto another, or by an offset — drag(selector={"css": ".card"}, to={"css": ".done"}) or drag(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.

  • interact takes glide — the pointer travels in steps instead of jumping, for interfaces that watch movement rather than arrival.

  • assert takes stable_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_file takes kept, the name of a file keep_file kept — 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_PREFIX mounts the whole server, and defaults to /. Every tree is fixed beneath it — /browser, /flows, /files, /admin, /mcp, /openapi.yaml — where it used to rename /browser while 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. /admin redirects there and remains the API the page calls.

  • BREAKING: every session is named by its caller. Add ?session=<name> to the URL or send an X-Session-Key header; sending both, or neither, is refused. There is no session_id on 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}, PUT to save it, DELETE to remove it, POST /flows/{name}/runs to run it; POST /browser opens your browser, DELETE /browser ends it, GET /browser says what you are holding; a mouse action is a path — POST /browser/interact/click. Files are GET /files and PUT /files/{name}/kept.

  • BREAKING: xpath and css are one selector. interact(selector={"css": "button.go"}), and drag takes selector and to. Exactly one of the two, never both — and never a fallback from one to the other.

  • SAVED_SESSIONS is 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 returns file_error with the image.

  • BREAKING: a stored file is now described the way session_files describes one — created instead of creationTime, plus content_type, image, kept, url and absolute_url. Affects the file in screenshot and save_pdf results.

  • Tools list their fixed choices in their schemas — every interact, dialog and frame action, and open_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 :hover menu stays open across it. The click itself is unchanged, so a covered target is still refused.

  • outline says what reveals a hidden element, not just what blocks it — revealed_by carries the trigger's selector and open_with says 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 /ready or /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-expanded now and says which.

  • outline no longer offers a selector built from a container's concatenated descendant text, and no longer skips an <a> for having no href.

  • An unkept file says what would keep it — keep_with on 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_file naming a kept file that is not there answers 400, like naming a path that is not there — not 500.

  • POST /browser/upload takes session, naming the library a kept file belongs to — the same way /files/keep already 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 global one.

  • assert refuses a stable_for it cannot read instead of silently dropping the stability check, and no longer accepts an answer a slow script returned after wait_timeout had 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.0

Python 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.whl

Or straight from the tag:

pip install git+https://github.com/kubed-io/selenium-flow.git@v0.2.0