Skip to content

v0.20.0

Choose a tag to compare

@AminChirazi AminChirazi released this 28 Aug 11:14
· 71 commits to main since this release
453259e

Added

  • A same-origin framed Click and Press … button now dispatch a real
    trusted click, not a refusal.
    A classic SAP GUI for HTML screen embeds
    its whole UI in a same-origin iframe, and every tab strip, button, and
    field on it lived behind that frame boundary. Clicking one was refused
    outright: a pointer action inside a frame could only ever reach it as an
    untrusted synthetic event, which an application checking isTrusted is
    free to ignore while the step still reports success - a real
    release-without-effect false green, so the refusal was the honest answer
    at the time. It no longer has to be. The driver now computes the target's
    page-absolute point (the frame's own offset in the parent document, plus
    the element's offset inside the frame) and dispatches the same
    Input.dispatchMouseEvent sequence the top-level document's click
    already used - the click is real, isTrusted is true, and an application
    driven this way cannot tell the difference from a person. Hover,
    Double-click, Right-click, and Upload inside a frame stay refused;
    none has this point-computation wired up yet.

  • A framed Type into a real <input>/<textarea> now types for real.
    Framed value-writes previously set .value through the native setter and
    fired synthetic input/change events - correct for anything listening
    to those events, and wrong for anything that is not. A live SAP GUI for
    HTML screen tracks its own field state off real keyboard events, the same
    way its desktop ancestor always did, and never saw a synthetic write at
    all: the field stayed visibly empty no matter what the trace said it
    typed. The driver now clicks the field for real, selects any existing
    value, and types the real keystrokes CDP would generate for an actual
    person - the same trusted path the top-level document's Type already
    used. Anything framed that is not a native input (a contenteditable, a
    custom widget) keeps the synthetic write, since there is no native
    keystroke target to land on.

  • A framed element is now found by the label its OWN form control
    resolves to, not by matching arbitrary text.
    the "Material" in the iframe "X" used to search the frame for any element whose raw
    textContent read exactly "Material" - which, on a screen where the
    visible label and the input it labels are separate DOM nodes (common
    outside hand-rolled markup), matched the label itself, never the field.
    Typing then landed on a <div>, silently no-op'd through the
    now-corrected trusted-keystroke path, and the search it was meant to fill
    in ran empty. Both the write and read paths now check a form control's
    native .labels association first - the same relationship scene()
    already uses to report a field's label back to authoring - before falling
    back to the old plain-text search, so a label naming a real field finds
    that field.

  • flowproof record shows the browser by default; --headed/--headless
    make the choice a flag, not tribal knowledge.
    Watching a web recording
    has been possible since FLOWPROOF_HEADED shipped, but only if you already
    knew the variable existed - nothing in --help said so, and a new user
    evaluating flowproof against a tool like Tosca (where you always watch the
    browser while recording) got a blank terminal by default. Recording is the
    one human-in-the-loop step, so it now opens Chromium unless told not to;
    flowproof run (replay) is unchanged and stays headless, because it is
    meant to run unattended on CI runners that often have no display at all,
    and a default flip there risks the false-green class of bug this project
    exists to catch - headed Chromium sizes its window from the desktop, so a
    visual baseline recorded one way and replayed the other reports a mismatch
    that has nothing to do with the flow. Anything that scripts flowproof record without a person watching (CI, a container, a cassette-generation
    pipeline) needs --headless now; everything else needs nothing at all.

  • The SAP test simulator models more than one screen shape. Every
    automated SAP check ran against the same flat VA01 window - one wnd[0],
    every field hanging straight off it. A fixture like that cannot fail.
    Window scoping could break, nesting could break, and nothing short of a
    person sitting at the one real SAP machine the team has would notice.

    The simulator now serves two more shapes. A classic GuiTableControl
    carries its cells as CHILDREN, under SAP's real [column,row] ids, so the
    tree walk has to recurse past depth two and FindById has to survive an id
    with brackets and a comma in it. Back opens a wnd[1] modal that sits in
    the session tree beside wnd[0] and leaves it again when dismissed - and
    the two windows deliberately share no text, so which window a reader is
    reading is a question with an answer.

    sap_sim_e2e drives both through the production COM engine.

Fixed

  • The Python SDK's dev/test lock resolved a known-vulnerable pytest for
    Python 3.9.
    pytest < 9.0.3 has insecure /tmp/pytest-of-{user}
    handling on UNIX (GHSA-6w46-j5rx-g56g); the fix only ever shipped in the
    9.x line, and 9.x dropped Python 3.9 support outright, so a plain floor
    bump was unsatisfiable for the 3.9 branch of the lock. The dev
    dependency group now declares its own requires-python = ">=3.10"
    ([tool.uv.dependency-groups]), separate from the package's own
    requires-python = ">=3.9" — running the test suite from source now needs
    3.10+, same as CI already effectively runs, while nothing changes for
    anyone installing the shipped flowproof package on 3.9. The lock now
    resolves one pytest version everywhere: 9.1.1, patched.

  • The nightly SAP suite was failing on the same field, every night, for a
    reason nobody had looked for.
    Every scheduled sap-e2e run since early
    August had failed on the first field of every flow that types into one —
    while the one flow that never touches a field kept passing. The heartbeat
    script written to keep an idle SAP session alive (#453) had nothing to do
    with it: it isn't invoked from the workflow at all, and even where it was
    separately registered on the runner, its scheduled task had no
    -Principal, so it silently stopped reaching the interactive desktop the
    moment that session's RDP connection went from active to disconnected.

    The actual failure was inside the job itself. sap-session-bootstrap.ps1
    logs the session in once, at job start; the login is genuinely fine at
    that point, confirmed by cargo test sap_e2e passing cleanly a few
    minutes later. But two full cargo builds follow with no shared
    incremental cache — around seven minutes of pure compilation, untouched
    by any SAP activity — and by the time the flow suite starts, the
    application server has logged the session out for sitting idle. The
    client raises its own "maximum user idle time exceeded" notice, a native
    Win32 dialog outside SAP's scripting object model — invisible to
    FindById, so nothing already in the driver could see or close it, and
    every field lookup after it just timed out waiting for a screen that was
    never going to render.

    sap-session-bootstrap.ps1 now recognizes that dialog and dismisses it
    (declining, not accepting — the default button opens a second window
    that would need dismissing too), and sap-e2e.yml runs bootstrap a
    second time immediately before the flow suite, not only once at job
    start, closing the actual idle window instead of one that had already
    passed.