From 5702eca1f244f7903940d71d9e8c51c337767c6f Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 11 Nov 2020 15:33:23 -0800 Subject: [PATCH] fix(selectors): make selectOptions work for labels (#4402) --- src/server/injected/injectedScript.ts | 20 ++++++++++---------- test/page-select-option.spec.ts | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/server/injected/injectedScript.ts b/src/server/injected/injectedScript.ts index a656612fb9..d5c4b50627 100644 --- a/src/server/injected/injectedScript.ts +++ b/src/server/injected/injectedScript.ts @@ -227,14 +227,14 @@ export class InjectedScript { } selectOptions(node: Node, optionsToSelect: (Node | { value?: string, label?: string, index?: number })[]): string[] | 'error:notconnected' | FatalDOMError { - if (node.nodeName.toLowerCase() !== 'select') - return 'error:notselect'; - if (!node.isConnected) + const element = this.findLabelTarget(node as Element); + if (!element || !element.isConnected) return 'error:notconnected'; - const element = node as HTMLSelectElement; - - const options = Array.from(element.options); - element.value = undefined as any; + if (element.nodeName.toLowerCase() !== 'select') + return 'error:notselect'; + const select = element as HTMLSelectElement; + const options = Array.from(select.options); + select.value = undefined as any; for (let index = 0; index < options.length; index++) { const option = options[index]; option.selected = optionsToSelect.some(optionToSelect => { @@ -249,11 +249,11 @@ export class InjectedScript { matches = matches && optionToSelect.index === index; return matches; }); - if (option.selected && !element.multiple) + if (option.selected && !select.multiple) break; } - element.dispatchEvent(new Event('input', { 'bubbles': true })); - element.dispatchEvent(new Event('change', { 'bubbles': true })); + select.dispatchEvent(new Event('input', { 'bubbles': true })); + select.dispatchEvent(new Event('change', { 'bubbles': true })); return options.filter(option => option.selected).map(option => option.value); } diff --git a/test/page-select-option.spec.ts b/test/page-select-option.spec.ts index ecd7365d6d..c3587c3c58 100644 --- a/test/page-select-option.spec.ts +++ b/test/page-select-option.spec.ts @@ -98,6 +98,26 @@ it('should select multiple options with attributes', async ({page, server}) => { expect(await page.evaluate(() => window['result'].onChange)).toEqual(['blue', 'gray', 'green']); }); +it('should select options with sibling label', async ({page, server}) => { + await page.setContent(` + `); + await page.selectOption('text=Choose a pet', 'cat'); + expect(await page.$eval('select', select => select.options[select.selectedIndex].text)).toEqual('Cat'); +}); + +it('should select options with outer label', async ({page, server}) => { + await page.setContent(``); + await page.selectOption('text=Choose a pet', 'cat'); + expect(await page.$eval('select', select => select.options[select.selectedIndex].text)).toEqual('Cat'); +}); + it('should respect event bubbling', async ({page, server}) => { await page.goto(server.PREFIX + '/input/select.html'); await page.selectOption('select', 'blue');