feat(playwright): form-interaction primitives (doubleClick, check/uncheck, selectOption, upload) + MCP tools#43
Merged
Merged
Conversation
Adds doubleClick, check/uncheck, selectOption, and upload to @humanjs/playwright so real flows (forms, checkout, settings) stay humanized instead of falling back to raw Playwright. - doubleClick reuses executeClick via a clickCount option (same approach motion as click; single-click dispatch is unchanged). - check/uncheck click only when the state needs changing, then verify; tolerate non-checkable label/role targets. - selectOption moves the cursor to the <select> then sets the value. - upload moves to the control then setInputFiles (no OS dialog; tolerates hidden inputs). Each is mirrored as an MCP tool, exported by the recorder codegen (toPlaywright/toHumanJS), documented in the skill primitives table, and backed by new KnownActionType entries in @humanjs/core. Colocated tests cover humanized + instant paths and the idempotency/verify behavior.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Address branch-review findings on the form-primitives PR: - human_upload now reads files by basename from HUMANJS_UPLOAD_DIR (resolveUploadPath, mirroring the output-file path-safety model) — ../, subdirectories, and absolute paths are rejected, so a prompt- injected path can't read+exfiltrate arbitrary local files to a form. Documented in the MCP README security section + env table. - check/uncheck tool docs drop the "or its label" hint and point at the checkbox input / [role=checkbox] so state is readable and the click stays idempotent (a label target can't be made idempotent). - selectOption tolerates a hover failure (no visible control) and lets selectOption raise the authoritative error instead of "Cannot hover". Adds resolveUploadPath tests; fixes the McpEnv test mock for uploadDir.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Real flows — forms, checkout, settings — hit checkboxes, dropdowns, double-clicks, and file inputs. Until now those weren't in
@humanjs/playwright, so anyone running a real flow had to drop back to raw Playwright exactly where the humanization matters. This closes that gap.New primitives (
@humanjs/playwright)human.doubleClick(target)— same humanized approach asclick()(Bezier path, hover dwell, near-miss), double-click dispatch. ReusesexecuteClickvia aclickCountoption; the single-click path is unchanged.human.check(target)/human.uncheck(target)— tick/untick a checkbox or radio. Clicks only when the state needs to change (a real user doesn't re-click a ticked box) and verifies the result. Tolerates non-checkable<label>/roletargets (toggles without verifying). Radios can't be unchecked by clicking → clear error.human.selectOption(target, values)— native<select>: cursor moves to the dropdown, then the value is set (firinginput/change). Returns the selected values.human.upload(target, files)— file input: cursor moves to the control, thensetInputFiles. Never opens the OS dialog (would hang); tolerates hidden inputs behind styled buttons.Parity (the "mirror the MCP surface" rule)
human_doubleClick,human_check,human_uncheck,human_selectOption,human_upload.toPlaywright/toHumanJS.skill-body.md.KnownActionTypeentries so plugins observe them.CLAUDE.mdAPI shape + README quick-start.Tests
Colocated
forms/forms.test.tscovers humanized + instant paths, the idempotency guard (no click when already in state), state verification (throws when a toggle doesn't take), hidden-input tolerance for upload, and theclickCount: 2dispatch for doubleClick. Full gate green: lint, typecheck (9/9), tests (222+), build,check:exports(publint, 11/11).Changeset
minorfor@humanjs/{playwright,mcp,core},patchfor@humanjs/skill.🤖 Generated with Claude Code