@@ -230,7 +230,7 @@ public async Task TapAsync()
230230 /// Calls <c>focus</c> <see href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus"/> on the element.
231231 /// </summary>
232232 /// <returns>Task</returns>
233- public Task FocusAsync ( ) => ExecutionContext . EvaluateFunctionAsync ( "element => element.focus()" , this ) ;
233+ public Task FocusAsync ( ) => EvaluateFunctionAsync ( "element => element.focus()" ) ;
234234
235235 /// <summary>
236236 /// Focuses the element, and sends a <c>keydown</c>, <c>keypress</c>/<c>input</c>, and <c>keyup</c> event for each character in the text.
@@ -281,9 +281,9 @@ public async Task PressAsync(string key, PressOptions options = null)
281281 /// <returns>Task which resolves to <see cref="ElementHandle"/> pointing to the frame element</returns>
282282 public async Task < ElementHandle > QuerySelectorAsync ( string selector )
283283 {
284- var handle = await ExecutionContext . EvaluateFunctionHandleAsync (
284+ var handle = await EvaluateFunctionHandleAsync (
285285 "(element, selector) => element.querySelector(selector)" ,
286- this , selector ) . ConfigureAwait ( false ) ;
286+ selector ) . ConfigureAwait ( false ) ;
287287
288288 if ( handle is ElementHandle element )
289289 {
@@ -301,9 +301,9 @@ public async Task<ElementHandle> QuerySelectorAsync(string selector)
301301 /// <returns>Task which resolves to ElementHandles pointing to the frame elements</returns>
302302 public async Task < ElementHandle [ ] > QuerySelectorAllAsync ( string selector )
303303 {
304- var arrayHandle = await ExecutionContext . EvaluateFunctionHandleAsync (
304+ var arrayHandle = await EvaluateFunctionHandleAsync (
305305 "(element, selector) => element.querySelectorAll(selector)" ,
306- this , selector ) . ConfigureAwait ( false ) ;
306+ selector ) . ConfigureAwait ( false ) ;
307307
308308 var properties = await arrayHandle . GetPropertiesAsync ( ) . ConfigureAwait ( false ) ;
309309 await arrayHandle . DisposeAsync ( ) . ConfigureAwait ( false ) ;
@@ -423,6 +423,36 @@ public Task<bool> IsIntersectingViewportAsync()
423423 return visibleRatio > 0;
424424 }" , this ) ;
425425
426+ /// <summary>
427+ /// Triggers a `change` and `input` event once all the provided options have been selected.
428+ /// If there's no `select` element matching `selector`, the method throws an exception.
429+ /// </summary>
430+ /// <example>
431+ /// <code>
432+ /// await handle.SelectAsync("blue"); // single selection
433+ /// await handle.SelectAsync("red", "green", "blue"); // multiple selections
434+ /// </code>
435+ /// </example>
436+ /// <param name="values">Values of options to select. If the `select` has the `multiple` attribute, all values are considered, otherwise only the first one is taken into account.</param>
437+ /// <returns>A task that resolves to an array of option values that have been successfully selected.</returns>
438+ public Task < string [ ] > SelectAsync ( params string [ ] values )
439+ => EvaluateFunctionAsync < string [ ] > ( @"(element, values) =>
440+ {
441+ if (element.nodeName.toLowerCase() !== 'select')
442+ throw new Error('Element is not a <select> element.');
443+
444+ const options = Array.from(element.options);
445+ element.value = undefined;
446+ for (const option of options) {
447+ option.selected = values.includes(option.value);
448+ if (option.selected && !element.multiple)
449+ break;
450+ }
451+ element.dispatchEvent(new Event('input', { 'bubbles': true }));
452+ element.dispatchEvent(new Event('change', { 'bubbles': true }));
453+ return options.filter(option => option.selected).map(option => option.value);
454+ }" , new [ ] { values } ) ;
455+
426456 private async Task < ( decimal x , decimal y ) > ClickablePointAsync ( )
427457 {
428458 GetContentQuadsResponse result = null ;
@@ -484,7 +514,7 @@ private IEnumerable<BoxModelPoint> IntersectQuadWithViewport(IEnumerable<BoxMode
484514
485515 private async Task ScrollIntoViewIfNeededAsync ( )
486516 {
487- var errorMessage = await ExecutionContext . EvaluateFunctionAsync < string > ( @"async(element, pageJavascriptEnabled) => {
517+ var errorMessage = await EvaluateFunctionAsync < string > ( @"async(element, pageJavascriptEnabled) => {
488518 if (!element.isConnected)
489519 return 'Node is detached from document';
490520 if (element.nodeType !== Node.ELEMENT_NODE)
@@ -504,7 +534,7 @@ private async Task ScrollIntoViewIfNeededAsync()
504534 if (visibleRatio !== 1.0)
505535 element.scrollIntoView({block: 'center', inline: 'center', behavior: 'instant'});
506536 return null;
507- }" , this , Page . JavascriptEnabled ) . ConfigureAwait ( false ) ;
537+ }" , Page . JavascriptEnabled ) . ConfigureAwait ( false ) ;
508538
509539 if ( errorMessage != null )
510540 {
0 commit comments