From e3f34bd69ae8a3b1ed1b1bea80ca118e6e2ad691 Mon Sep 17 00:00:00 2001 From: Joel Einbinder Date: Mon, 9 Dec 2019 14:51:19 -0800 Subject: [PATCH] fix(fill): throw when the element isn't fillable (#160) An element is fillable if its: - In dom - Not display:none or visibility:hidden - textarea or input or contenteditable if textarea or input it must also be - not readOnly - not disabled #133 --- src/dom.ts | 2 -- src/input.ts | 23 +++++++++++++++++++++-- test/page.spec.js | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/dom.ts b/src/dom.ts index 13f9a9f228..1c2aa498c9 100644 --- a/src/dom.ts +++ b/src/dom.ts @@ -335,8 +335,6 @@ export class ElementHandle extends js.JSHandle { const error = await this.evaluate(input.fillFunction); if (error) throw new Error(error); - await this.focus(); - // TODO: we should check that focus() succeeded. await this._world.delegate.keyboard.sendCharacters(value); } diff --git a/src/input.ts b/src/input.ts index d41f28b42d..2adf924fca 100644 --- a/src/input.ts +++ b/src/input.ts @@ -320,26 +320,45 @@ export const fillFunction = (node: Node) => { if (node.nodeType !== Node.ELEMENT_NODE) return 'Node is not of type HTMLElement'; const element = node as HTMLElement; + if (!element.isConnected) + return 'Element is not attached to the DOM'; + if (!element.ownerDocument || !element.ownerDocument.defaultView) + return 'Element does not belong to a window'; + + const style = element.ownerDocument.defaultView.getComputedStyle(element); + if (!style || style.visibility === 'hidden') + return 'Element is hidden'; + if (!element.offsetParent && element.tagName !== 'BODY') + return 'Element is not visible'; if (element.nodeName.toLowerCase() === 'input') { const input = element as HTMLInputElement; const type = input.getAttribute('type') || ''; const kTextInputTypes = new Set(['', 'password', 'search', 'tel', 'text', 'url']); if (!kTextInputTypes.has(type.toLowerCase())) return 'Cannot fill input of type "' + type + '".'; + if (input.disabled) + return 'Cannot fill a disabled input.'; + if (input.readOnly) + return 'Cannot fill a readonly input.'; input.selectionStart = 0; input.selectionEnd = input.value.length; + input.focus(); } else if (element.nodeName.toLowerCase() === 'textarea') { const textarea = element as HTMLTextAreaElement; + if (textarea.disabled) + return 'Cannot fill a disabled textarea.'; + if (textarea.readOnly) + return 'Cannot fill a readonly textarea.'; textarea.selectionStart = 0; textarea.selectionEnd = textarea.value.length; + textarea.focus(); } else if (element.isContentEditable) { - if (!element.ownerDocument || !element.ownerDocument.defaultView) - return 'Element does not belong to a window'; const range = element.ownerDocument.createRange(); range.selectNodeContents(element); const selection = element.ownerDocument.defaultView.getSelection(); selection.removeAllRanges(); selection.addRange(range); + element.focus(); } else { return 'Element is not an ,