Repository navigation
capturePage renders form controls with their initial HTML state instead of their live value/checked/selected state #91
Description
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>elementsinputChecked: checked state of checkboxes and radiosoptionSelected: selected state of<option>elementstextValue: 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): setvaluetoinputValuewhen present, even if the markup had novalue. If the live value is empty,value=""is honest; dropping the attribute is too.<input type=checkbox|radio>: addcheckedwheninputCheckedholds the node, and remove a markupcheckedwhen it doesn't.<option>: same forselectedusingoptionSelected. 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 withtextValue/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
checkedin markup and then unchecked, - a password field that is not revealed.
Activity