diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d46a50..2c753f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,27 @@ together). ### Fixed +- **`Select` typed the option name when the option did not exist.** A JS + exception inside the driver does not reach Rust as an `Err`, so the throw + on a missing option looked exactly like "this element is not a + `` is itself a prefix search, so the step landed on + whatever option starts with the same letters and reported success. Not a + failure and not the option that was asked for: a plausible wrong answer, + chosen quietly. + + The two cases are now different answers rather than the same one. A status + value comes back and is inspected: `not_select` keeps the fall-through to + typing, which is what it was always for, and a name matching nothing fails + naming it. Prefix matching is untouched — it is the documented ladder + (value, then exact visible text, then prefix), and `Audit` selecting + `Auditor` is correct. + + Found while building the multi-option form, whose first version had the + same defect and was caught by its own red-path test. + - **The docs never said what a typed capture does with the text around it.** `authoring.md` showed one form, `Type ${captured.oid} into the …`, and said the value is read fresh on every replay. It did not say that diff --git a/crates/flowproof-adapters/src/web.rs b/crates/flowproof-adapters/src/web.rs index 47c71fa..b799050 100644 --- a/crates/flowproof-adapters/src/web.rs +++ b/crates/flowproof-adapters/src/web.rs @@ -2287,31 +2287,51 @@ impl AppDriver for WebAppDriver { let handled = self.with_element(&locator, &format!("selecting in [{selector}]"), |element| { element.call_js_fn( + // A STATUS STRING, not a throw and not a bare boolean. + // A JS exception does not reach Rust as an `Err` here, + // so throwing on a missing option looked identical to + // "this is not a `" — and fell through to typing the option's name into the +//! dropdown. Typing into a ` + + + + + +
none
+ + +"#; + +fn fixture(dir: &std::path::Path) -> String { + std::fs::create_dir_all(dir).expect("temp dir"); + let page = dir.join("roles.html"); + std::fs::write(&page, PAGE).expect("page written"); + format!("file://{}", page.display()) +} + +/// The red path: an option that matches NOTHING on the ladder. +/// +/// Note what is deliberately absent here. `Audit` is not one of these, +/// because prefix matching is documented behaviour — value, then exact +/// visible text, then prefix — so `Audit` legitimately selects `Auditor`. +/// The bug was never about prefixes; it was that a name matching nothing +/// at all fell through to typing, and typing into a ``: committed via the value setter, fires `input`+`change` (React-safe). `in the` and `… dropdown` also accepted | +| `Select