Problem
Five locator actions are missing, and the DOM underneath each one already exists:
const loc = page.locator('select')
typeof loc.selectOption // 'undefined' — HTMLSelectElement + selectedIndex exist
typeof loc.press // 'undefined' — page.keyboard.press exists
typeof loc.clear // 'undefined' — _fillElement exists
typeof loc.dblclick // 'undefined'
typeof loc.setInputFiles // 'undefined' — File and FileList are exportedpage has no selectOption, press, check, uncheck or setInputFiles either, so there is no selector-level fallback for most of them.
wildloop's specs: selectOption 4, setInputFiles 3, press 2.
Why it matters
<select> and <input type=file> are the two controls with no reasonable hand-rolled substitute. Setting select.value directly does not fire change, so a component listening for it never updates, and the test passes against a DOM the app never saw. The same is true of assigning to input.files — it needs a FileList, which is why setInputFiles exists.
press matters for the keys that are behaviour rather than text: Enter to submit, Escape to close, Tab to move focus, ArrowDown through a combobox. page.keyboard.press can reach them, but only against whatever has focus, so the call site becomes focus-then-press and the focus half is easy to get wrong.
clear() and dblclick() are conveniences — fill('') and two click()s cover them — but they are cheap and their absence is noticed immediately.
Proposed scope
locator.selectOption(value | { label } | { index } | { value } | array)— setselectedon the matching<option>s, updateselectedIndex, and fireinputthenchange, in that order. Multiple values only for amultipleselect; throw otherwise rather than silently taking the last.locator.press(key, { delay })— focus the resolved element, then route through the existingpage.keyboardso the key parsing lives in one place. Accept theControl+Entermodifier form.locator.clear()—fill(''), so it inherits whatever events_fillElementfires.locator.dblclick()— two clicks plus adblclickevent, which is the part twoclick()s does not give.locator.setInputFiles(path | paths | { name, mimeType, buffer })— build aFileListfrom the existingFileimplementation, assign it, fireinputandchange. Reading from disk needs a decision: Playwright takes paths, and taking only the in-memory form would be a quieter API but a different one.- The corresponding
page.selectOption(selector, ...)etc. for parity with the otherpage-level actions.
Acceptance
selectOptionfiresinputandchange, asserted with listeners, and a component readingevent.target.valuesees the new value.selectOptionon a single-value select rejects an array.press('Enter')on an input inside a form triggers submit;press('Escape')reaches a keydown listener on the element.setInputFilesleavesinput.filesaFileListwhoseitem(0).namematches, and fireschange.clear()empties a filled input and fires the same eventsfill('')does.
Found while assessing whether wildloop's Playwright specs could port here.