Skip to content

capturePage renders form controls with their initial HTML state instead of their live value/checked/selected state #91

Closed

Description

@morisil

Problem

capturePage renders form controls with their initial HTML state, not their live state.
After a user (or an agent driving the page over CDP) types into a field, picks an option or ticks a checkbox, the captured events still show what the server sent.

Found while testing umwelt, which builds its session dump on markanywhere-browse.
Against this fixture:

<form action="/submit" method="get">
  <label>Name <input name=name value="preset"></label>
  <label>Bio <textarea name=bio>old bio</textarea></label>
  <label>Color <select name=color><option value=r>Red</option><option value=g>Green</option><option value=b>Blue</option></select></label>
  <label><input type=checkbox name=agree> Agree</label>
  <button type=submit>Send</button>
</form>

after typing Ana into the input, new bio into the textarea, selecting Green and clicking the checkbox, a fresh capture still renders:

<input name="name" value="preset" ref="1">
<textarea name="bio" ref="2">

old bio

</textarea>
<select name="color" ref="3">
<option value="r" ref="4">  … no `selected` on any option
<input type="checkbox" name="agree" ref="7">   … no `checked`

Submitting the form proves the page really holds the new values (name=Ana&bio=new+bio&color=g&agree=on).
So a consumer can't see what it just typed, or check a form's state before it submits.

Cause

CapturePage.kt builds each element's attributes from DOMSnapshot nodes.attributes, which are the content attributes (the markup's value, checked, selected and the textarea's child text).
Those don't change when the user edits the control; the live state is held in DOM properties.

DOMSnapshot.captureSnapshot already returns the live state in NodeTreeSnapshot, and markanywhere-browse reads none of it (grep for these names finds nothing):

  • inputValue: the current value of <input> and <textarea> elements
  • inputChecked: checked state of checkboxes and radios
  • optionSelected: selected state of <option> elements
  • textValue: the value of a <textarea>

(see the CDP DOMSnapshot.NodeTreeSnapshot docs).
These are rare-data arrays indexed by node; check how kdriver exposes them (RareStringData / RareBooleanData).

Proposed fix

In SnapshotDom / walkElement (markanywhere-browse/src/commonMain/kotlin/CapturePage.kt), apply the live state over the content attributes:

  • <input> (text-like types): set value to inputValue when present, even if the markup had no value. If the live value is empty, value="" is honest; dropping the attribute is too.
  • <input type=checkbox|radio>: add checked when inputChecked holds the node, and remove a markup checked when it doesn't.
  • <option>: same for selected using optionSelected. This also covers the browser's implicit choice: the first option of a single <select> counts as selected even without the attribute. Decide deliberately whether to mark the implicit default (I'd say yes, since it's what would be submitted).
  • <textarea>: replace its text children with textValue / inputValue.

No change is needed downstream: simplifyHtml's attribute whitelist already keeps input[value|checked] and option[selected] (SimplifyHtml.kt ~line 694).

Don't leak secrets: <input type=password> should not get its live value written out, and probably not its markup value either.

Tests

Add a CapturePageTest case (real browser, as the existing ones) that loads the fixture above, changes each control through CDP (Input.insertText / setting the property and dispatching input/change), captures, and asserts the whole event stream, including:

  • a typed input value,
  • a textarea whose new text has a line break in it,
  • a selected option (and that the old default is no longer marked),
  • a checked box, and one that was checked in markup and then unchecked,
  • a password field that is not revealed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions