Closed vermaxik closed 5 years ago
Works just fine with new browser on my machine. Could you please run tests with CUPRITE_DEBUG=true?
I'm using docker contrainer with no-sandbox
options
<<< {"id":1,"result":{"targetInfos":[{"targetId":"43F15505150DE6A6F27673655FCFC028","type":"page","title":"","url":"about:blank","attached":false,"browserContextId":"614D5183645E2B4628ED820405AA995E"}]}}
>>> {"method":"Target.createBrowserContext","params":{},"id":2}
<<< {"id":2,"result":{"browserContextId":"1350334B7EF8A4625FE7E5A7937DBDB2"}}
>>> {"method":"Target.createTarget","params":{"url":"about:blank","browserContextId":"1350334B7EF8A4625FE7E5A7937DBDB2"},"id":3}
<<< {"id":3,"result":{"targetId":"F8F11DFDF7A67282EBC76EB6DAB06B46"}}
>>> {"method":"Target.attachToTarget","params":{"targetId":"F8F11DFDF7A67282EBC76EB6DAB06B46"},"id":4}
<<< {"method":"Target.attachedToTarget","params":{"sessionId":"A63DAC7C5D613751CB0AB0B3EF9D7C59","targetInfo":{"targetId":"F8F11DFDF7A67282EBC76EB6DAB06B46","type":"page","title":"","url":"about:blank","attached":true,"browserContextId":"1350334B7EF8A4625FE7E5A7937DBDB2"},"waitingForDebugger":false}}
<<< {"id":4,"result":{"sessionId":"A63DAC7C5D613751CB0AB0B3EF9D7C59"}}
>>> {"method":"Page.enable","params":{},"id":1}
<<< {"id":1,"result":{}}
>>> {"method":"DOM.enable","params":{},"id":2}
<<< {"id":2,"result":{}}
>>> {"method":"CSS.enable","params":{},"id":3}
<<< {"id":3,"result":{}}
>>> {"method":"Runtime.enable","params":{},"id":4}
<<< {"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"origin":"://","name":"","auxData":{"isDefault":true,"type":"default","frameId":"F8F11DFDF7A67282EBC76EB6DAB06B46"}}}}
<<< {"id":4,"result":{}}
>>> {"method":"Log.enable","params":{},"id":5}
<<< {"id":5,"result":{}}
>>> {"method":"Network.enable","params":{},"id":6}
<<< {"id":6,"result":{}}
>>> {"method":"Page.setDownloadBehavior","params":{"behavior":"allow","downloadPath":"/app/capybara"},"id":7}
<<< {"id":7,"result":{}}
>>> {"method":"Page.addScriptToEvaluateOnNewDocument","params":{"source":"class InvalidSelector extends Error {}\nclass TimedOutPromise extends Error {}\nclass MouseEventFailed extends Error {}\n\nconst EVENTS = {\n FOCUS: [\"blur\", \"focus\", \"focusin\", \"focusout\"],\n MOUSE: [\"click\", \"dblclick\", \"mousedown\", \"mouseenter\", \"mouseleave\",\n \"mousemove\", \"mouseover\", \"mouseout\", \"mouseup\", \"contextmenu\"],\n FORM: [\"submit\"]\n}\n\nclass Cuprite {\n constructor() {\n this._json = JSON; // In case someone overrides it like mootools\n }\n\n find(method, selector, within = document) {\n try {\n let results = [];\n\n if (method == \"xpath\") {\n let xpath = document.evaluate(selector, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n for (let i = 0; i \u003c xpath.snapshotLength; i++) {\n results.push(xpath.snapshotItem(i));\n }\n } else {\n results = Array.from(within.querySelectorAll(selector));\n }\n\n return results;\n } catch (error) {\n // DOMException.INVALID_EXPRESSION_ERR is undefined, using pure code\n if (error.code == DOMException.SYNTAX_ERR || error.code == 51) {\n throw new InvalidSelector;\n } else {\n throw error;\n }\n }\n }\n\n parents(node) {\n let nodes = [];\n let parent = node.parentNode;\n while (parent != document) {\n nodes.push(parent);\n parent = parent.parentNode;\n }\n return nodes;\n }\n\n visibleText(node) {\n if (this.isVisible(node)) {\n if (node.nodeName == \"TEXTAREA\") {\n return node.textContent;\n } else {\n if (node instanceof SVGElement) {\n return node.textContent;\n } else {\n return node.innerText;\n }\n }\n }\n }\n\n isVisible(node) {\n let mapName, style;\n // if node is area, check visibility of relevant image\n if (node.tagName === \"AREA\") {\n mapName = document.evaluate(\"./ancestor::map/@name\", node, null, XPathResult.STRING_TYPE, null).stringValue;\n node = document.querySelector(`img[usemap=\"#${mapName}\"]`);\n if (node == null) {\n return false;\n }\n }\n\n while (node) {\n style = window.getComputedStyle(node);\n if (style.display === \"none\" || style.visibility === \"hidden\" || parseFloat(style.opacity) === 0) {\n return false;\n }\n node = node.parentElement;\n }\n\n return true;\n }\n\n\n isDisabled(node) {\n let xpath = \"parent::optgroup[@disabled] | \\\n ancestor::select[@disabled] | \\\n parent::fieldset[@disabled] | \\\n ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]\";\n\n return node.disabled || document.evaluate(xpath, node, null, XPathResult.BOOLEAN_TYPE, null).booleanValue;\n }\n\n path(node) {\n let nodes = [node];\n let parent = node.parentNode;\n while (parent !== document) {\n nodes.unshift(parent);\n parent = parent.parentNode;\n }\n\n let selectors = nodes.map(node =\u003e {\n let prevSiblings = [];\n let xpath = document.evaluate(`./preceding-sibling::${node.tagName}`, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n\n for (let i = 0; i \u003c xpath.snapshotLength; i++) {\n prevSiblings.push(xpath.snapshotItem(i));\n }\n\n return `${node.tagName}[${(prevSiblings.length + 1)}]`;\n });\n\n return `//${selectors.join(\"/\")}`;\n }\n\n set(node, value) {\n if (node.readOnly) return;\n\n if (node.maxLength \u003e= 0) {\n value = value.substr(0, node.maxLength);\n }\n\n this.trigger(node, \"focus\");\n this.setValue(node, \"\");\n\n if (node.type == \"number\" || node.type == \"date\") {\n this.setValue(node, value);\n } else if (node.type == \"time\") {\n this.setValue(node, new Date(value).toTimeString().split(\" \")[0]);\n } else if (node.type == \"datetime-local\") {\n value = new Date(value);\n let year = value.getFullYear();\n let month = (\"0\" + (value.getMonth() + 1)).slice(-2);\n let date = (\"0\" + value.getDate()).slice(-2);\n let hour = (\"0\" + value.getHours()).slice(-2);\n let min = (\"0\" + value.getMinutes()).slice(-2);\n let sec = (\"0\" + value.getSeconds()).slice(-2);\n this.setValue(node, `${year}-${month}-${date}T${hour}:${min}:${sec}`);\n } else {\n for (let i = 0; i \u003c value.length; i++) {\n let char = value[i];\n let keyCode = this.characterToKeyCode(char);\n this.keyupdowned(node, \"keydown\", keyCode);\n this.setValue(node, node.value + char);\n\n this.keypressed(node, false, false, false, false, char.charCodeAt(0), char.charCodeAt(0));\n this.keyupdowned(node, \"keyup\", keyCode);\n }\n }\n\n this.changed(node);\n this.input(node);\n this.trigger(node, \"blur\");\n }\n\n setValue(node, value) {\n let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, \"value\").set;\n let nativeTextareaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, \"value\").set;\n\n if (node.tagName.toLowerCase() === 'input') {\n return nativeInputValueSetter.call(node, value);\n }\n return nativeTextareaValueSetter.call(node, value);\n }\n\n input(node) {\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(\"input\", true, false);\n node.dispatchEvent(event);\n }\n\n keyupdowned(node, eventName, keyCode) {\n let event = document.createEvent(\"UIEvents\");\n event.initEvent(eventName, true, true);\n event.keyCode = keyCode;\n event.charCode = 0;\n node.dispatchEvent(event);\n }\n\n keypressed(node, altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) {\n event = document.createEvent(\"UIEvents\");\n event.initEvent(\"keypress\", true, true);\n event.window = window;\n event.altKey = altKey;\n event.ctrlKey = ctrlKey;\n event.shiftKey = shiftKey;\n event.metaKey = metaKey;\n event.keyCode = keyCode;\n event.charCode = charCode;\n node.dispatchEvent(event);\n }\n\n characterToKeyCode(char) {\n const specialKeys = {\n 96: 192, // `\n 45: 189, // -\n 61: 187, // =\n 91: 219, // [\n 93: 221, // ]\n 92: 220, // \\\n 59: 186, // ;\n 39: 222, // '\n 44: 188, // ,\n 46: 190, // .\n 47: 191, // /\n 127: 46, // delete\n 126: 192, // ~\n 33: 49, // !\n 64: 50, // @\n 35: 51, // #\n 36: 52, // $\n 37: 53, // %\n 94: 54, // ^\n 38: 55, // \u0026\n 42: 56, // *\n 40: 57, // (\n 41: 48, // )\n 95: 189, // _\n 43: 187, // +\n 123: 219, // {\n 125: 221, // }\n 124: 220, // |\n 58: 186, // :\n 34: 222, // \"\n 60: 188, // \u003c\n 62: 190, // \u003e\n 63: 191, // ?\n }\n\n let code = char.toUpperCase().charCodeAt(0);\n return specialKeys[code] || code;\n }\n\n scrollIntoViewport(node) {\n let areaImage = this._getAreaImage(node);\n\n if (areaImage) {\n return this.scrollIntoViewport(areaImage);\n } else {\n node.scrollIntoViewIfNeeded();\n\n if (!this._isInViewport(node)) {\n node.scrollIntoView({block: \"center\", inline: \"center\", behavior: \"instant\"});\n return this._isInViewport(node);\n }\n\n return true;\n }\n }\n\n mouseEventTest(node, name, x, y) {\n let frameOffset = this._frameOffset();\n x -= frameOffset.left;\n y -= frameOffset.top;\n\n let element = document.elementFromPoint(x, y);\n\n let el = element;\n while (el) {\n if (el == node) {\n return true;\n } else {\n el = el.parentNode;\n }\n }\n\n let selector = element \u0026\u0026 this._getSelector(element) || \"none\";\n throw new MouseEventFailed([name, selector, x, y].join(\", \"));\n }\n\n _getAreaImage(node) {\n if (\"area\" == node.tagName.toLowerCase()) {\n let map = node.parentNode;\n if (map.tagName.toLowerCase() != \"map\") {\n throw new Error(\"the area is not within a map\");\n }\n\n let mapName = map.getAttribute(\"name\");\n if (typeof mapName === \"undefined\" || mapName === null) {\n throw new Error(\"area's parent map must have a name\");\n }\n\n mapName = `#${mapName.toLowerCase()}`;\n let imageNode = this.find(\"css\", `img[usemap='${mapName}']`)[0];\n if (typeof imageNode === \"undefined\" || imageNode === null) {\n throw new Error(\"no image matches the map\");\n }\n\n return imageNode;\n }\n }\n\n _frameOffset() {\n let win = window;\n let offset = { top: 0, left: 0 };\n\n while (win.frameElement) {\n let rect = win.frameElement.getClientRects()[0];\n let style = win.getComputedStyle(win.frameElement);\n win = win.parent;\n\n offset.top += rect.top + parseInt(style.getPropertyValue(\"padding-top\"), 10)\n offset.left += rect.left + parseInt(style.getPropertyValue(\"padding-left\"), 10)\n }\n\n return offset;\n }\n\n _getSelector(el) {\n let selector = (el.tagName != 'HTML') ? this._getSelector(el.parentNode) + \" \" : \"\";\n selector += el.tagName.toLowerCase();\n if (el.id) { selector += `#${el.id}` };\n el.classList.forEach(c =\u003e selector += `.${c}`);\n return selector;\n }\n\n _isInViewport(node) {\n let rect = node.getBoundingClientRect();\n return rect.top \u003e= 0 \u0026\u0026\n rect.left \u003e= 0 \u0026\u0026\n rect.bottom \u003c= window.innerHeight \u0026\u0026\n rect.right \u003c= window.innerWidth;\n }\n\n select(node, value) {\n if (this.isDisabled(node)) {\n return false;\n } else if (value == false \u0026\u0026 !node.parentNode.multiple) {\n return false;\n } else {\n this.trigger(node.parentNode, \"focus\");\n\n node.selected = value;\n this.changed(node);\n\n this.trigger(node.parentNode, \"blur\");\n return true;\n }\n }\n\n changed(node) {\n let element;\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(\"change\", true, false);\n\n // In the case of an OPTION tag, the change event should come\n // from the parent SELECT\n if (node.nodeName == \"OPTION\") {\n element = node.parentNode\n if (element.nodeName == \"OPTGROUP\") {\n element = element.parentNode\n }\n element\n } else {\n element = node\n }\n\n element.dispatchEvent(event)\n }\n\n trigger(node, name, options = {}) {\n let event;\n\n if (EVENTS.MOUSE.indexOf(name) != -1) {\n event = document.createEvent(\"MouseEvent\");\n event.initMouseEvent(\n name, true, true, window, 0,\n options[\"screenX\"] || 0, options[\"screenY\"] || 0,\n options[\"clientX\"] || 0, options[\"clientY\"] || 0,\n options[\"ctrlKey\"] || false,\n options[\"altKey\"] || false,\n options[\"shiftKey\"] || false,\n options[\"metaKey\"] || false,\n options[\"button\"] || 0, null\n )\n } else if (EVENTS.FOCUS.indexOf(name) != -1) {\n event = this.obtainEvent(name);\n } else if (EVENTS.FORM.indexOf(name) != -1) {\n event = this.obtainEvent(name);\n } else {\n throw \"Unknown event\";\n }\n\n node.dispatchEvent(event);\n }\n\n obtainEvent(name) {\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(name, true, true);\n return event;\n }\n\n getAttributes(node) {\n let attrs = {};\n for (let i = 0, len = node.attributes.length; i \u003c len; i++) {\n let attr = node.attributes[i];\n attrs[attr.name] = attr.value.replace(\"\\n\", \"\\\\n\");\n }\n\n return this._json.stringify(attrs);\n }\n\n getAttribute(node, name) {\n if (name == \"checked\" || name == \"selected\") {\n return node[name];\n } else {\n return node.getAttribute(name);\n }\n }\n\n value(node) {\n if (node.tagName == \"SELECT\" \u0026\u0026 node.multiple) {\n let result = []\n\n for (let i = 0, len = node.children.length; i \u003c len; i++) {\n let option = node.children[i];\n if (option.selected) {\n result.push(option.value);\n }\n }\n\n return result;\n } else {\n return node.value;\n }\n }\n\n deleteText(node) {\n let range = document.createRange();\n range.selectNodeContents(node);\n window.getSelection().removeAllRanges();\n window.getSelection().addRange(range);\n window.getSelection().deleteFromDocument();\n }\n\n containsSelection(node) {\n let selectedNode = document.getSelection().focusNode;\n\n if (!selectedNode) {\n return false;\n }\n\n if (selectedNode.nodeType == 3) {\n selectedNode = selectedNode.parentNode;\n }\n\n return node.contains(selectedNode);\n }\n\n isCyclic(object) {\n if (Array.isArray(object) \u0026\u0026 object.every(n =\u003e n instanceof Node)) {\n return false;\n }\n\n try {\n this._json.stringify(object);\n return false;\n } catch (e) {\n return true;\n }\n }\n\n // This command is purely for testing error handling\n browserError() {\n throw new Error(\"zomg\");\n }\n}\n\nwindow._cuprite = new Cuprite;\n"},"id":8}
>>> {"method":"Page.addScriptToEvaluateOnNewDocument","params":{"source":"/* global $ */\ndocument.addEventListener('DOMContentLoaded', function() {\n // kill bootstrap transitions\n $.support.transition = false\n\n // kill all CSS transitions\n})\n"},"id":9}
>>> {"method":"Runtime.evaluate","params":{"expression":"class InvalidSelector extends Error {}\nclass TimedOutPromise extends Error {}\nclass MouseEventFailed extends Error {}\n\nconst EVENTS = {\n FOCUS: [\"blur\", \"focus\", \"focusin\", \"focusout\"],\n MOUSE: [\"click\", \"dblclick\", \"mousedown\", \"mouseenter\", \"mouseleave\",\n \"mousemove\", \"mouseover\", \"mouseout\", \"mouseup\", \"contextmenu\"],\n FORM: [\"submit\"]\n}\n\nclass Cuprite {\n constructor() {\n this._json = JSON; // In case someone overrides it like mootools\n }\n\n find(method, selector, within = document) {\n try {\n let results = [];\n\n if (method == \"xpath\") {\n let xpath = document.evaluate(selector, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n for (let i = 0; i \u003c xpath.snapshotLength; i++) {\n results.push(xpath.snapshotItem(i));\n }\n } else {\n results = Array.from(within.querySelectorAll(selector));\n }\n\n return results;\n } catch (error) {\n // DOMException.INVALID_EXPRESSION_ERR is undefined, using pure code\n if (error.code == DOMException.SYNTAX_ERR || error.code == 51) {\n throw new InvalidSelector;\n } else {\n throw error;\n }\n }\n }\n\n parents(node) {\n let nodes = [];\n let parent = node.parentNode;\n while (parent != document) {\n nodes.push(parent);\n parent = parent.parentNode;\n }\n return nodes;\n }\n\n visibleText(node) {\n if (this.isVisible(node)) {\n if (node.nodeName == \"TEXTAREA\") {\n return node.textContent;\n } else {\n if (node instanceof SVGElement) {\n return node.textContent;\n } else {\n return node.innerText;\n }\n }\n }\n }\n\n isVisible(node) {\n let mapName, style;\n // if node is area, check visibility of relevant image\n if (node.tagName === \"AREA\") {\n mapName = document.evaluate(\"./ancestor::map/@name\", node, null, XPathResult.STRING_TYPE, null).stringValue;\n node = document.querySelector(`img[usemap=\"#${mapName}\"]`);\n if (node == null) {\n return false;\n }\n }\n\n while (node) {\n style = window.getComputedStyle(node);\n if (style.display === \"none\" || style.visibility === \"hidden\" || parseFloat(style.opacity) === 0) {\n return false;\n }\n node = node.parentElement;\n }\n\n return true;\n }\n\n\n isDisabled(node) {\n let xpath = \"parent::optgroup[@disabled] | \\\n ancestor::select[@disabled] | \\\n parent::fieldset[@disabled] | \\\n ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]\";\n\n return node.disabled || document.evaluate(xpath, node, null, XPathResult.BOOLEAN_TYPE, null).booleanValue;\n }\n\n path(node) {\n let nodes = [node];\n let parent = node.parentNode;\n while (parent !== document) {\n nodes.unshift(parent);\n parent = parent.parentNode;\n }\n\n let selectors = nodes.map(node =\u003e {\n let prevSiblings = [];\n let xpath = document.evaluate(`./preceding-sibling::${node.tagName}`, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n\n for (let i = 0; i \u003c xpath.snapshotLength; i++) {\n prevSiblings.push(xpath.snapshotItem(i));\n }\n\n return `${node.tagName}[${(prevSiblings.length + 1)}]`;\n });\n\n return `//${selectors.join(\"/\")}`;\n }\n\n set(node, value) {\n if (node.readOnly) return;\n\n if (node.maxLength \u003e= 0) {\n value = value.substr(0, node.maxLength);\n }\n\n this.trigger(node, \"focus\");\n this.setValue(node, \"\");\n\n if (node.type == \"number\" || node.type == \"date\") {\n this.setValue(node, value);\n } else if (node.type == \"time\") {\n this.setValue(node, new Date(value).toTimeString().split(\" \")[0]);\n } else if (node.type == \"datetime-local\") {\n value = new Date(value);\n let year = value.getFullYear();\n let month = (\"0\" + (value.getMonth() + 1)).slice(-2);\n let date = (\"0\" + value.getDate()).slice(-2);\n let hour = (\"0\" + value.getHours()).slice(-2);\n let min = (\"0\" + value.getMinutes()).slice(-2);\n let sec = (\"0\" + value.getSeconds()).slice(-2);\n this.setValue(node, `${year}-${month}-${date}T${hour}:${min}:${sec}`);\n } else {\n for (let i = 0; i \u003c value.length; i++) {\n let char = value[i];\n let keyCode = this.characterToKeyCode(char);\n this.keyupdowned(node, \"keydown\", keyCode);\n this.setValue(node, node.value + char);\n\n this.keypressed(node, false, false, false, false, char.charCodeAt(0), char.charCodeAt(0));\n this.keyupdowned(node, \"keyup\", keyCode);\n }\n }\n\n this.changed(node);\n this.input(node);\n this.trigger(node, \"blur\");\n }\n\n setValue(node, value) {\n let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, \"value\").set;\n let nativeTextareaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, \"value\").set;\n\n if (node.tagName.toLowerCase() === 'input') {\n return nativeInputValueSetter.call(node, value);\n }\n return nativeTextareaValueSetter.call(node, value);\n }\n\n input(node) {\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(\"input\", true, false);\n node.dispatchEvent(event);\n }\n\n keyupdowned(node, eventName, keyCode) {\n let event = document.createEvent(\"UIEvents\");\n event.initEvent(eventName, true, true);\n event.keyCode = keyCode;\n event.charCode = 0;\n node.dispatchEvent(event);\n }\n\n keypressed(node, altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) {\n event = document.createEvent(\"UIEvents\");\n event.initEvent(\"keypress\", true, true);\n event.window = window;\n event.altKey = altKey;\n event.ctrlKey = ctrlKey;\n event.shiftKey = shiftKey;\n event.metaKey = metaKey;\n event.keyCode = keyCode;\n event.charCode = charCode;\n node.dispatchEvent(event);\n }\n\n characterToKeyCode(char) {\n const specialKeys = {\n 96: 192, // `\n 45: 189, // -\n 61: 187, // =\n 91: 219, // [\n 93: 221, // ]\n 92: 220, // \\\n 59: 186, // ;\n 39: 222, // '\n 44: 188, // ,\n 46: 190, // .\n 47: 191, // /\n 127: 46, // delete\n 126: 192, // ~\n 33: 49, // !\n 64: 50, // @\n 35: 51, // #\n 36: 52, // $\n 37: 53, // %\n 94: 54, // ^\n 38: 55, // \u0026\n 42: 56, // *\n 40: 57, // (\n 41: 48, // )\n 95: 189, // _\n 43: 187, // +\n 123: 219, // {\n 125: 221, // }\n 124: 220, // |\n 58: 186, // :\n 34: 222, // \"\n 60: 188, // \u003c\n 62: 190, // \u003e\n 63: 191, // ?\n }\n\n let code = char.toUpperCase().charCodeAt(0);\n return specialKeys[code] || code;\n }\n\n scrollIntoViewport(node) {\n let areaImage = this._getAreaImage(node);\n\n if (areaImage) {\n return this.scrollIntoViewport(areaImage);\n } else {\n node.scrollIntoViewIfNeeded();\n\n if (!this._isInViewport(node)) {\n node.scrollIntoView({block: \"center\", inline: \"center\", behavior: \"instant\"});\n return this._isInViewport(node);\n }\n\n return true;\n }\n }\n\n mouseEventTest(node, name, x, y) {\n let frameOffset = this._frameOffset();\n x -= frameOffset.left;\n y -= frameOffset.top;\n\n let element = document.elementFromPoint(x, y);\n\n let el = element;\n while (el) {\n if (el == node) {\n return true;\n } else {\n el = el.parentNode;\n }\n }\n\n let selector = element \u0026\u0026 this._getSelector(element) || \"none\";\n throw new MouseEventFailed([name, selector, x, y].join(\", \"));\n }\n\n _getAreaImage(node) {\n if (\"area\" == node.tagName.toLowerCase()) {\n let map = node.parentNode;\n if (map.tagName.toLowerCase() != \"map\") {\n throw new Error(\"the area is not within a map\");\n }\n\n let mapName = map.getAttribute(\"name\");\n if (typeof mapName === \"undefined\" || mapName === null) {\n throw new Error(\"area's parent map must have a name\");\n }\n\n mapName = `#${mapName.toLowerCase()}`;\n let imageNode = this.find(\"css\", `img[usemap='${mapName}']`)[0];\n if (typeof imageNode === \"undefined\" || imageNode === null) {\n throw new Error(\"no image matches the map\");\n }\n\n return imageNode;\n }\n }\n\n _frameOffset() {\n let win = window;\n let offset = { top: 0, left: 0 };\n\n while (win.frameElement) {\n let rect = win.frameElement.getClientRects()[0];\n let style = win.getComputedStyle(win.frameElement);\n win = win.parent;\n\n offset.top += rect.top + parseInt(style.getPropertyValue(\"padding-top\"), 10)\n offset.left += rect.left + parseInt(style.getPropertyValue(\"padding-left\"), 10)\n }\n\n return offset;\n }\n\n _getSelector(el) {\n let selector = (el.tagName != 'HTML') ? this._getSelector(el.parentNode) + \" \" : \"\";\n selector += el.tagName.toLowerCase();\n if (el.id) { selector += `#${el.id}` };\n el.classList.forEach(c =\u003e selector += `.${c}`);\n return selector;\n }\n\n _isInViewport(node) {\n let rect = node.getBoundingClientRect();\n return rect.top \u003e= 0 \u0026\u0026\n rect.left \u003e= 0 \u0026\u0026\n rect.bottom \u003c= window.innerHeight \u0026\u0026\n rect.right \u003c= window.innerWidth;\n }\n\n select(node, value) {\n if (this.isDisabled(node)) {\n return false;\n } else if (value == false \u0026\u0026 !node.parentNode.multiple) {\n return false;\n } else {\n this.trigger(node.parentNode, \"focus\");\n\n node.selected = value;\n this.changed(node);\n\n this.trigger(node.parentNode, \"blur\");\n return true;\n }\n }\n\n changed(node) {\n let element;\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(\"change\", true, false);\n\n // In the case of an OPTION tag, the change event should come\n // from the parent SELECT\n if (node.nodeName == \"OPTION\") {\n element = node.parentNode\n if (element.nodeName == \"OPTGROUP\") {\n element = element.parentNode\n }\n element\n } else {\n element = node\n }\n\n element.dispatchEvent(event)\n }\n\n trigger(node, name, options = {}) {\n let event;\n\n if (EVENTS.MOUSE.indexOf(name) != -1) {\n event = document.createEvent(\"MouseEvent\");\n event.initMouseEvent(\n name, true, true, window, 0,\n options[\"screenX\"] || 0, options[\"screenY\"] || 0,\n options[\"clientX\"] || 0, options[\"clientY\"] || 0,\n options[\"ctrlKey\"] || false,\n options[\"altKey\"] || false,\n options[\"shiftKey\"] || false,\n options[\"metaKey\"] || false,\n options[\"button\"] || 0, null\n )\n } else if (EVENTS.FOCUS.indexOf(name) != -1) {\n event = this.obtainEvent(name);\n } else if (EVENTS.FORM.indexOf(name) != -1) {\n event = this.obtainEvent(name);\n } else {\n throw \"Unknown event\";\n }\n\n node.dispatchEvent(event);\n }\n\n obtainEvent(name) {\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(name, true, true);\n return event;\n }\n\n getAttributes(node) {\n let attrs = {};\n for (let i = 0, len = node.attributes.length; i \u003c len; i++) {\n let attr = node.attributes[i];\n attrs[attr.name] = attr.value.replace(\"\\n\", \"\\\\n\");\n }\n\n return this._json.stringify(attrs);\n }\n\n getAttribute(node, name) {\n if (name == \"checked\" || name == \"selected\") {\n return node[name];\n } else {\n return node.getAttribute(name);\n }\n }\n\n value(node) {\n if (node.tagName == \"SELECT\" \u0026\u0026 node.multiple) {\n let result = []\n\n for (let i = 0, len = node.children.length; i \u003c len; i++) {\n let option = node.children[i];\n if (option.selected) {\n result.push(option.value);\n }\n }\n\n return result;\n } else {\n return node.value;\n }\n }\n\n deleteText(node) {\n let range = document.createRange();\n range.selectNodeContents(node);\n window.getSelection().removeAllRanges();\n window.getSelection().addRange(range);\n window.getSelection().deleteFromDocument();\n }\n\n containsSelection(node) {\n let selectedNode = document.getSelection().focusNode;\n\n if (!selectedNode) {\n return false;\n }\n\n if (selectedNode.nodeType == 3) {\n selectedNode = selectedNode.parentNode;\n }\n\n return node.contains(selectedNode);\n }\n\n isCyclic(object) {\n if (Array.isArray(object) \u0026\u0026 object.every(n =\u003e n instanceof Node)) {\n return false;\n }\n\n try {\n this._json.stringify(object);\n return false;\n } catch (e) {\n return true;\n }\n }\n\n // This command is purely for testing error handling\n browserError() {\n throw new Error(\"zomg\");\n }\n}\n\nwindow._cuprite = new Cuprite;\n","contextId":1,"returnByValue":true},"id":10}
<<< {"id":8,"result":{"identifier":"1"}}
<<< {"id":9,"result":{"identifier":"2"}}
>>> {"method":"Runtime.evaluate","params":{"expression":"/* global $ */\ndocument.addEventListener('DOMContentLoaded', function() {\n // kill bootstrap transitions\n $.support.transition = false\n\n // kill all CSS transitions\n})\n","contextId":1,"returnByValue":true},"id":11}
<<< {"id":10,"result":{"result":{"type":"object","value":{"_json":{}}}}}
<<< {"id":5,"result":{"windowId":2,"bounds":{"left":0,"top":0,"width":1200,"height":900,"windowState":"normal"}}}
>>> {"method":"Browser.getWindowForTarget","params":{"targetId":"F8F11DFDF7A67282EBC76EB6DAB06B46"},"id":5}
<<< {"id":11,"result":{"result":{"type":"undefined"}}}
>>> {"method":"Browser.setWindowBounds","params":{"windowId":2,"bounds":{"windowState":"normal"}},"id":6}
<<< {"id":6,"result":{}}
>>> {"method":"Browser.setWindowBounds","params":{"windowId":2,"bounds":{"width":1200,"height":900,"windowState":"normal"}},"id":7}
<<< {"id":7,"result":{}}
>>> {"method":"Emulation.setDeviceMetricsOverride","params":{"width":1200,"height":900,"deviceScaleFactor":1,"mobile":false},"id":12}
<<< {"method":"CSS.mediaQueryResultChanged","params":{}}
<<< {"id":12,"result":{}}
>>> {"method":"Network.setRequestInterception","params":{"patterns":[{"urlPattern":"*"}]},"id":13}
>>> {"method":"Page.getNavigationHistory","params":{},"id":14}
<<< {"id":13,"result":{}}
<<< {"id":14,"result":{"currentIndex":0,"entries":[{"id":2,"url":"about:blank","userTypedURL":"about:blank","title":"","transitionType":"typed"}]}}
>>> {"method":"Network.setRequestInterception","params":{"patterns":[{"urlPattern":"*"}]},"id":15}
<<< {"id":15,"result":{}}
>>> {"method":"Network.setCookie","params":{"name":"tracking","value":"%7B%22full%22%3Atrue%2C%22version%22%3A%222018-05-25%22%7D","domain":"127.0.0.1"},"id":16}
<<< {"id":16,"result":{"success":true}}
>>> {"method":"Page.navigate","params":{"url":"http://127.0.0.1:43279/companyslug-2"},"id":17}
<<< {"method":"Network.requestWillBeSent","params":{"requestId":"A61D1200A0A4EE2FE6909C46DD8C4A79","loaderId":"A61D1200A0A4EE2FE6909C46DD8C4A79","documentURL":"http://127.0.0.1:43279/companyslug-2","request":{"url":"http://127.0.0.1:43279/companyslug-2","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36"},"mixedContentType":"none","initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"timestamp":4237859.195411,"wallTime":1552573170.380735,"initiator":{"type":"other"},"type":"Document","frameId":"F8F11DFDF7A67282EBC76EB6DAB06B46","hasUserGesture":false}}
<<< {"method":"Network.requestIntercepted","params":{"interceptionId":"interception-job-1.0","request":{"url":"http://127.0.0.1:43279/companyslug-2","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","Cookie":"tracking=%7B%22full%22%3Atrue%2C%22version%22%3A%222018-05-25%22%7D"},"initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"frameId":"F8F11DFDF7A67282EBC76EB6DAB06B46","resourceType":"Document","isNavigationRequest":true}}
>>> {"method":"Network.continueInterceptedRequest","params":{"interceptionId":"interception-job-1.0"},"id":18}
<<< {"id":18,"result":{}}
<<< {"method":"Network.requestWillBeSent","params":{"requestId":"A61D1200A0A4EE2FE6909C46DD8C4A79","loaderId":"A61D1200A0A4EE2FE6909C46DD8C4A79","documentURL":"http://127.0.0.1:43279/wayne-enterprises-2","request":{"url":"http://127.0.0.1:43279/wayne-enterprises-2","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36"},"mixedContentType":"none","initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"timestamp":4237859.365825,"wallTime":1552573170.551149,"initiator":{"type":"other"},"redirectResponse":{"url":"http://127.0.0.1:43279/companyslug-2","status":301,"statusText":"Moved Permanently","headers":{"X-Frame-Options":"SAMEORIGIN","X-Xss-Protection":"1; mode=block","X-Content-Type-Options":"nosniff","Location":"http://127.0.0.1:43279/wayne-enterprises-2","Content-Type":"text/html; charset=utf-8","Cache-Control":"no-cache","X-Request-Id":"f6eb29b9-8d12-41e7-848d-9d55600da5a1","X-Runtime":"0.157283","Server":"WEBrick/1.4.2 (Ruby/2.5.3/2018-10-18)","Date":"Thu, 14 Mar 2019 14:19:30 GMT","Content-Length":"117","Connection":"Keep-Alive","Set-Cookie":"locale=de; path=/; expires=Sun, 14 Apr 2019 13:19:30 -0000"},"headersText":"HTTP/1.1 301 Moved Permanently\r\nX-Frame-Options: SAMEORIGIN\r\nX-Xss-Protection: 1; mode=block\r\nX-Content-Type-Options: nosniff\r\nLocation: http://127.0.0.1:43279/wayne-enterprises-2\r\nContent-Type: text/html; charset=utf-8\r\nCache-Control: no-cache\r\nX-Request-Id: f6eb29b9-8d12-41e7-848d-9d55600da5a1\r\nX-Runtime: 0.157283\r\nServer: WEBrick/1.4.2 (Ruby/2.5.3/2018-10-18)\r\nDate: Thu, 14 Mar 2019 14:19:30 GMT\r\nContent-Length: 117\r\nConnection: Keep-Alive\r\nSet-Cookie: locale=de; path=/; expires=Sun, 14 Apr 2019 13:19:30 -0000\r\n\r\n","mimeType":"text/html","requestHeaders":{"Host":"127.0.0.1:43279","Connection":"keep-alive","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","Accept-Encoding":"gzip, deflate, br","Cookie":"tracking=%7B%22full%22%3Atrue%2C%22version%22%3A%222018-05-25%22%7D"},"requestHeadersText":"GET /companyslug-2 HTTP/1.1\r\nHost: 127.0.0.1:43279\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nCookie: tracking=%7B%22full%22%3Atrue%2C%22version%22%3A%222018-05-25%22%7D\r\n","connectionReused":false,"connectionId":12,"remoteIPAddress":"127.0.0.1","remotePort":43279,"fromDiskCache":false,"fromServiceWorker":false,"encodedDataLength":536,"timing":{"requestTime":4237859.19903,"proxyStart":-1,"proxyEnd":-1,"dnsStart":0.351,"dnsEnd":0.389,"connectStart":0.389,"connectEnd":0.575,"sslStart":-1,"sslEnd":-1,"workerStart":-1,"workerReady":-1,"sendStart":0.624,"sendEnd":0.656,"pushStart":0,"pushEnd":0,"receiveHeadersEnd":165.671},"protocol":"http/1.1","securityState":"neutral"},"type":"Document","frameId":"F8F11DFDF7A67282EBC76EB6DAB06B46","hasUserGesture":false}}
<<< {"method":"Network.requestIntercepted","params":{"interceptionId":"interception-job-1.1","request":{"url":"http://127.0.0.1:43279/wayne-enterprises-2","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","Cookie":"tracking=%7B%22full%22%3Atrue%2C%22version%22%3A%222018-05-25%22%7D; locale=de"},"initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"frameId":"F8F11DFDF7A67282EBC76EB6DAB06B46","resourceType":"Document","isNavigationRequest":true}}
>>> {"method":"Network.continueInterceptedRequest","params":{"interceptionId":"interception-job-1.1"},"id":19}
<<< {"id":19,"result":{}}
>>> {"method":"Runtime.callFunctionOn","params":{"functionDeclaration":"function() { return window.location.href }","arguments":[],"executionContextId":1},"id":20}
>>> {"method":"Target.detachFromTarget","params":{"sessionId":"A63DAC7C5D613751CB0AB0B3EF9D7C59"},"id":8}
F
Failures:
1.1) Failure/Error: page.visit "/companyslug-#{company.id}"
Capybara::Cuprite::DeadBrowser:
Chrome is dead
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/client.rb:41:in `wait'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/page.rb:196:in `command'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/page.rb:77:in `visit'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/driver.rb:31:in `visit'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara/session.rb:274:in `visit'
# ./spec/features/company/vcard_spec.rb:35:in `block (2 levels) in <top (required)>'
1.2) Failure/Error: raise DeadBrowser unless message
Capybara::Cuprite::DeadBrowser:
Chrome is dead
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/client.rb:41:in `wait'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/page.rb:196:in `command'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/runtime.rb:81:in `call'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/runtime.rb:32:in `evaluate'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/frame.rb:19:in `frame_url'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/driver.rb:43:in `frame_url'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/driver.rb:36:in `current_url'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara/session.rb:217:in `current_url'
# /bundle/2.5.3/gems/capybara-screenshot-1.0.14/lib/capybara-screenshot/rspec.rb:55:in `block in after_failed_example'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara.rb:351:in `using_session'
# /bundle/2.5.3/gems/capybara-screenshot-1.0.14/lib/capybara-screenshot/rspec.rb:54:in `after_failed_example'
# /bundle/2.5.3/gems/capybara-screenshot-1.0.14/lib/capybara-screenshot/rspec.rb:84:in `block (2 levels) in <top (required)>'
1.3) Failure/Error: @sock.write(data)
Errno::EPIPE:
Broken pipe
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/web_socket.rb:61:in `write'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/web_socket.rb:61:in `write'
# /bundle/2.5.3/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi.rb:228:in `send_frame'
# /bundle/2.5.3/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi.rb:191:in `frame'
# /bundle/2.5.3/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi.rb:154:in `close'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/web_socket.rb:65:in `close'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/client.rb:56:in `close'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:214:in `quit'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:209:in `restart'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:236:in `rescue in command'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:232:in `command'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/page.rb:89:in `close'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/targets.rb:80:in `reset'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:205:in `reset'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/driver.rb:131:in `reset!'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara/session.rb:127:in `reset!'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara.rb:314:in `block in reset_sessions!'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara.rb:314:in `reverse_each'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara.rb:314:in `reset_sessions!'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara/rspec.rb:22:in `block (2 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# Capybara::Cuprite::DeadBrowser:
# Chrome is dead
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/client.rb:41:in `wait'
Finished in 6.98 seconds (files took 9.03 seconds to load)
1 example, 1 failure
Failed examples:
Yea looks fishy, I see you are using black or whitelisting, try to turn it off for a test, any better? If no again logs would be awesome
Yes, use blacklists, but turning off not helping:
<<< {"id":1,"result":{"targetInfos":[{"targetId":"F477F57E939E7C973211ADB2145D6A71","type":"page","title":"","url":"about:blank","attached":false,"browserContextId":"1294B76B78ADEF3F3F9F9C63E22789FA"}]}}
>>> {"method":"Target.createBrowserContext","params":{},"id":2}
<<< {"id":2,"result":{"browserContextId":"A29200EC561BEDFD2D45DDC2FA8131C9"}}
>>> {"method":"Target.createTarget","params":{"url":"about:blank","browserContextId":"A29200EC561BEDFD2D45DDC2FA8131C9"},"id":3}
<<< {"id":3,"result":{"targetId":"4DB9991144C865BC1A76C00D74208FF9"}}
>>> {"method":"Target.attachToTarget","params":{"targetId":"4DB9991144C865BC1A76C00D74208FF9"},"id":4}
<<< {"method":"Target.attachedToTarget","params":{"sessionId":"10A96BAE9B51A6B48F861DE89CB669A2","targetInfo":{"targetId":"4DB9991144C865BC1A76C00D74208FF9","type":"page","title":"","url":"about:blank","attached":true,"browserContextId":"A29200EC561BEDFD2D45DDC2FA8131C9"},"waitingForDebugger":false}}
<<< {"id":4,"result":{"sessionId":"10A96BAE9B51A6B48F861DE89CB669A2"}}
>>> {"method":"Page.enable","params":{},"id":1}
<<< {"id":1,"result":{}}
>>> {"method":"DOM.enable","params":{},"id":2}
<<< {"id":2,"result":{}}
>>> {"method":"CSS.enable","params":{},"id":3}
<<< {"id":3,"result":{}}
>>> {"method":"Runtime.enable","params":{},"id":4}
<<< {"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"origin":"://","name":"","auxData":{"isDefault":true,"type":"default","frameId":"4DB9991144C865BC1A76C00D74208FF9"}}}}
<<< {"id":4,"result":{}}
>>> {"method":"Log.enable","params":{},"id":5}
<<< {"id":5,"result":{}}
>>> {"method":"Network.enable","params":{},"id":6}
<<< {"id":6,"result":{}}
>>> {"method":"Page.setDownloadBehavior","params":{"behavior":"allow","downloadPath":"/app/capybara"},"id":7}
<<< {"id":7,"result":{}}
>>> {"method":"Page.addScriptToEvaluateOnNewDocument","params":{"source":"class InvalidSelector extends Error {}\nclass TimedOutPromise extends Error {}\nclass MouseEventFailed extends Error {}\n\nconst EVENTS = {\n FOCUS: [\"blur\", \"focus\", \"focusin\", \"focusout\"],\n MOUSE: [\"click\", \"dblclick\", \"mousedown\", \"mouseenter\", \"mouseleave\",\n \"mousemove\", \"mouseover\", \"mouseout\", \"mouseup\", \"contextmenu\"],\n FORM: [\"submit\"]\n}\n\nclass Cuprite {\n constructor() {\n this._json = JSON; // In case someone overrides it like mootools\n }\n\n find(method, selector, within = document) {\n try {\n let results = [];\n\n if (method == \"xpath\") {\n let xpath = document.evaluate(selector, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n for (let i = 0; i \u003c xpath.snapshotLength; i++) {\n results.push(xpath.snapshotItem(i));\n }\n } else {\n results = Array.from(within.querySelectorAll(selector));\n }\n\n return results;\n } catch (error) {\n // DOMException.INVALID_EXPRESSION_ERR is undefined, using pure code\n if (error.code == DOMException.SYNTAX_ERR || error.code == 51) {\n throw new InvalidSelector;\n } else {\n throw error;\n }\n }\n }\n\n parents(node) {\n let nodes = [];\n let parent = node.parentNode;\n while (parent != document) {\n nodes.push(parent);\n parent = parent.parentNode;\n }\n return nodes;\n }\n\n visibleText(node) {\n if (this.isVisible(node)) {\n if (node.nodeName == \"TEXTAREA\") {\n return node.textContent;\n } else {\n if (node instanceof SVGElement) {\n return node.textContent;\n } else {\n return node.innerText;\n }\n }\n }\n }\n\n isVisible(node) {\n let mapName, style;\n // if node is area, check visibility of relevant image\n if (node.tagName === \"AREA\") {\n mapName = document.evaluate(\"./ancestor::map/@name\", node, null, XPathResult.STRING_TYPE, null).stringValue;\n node = document.querySelector(`img[usemap=\"#${mapName}\"]`);\n if (node == null) {\n return false;\n }\n }\n\n while (node) {\n style = window.getComputedStyle(node);\n if (style.display === \"none\" || style.visibility === \"hidden\" || parseFloat(style.opacity) === 0) {\n return false;\n }\n node = node.parentElement;\n }\n\n return true;\n }\n\n\n isDisabled(node) {\n let xpath = \"parent::optgroup[@disabled] | \\\n ancestor::select[@disabled] | \\\n parent::fieldset[@disabled] | \\\n ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]\";\n\n return node.disabled || document.evaluate(xpath, node, null, XPathResult.BOOLEAN_TYPE, null).booleanValue;\n }\n\n path(node) {\n let nodes = [node];\n let parent = node.parentNode;\n while (parent !== document) {\n nodes.unshift(parent);\n parent = parent.parentNode;\n }\n\n let selectors = nodes.map(node =\u003e {\n let prevSiblings = [];\n let xpath = document.evaluate(`./preceding-sibling::${node.tagName}`, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n\n for (let i = 0; i \u003c xpath.snapshotLength; i++) {\n prevSiblings.push(xpath.snapshotItem(i));\n }\n\n return `${node.tagName}[${(prevSiblings.length + 1)}]`;\n });\n\n return `//${selectors.join(\"/\")}`;\n }\n\n set(node, value) {\n if (node.readOnly) return;\n\n if (node.maxLength \u003e= 0) {\n value = value.substr(0, node.maxLength);\n }\n\n this.trigger(node, \"focus\");\n this.setValue(node, \"\");\n\n if (node.type == \"number\" || node.type == \"date\") {\n this.setValue(node, value);\n } else if (node.type == \"time\") {\n this.setValue(node, new Date(value).toTimeString().split(\" \")[0]);\n } else if (node.type == \"datetime-local\") {\n value = new Date(value);\n let year = value.getFullYear();\n let month = (\"0\" + (value.getMonth() + 1)).slice(-2);\n let date = (\"0\" + value.getDate()).slice(-2);\n let hour = (\"0\" + value.getHours()).slice(-2);\n let min = (\"0\" + value.getMinutes()).slice(-2);\n let sec = (\"0\" + value.getSeconds()).slice(-2);\n this.setValue(node, `${year}-${month}-${date}T${hour}:${min}:${sec}`);\n } else {\n for (let i = 0; i \u003c value.length; i++) {\n let char = value[i];\n let keyCode = this.characterToKeyCode(char);\n this.keyupdowned(node, \"keydown\", keyCode);\n this.setValue(node, node.value + char);\n\n this.keypressed(node, false, false, false, false, char.charCodeAt(0), char.charCodeAt(0));\n this.keyupdowned(node, \"keyup\", keyCode);\n }\n }\n\n this.changed(node);\n this.input(node);\n this.trigger(node, \"blur\");\n }\n\n setValue(node, value) {\n let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, \"value\").set;\n let nativeTextareaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, \"value\").set;\n\n if (node.tagName.toLowerCase() === 'input') {\n return nativeInputValueSetter.call(node, value);\n }\n return nativeTextareaValueSetter.call(node, value);\n }\n\n input(node) {\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(\"input\", true, false);\n node.dispatchEvent(event);\n }\n\n keyupdowned(node, eventName, keyCode) {\n let event = document.createEvent(\"UIEvents\");\n event.initEvent(eventName, true, true);\n event.keyCode = keyCode;\n event.charCode = 0;\n node.dispatchEvent(event);\n }\n\n keypressed(node, altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) {\n event = document.createEvent(\"UIEvents\");\n event.initEvent(\"keypress\", true, true);\n event.window = window;\n event.altKey = altKey;\n event.ctrlKey = ctrlKey;\n event.shiftKey = shiftKey;\n event.metaKey = metaKey;\n event.keyCode = keyCode;\n event.charCode = charCode;\n node.dispatchEvent(event);\n }\n\n characterToKeyCode(char) {\n const specialKeys = {\n 96: 192, // `\n 45: 189, // -\n 61: 187, // =\n 91: 219, // [\n 93: 221, // ]\n 92: 220, // \\\n 59: 186, // ;\n 39: 222, // '\n 44: 188, // ,\n 46: 190, // .\n 47: 191, // /\n 127: 46, // delete\n 126: 192, // ~\n 33: 49, // !\n 64: 50, // @\n 35: 51, // #\n 36: 52, // $\n 37: 53, // %\n 94: 54, // ^\n 38: 55, // \u0026\n 42: 56, // *\n 40: 57, // (\n 41: 48, // )\n 95: 189, // _\n 43: 187, // +\n 123: 219, // {\n 125: 221, // }\n 124: 220, // |\n 58: 186, // :\n 34: 222, // \"\n 60: 188, // \u003c\n 62: 190, // \u003e\n 63: 191, // ?\n }\n\n let code = char.toUpperCase().charCodeAt(0);\n return specialKeys[code] || code;\n }\n\n scrollIntoViewport(node) {\n let areaImage = this._getAreaImage(node);\n\n if (areaImage) {\n return this.scrollIntoViewport(areaImage);\n } else {\n node.scrollIntoViewIfNeeded();\n\n if (!this._isInViewport(node)) {\n node.scrollIntoView({block: \"center\", inline: \"center\", behavior: \"instant\"});\n return this._isInViewport(node);\n }\n\n return true;\n }\n }\n\n mouseEventTest(node, name, x, y) {\n let frameOffset = this._frameOffset();\n x -= frameOffset.left;\n y -= frameOffset.top;\n\n let element = document.elementFromPoint(x, y);\n\n let el = element;\n while (el) {\n if (el == node) {\n return true;\n } else {\n el = el.parentNode;\n }\n }\n\n let selector = element \u0026\u0026 this._getSelector(element) || \"none\";\n throw new MouseEventFailed([name, selector, x, y].join(\", \"));\n }\n\n _getAreaImage(node) {\n if (\"area\" == node.tagName.toLowerCase()) {\n let map = node.parentNode;\n if (map.tagName.toLowerCase() != \"map\") {\n throw new Error(\"the area is not within a map\");\n }\n\n let mapName = map.getAttribute(\"name\");\n if (typeof mapName === \"undefined\" || mapName === null) {\n throw new Error(\"area's parent map must have a name\");\n }\n\n mapName = `#${mapName.toLowerCase()}`;\n let imageNode = this.find(\"css\", `img[usemap='${mapName}']`)[0];\n if (typeof imageNode === \"undefined\" || imageNode === null) {\n throw new Error(\"no image matches the map\");\n }\n\n return imageNode;\n }\n }\n\n _frameOffset() {\n let win = window;\n let offset = { top: 0, left: 0 };\n\n while (win.frameElement) {\n let rect = win.frameElement.getClientRects()[0];\n let style = win.getComputedStyle(win.frameElement);\n win = win.parent;\n\n offset.top += rect.top + parseInt(style.getPropertyValue(\"padding-top\"), 10)\n offset.left += rect.left + parseInt(style.getPropertyValue(\"padding-left\"), 10)\n }\n\n return offset;\n }\n\n _getSelector(el) {\n let selector = (el.tagName != 'HTML') ? this._getSelector(el.parentNode) + \" \" : \"\";\n selector += el.tagName.toLowerCase();\n if (el.id) { selector += `#${el.id}` };\n el.classList.forEach(c =\u003e selector += `.${c}`);\n return selector;\n }\n\n _isInViewport(node) {\n let rect = node.getBoundingClientRect();\n return rect.top \u003e= 0 \u0026\u0026\n rect.left \u003e= 0 \u0026\u0026\n rect.bottom \u003c= window.innerHeight \u0026\u0026\n rect.right \u003c= window.innerWidth;\n }\n\n select(node, value) {\n if (this.isDisabled(node)) {\n return false;\n } else if (value == false \u0026\u0026 !node.parentNode.multiple) {\n return false;\n } else {\n this.trigger(node.parentNode, \"focus\");\n\n node.selected = value;\n this.changed(node);\n\n this.trigger(node.parentNode, \"blur\");\n return true;\n }\n }\n\n changed(node) {\n let element;\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(\"change\", true, false);\n\n // In the case of an OPTION tag, the change event should come\n // from the parent SELECT\n if (node.nodeName == \"OPTION\") {\n element = node.parentNode\n if (element.nodeName == \"OPTGROUP\") {\n element = element.parentNode\n }\n element\n } else {\n element = node\n }\n\n element.dispatchEvent(event)\n }\n\n trigger(node, name, options = {}) {\n let event;\n\n if (EVENTS.MOUSE.indexOf(name) != -1) {\n event = document.createEvent(\"MouseEvent\");\n event.initMouseEvent(\n name, true, true, window, 0,\n options[\"screenX\"] || 0, options[\"screenY\"] || 0,\n options[\"clientX\"] || 0, options[\"clientY\"] || 0,\n options[\"ctrlKey\"] || false,\n options[\"altKey\"] || false,\n options[\"shiftKey\"] || false,\n options[\"metaKey\"] || false,\n options[\"button\"] || 0, null\n )\n } else if (EVENTS.FOCUS.indexOf(name) != -1) {\n event = this.obtainEvent(name);\n } else if (EVENTS.FORM.indexOf(name) != -1) {\n event = this.obtainEvent(name);\n } else {\n throw \"Unknown event\";\n }\n\n node.dispatchEvent(event);\n }\n\n obtainEvent(name) {\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(name, true, true);\n return event;\n }\n\n getAttributes(node) {\n let attrs = {};\n for (let i = 0, len = node.attributes.length; i \u003c len; i++) {\n let attr = node.attributes[i];\n attrs[attr.name] = attr.value.replace(\"\\n\", \"\\\\n\");\n }\n\n return this._json.stringify(attrs);\n }\n\n getAttribute(node, name) {\n if (name == \"checked\" || name == \"selected\") {\n return node[name];\n } else {\n return node.getAttribute(name);\n }\n }\n\n value(node) {\n if (node.tagName == \"SELECT\" \u0026\u0026 node.multiple) {\n let result = []\n\n for (let i = 0, len = node.children.length; i \u003c len; i++) {\n let option = node.children[i];\n if (option.selected) {\n result.push(option.value);\n }\n }\n\n return result;\n } else {\n return node.value;\n }\n }\n\n deleteText(node) {\n let range = document.createRange();\n range.selectNodeContents(node);\n window.getSelection().removeAllRanges();\n window.getSelection().addRange(range);\n window.getSelection().deleteFromDocument();\n }\n\n containsSelection(node) {\n let selectedNode = document.getSelection().focusNode;\n\n if (!selectedNode) {\n return false;\n }\n\n if (selectedNode.nodeType == 3) {\n selectedNode = selectedNode.parentNode;\n }\n\n return node.contains(selectedNode);\n }\n\n isCyclic(object) {\n if (Array.isArray(object) \u0026\u0026 object.every(n =\u003e n instanceof Node)) {\n return false;\n }\n\n try {\n this._json.stringify(object);\n return false;\n } catch (e) {\n return true;\n }\n }\n\n // This command is purely for testing error handling\n browserError() {\n throw new Error(\"zomg\");\n }\n}\n\nwindow._cuprite = new Cuprite;\n"},"id":8}
>>> {"method":"Page.addScriptToEvaluateOnNewDocument","params":{"source":"/* global $ */\ndocument.addEventListener('DOMContentLoaded', function() {\n // kill bootstrap transitions\n $.support.transition = false\n\n // kill all CSS transitions\n})\n"},"id":9}
>>> {"method":"Runtime.evaluate","params":{"expression":"class InvalidSelector extends Error {}\nclass TimedOutPromise extends Error {}\nclass MouseEventFailed extends Error {}\n\nconst EVENTS = {\n FOCUS: [\"blur\", \"focus\", \"focusin\", \"focusout\"],\n MOUSE: [\"click\", \"dblclick\", \"mousedown\", \"mouseenter\", \"mouseleave\",\n \"mousemove\", \"mouseover\", \"mouseout\", \"mouseup\", \"contextmenu\"],\n FORM: [\"submit\"]\n}\n\nclass Cuprite {\n constructor() {\n this._json = JSON; // In case someone overrides it like mootools\n }\n\n find(method, selector, within = document) {\n try {\n let results = [];\n\n if (method == \"xpath\") {\n let xpath = document.evaluate(selector, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n for (let i = 0; i \u003c xpath.snapshotLength; i++) {\n results.push(xpath.snapshotItem(i));\n }\n } else {\n results = Array.from(within.querySelectorAll(selector));\n }\n\n return results;\n } catch (error) {\n // DOMException.INVALID_EXPRESSION_ERR is undefined, using pure code\n if (error.code == DOMException.SYNTAX_ERR || error.code == 51) {\n throw new InvalidSelector;\n } else {\n throw error;\n }\n }\n }\n\n parents(node) {\n let nodes = [];\n let parent = node.parentNode;\n while (parent != document) {\n nodes.push(parent);\n parent = parent.parentNode;\n }\n return nodes;\n }\n\n visibleText(node) {\n if (this.isVisible(node)) {\n if (node.nodeName == \"TEXTAREA\") {\n return node.textContent;\n } else {\n if (node instanceof SVGElement) {\n return node.textContent;\n } else {\n return node.innerText;\n }\n }\n }\n }\n\n isVisible(node) {\n let mapName, style;\n // if node is area, check visibility of relevant image\n if (node.tagName === \"AREA\") {\n mapName = document.evaluate(\"./ancestor::map/@name\", node, null, XPathResult.STRING_TYPE, null).stringValue;\n node = document.querySelector(`img[usemap=\"#${mapName}\"]`);\n if (node == null) {\n return false;\n }\n }\n\n while (node) {\n style = window.getComputedStyle(node);\n if (style.display === \"none\" || style.visibility === \"hidden\" || parseFloat(style.opacity) === 0) {\n return false;\n }\n node = node.parentElement;\n }\n\n return true;\n }\n\n\n isDisabled(node) {\n let xpath = \"parent::optgroup[@disabled] | \\\n ancestor::select[@disabled] | \\\n parent::fieldset[@disabled] | \\\n ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]\";\n\n return node.disabled || document.evaluate(xpath, node, null, XPathResult.BOOLEAN_TYPE, null).booleanValue;\n }\n\n path(node) {\n let nodes = [node];\n let parent = node.parentNode;\n while (parent !== document) {\n nodes.unshift(parent);\n parent = parent.parentNode;\n }\n\n let selectors = nodes.map(node =\u003e {\n let prevSiblings = [];\n let xpath = document.evaluate(`./preceding-sibling::${node.tagName}`, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n\n for (let i = 0; i \u003c xpath.snapshotLength; i++) {\n prevSiblings.push(xpath.snapshotItem(i));\n }\n\n return `${node.tagName}[${(prevSiblings.length + 1)}]`;\n });\n\n return `//${selectors.join(\"/\")}`;\n }\n\n set(node, value) {\n if (node.readOnly) return;\n\n if (node.maxLength \u003e= 0) {\n value = value.substr(0, node.maxLength);\n }\n\n this.trigger(node, \"focus\");\n this.setValue(node, \"\");\n\n if (node.type == \"number\" || node.type == \"date\") {\n this.setValue(node, value);\n } else if (node.type == \"time\") {\n this.setValue(node, new Date(value).toTimeString().split(\" \")[0]);\n } else if (node.type == \"datetime-local\") {\n value = new Date(value);\n let year = value.getFullYear();\n let month = (\"0\" + (value.getMonth() + 1)).slice(-2);\n let date = (\"0\" + value.getDate()).slice(-2);\n let hour = (\"0\" + value.getHours()).slice(-2);\n let min = (\"0\" + value.getMinutes()).slice(-2);\n let sec = (\"0\" + value.getSeconds()).slice(-2);\n this.setValue(node, `${year}-${month}-${date}T${hour}:${min}:${sec}`);\n } else {\n for (let i = 0; i \u003c value.length; i++) {\n let char = value[i];\n let keyCode = this.characterToKeyCode(char);\n this.keyupdowned(node, \"keydown\", keyCode);\n this.setValue(node, node.value + char);\n\n this.keypressed(node, false, false, false, false, char.charCodeAt(0), char.charCodeAt(0));\n this.keyupdowned(node, \"keyup\", keyCode);\n }\n }\n\n this.changed(node);\n this.input(node);\n this.trigger(node, \"blur\");\n }\n\n setValue(node, value) {\n let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, \"value\").set;\n let nativeTextareaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, \"value\").set;\n\n if (node.tagName.toLowerCase() === 'input') {\n return nativeInputValueSetter.call(node, value);\n }\n return nativeTextareaValueSetter.call(node, value);\n }\n\n input(node) {\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(\"input\", true, false);\n node.dispatchEvent(event);\n }\n\n keyupdowned(node, eventName, keyCode) {\n let event = document.createEvent(\"UIEvents\");\n event.initEvent(eventName, true, true);\n event.keyCode = keyCode;\n event.charCode = 0;\n node.dispatchEvent(event);\n }\n\n keypressed(node, altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) {\n event = document.createEvent(\"UIEvents\");\n event.initEvent(\"keypress\", true, true);\n event.window = window;\n event.altKey = altKey;\n event.ctrlKey = ctrlKey;\n event.shiftKey = shiftKey;\n event.metaKey = metaKey;\n event.keyCode = keyCode;\n event.charCode = charCode;\n node.dispatchEvent(event);\n }\n\n characterToKeyCode(char) {\n const specialKeys = {\n 96: 192, // `\n 45: 189, // -\n 61: 187, // =\n 91: 219, // [\n 93: 221, // ]\n 92: 220, // \\\n 59: 186, // ;\n 39: 222, // '\n 44: 188, // ,\n 46: 190, // .\n 47: 191, // /\n 127: 46, // delete\n 126: 192, // ~\n 33: 49, // !\n 64: 50, // @\n 35: 51, // #\n 36: 52, // $\n 37: 53, // %\n 94: 54, // ^\n 38: 55, // \u0026\n 42: 56, // *\n 40: 57, // (\n 41: 48, // )\n 95: 189, // _\n 43: 187, // +\n 123: 219, // {\n 125: 221, // }\n 124: 220, // |\n 58: 186, // :\n 34: 222, // \"\n 60: 188, // \u003c\n 62: 190, // \u003e\n 63: 191, // ?\n }\n\n let code = char.toUpperCase().charCodeAt(0);\n return specialKeys[code] || code;\n }\n\n scrollIntoViewport(node) {\n let areaImage = this._getAreaImage(node);\n\n if (areaImage) {\n return this.scrollIntoViewport(areaImage);\n } else {\n node.scrollIntoViewIfNeeded();\n\n if (!this._isInViewport(node)) {\n node.scrollIntoView({block: \"center\", inline: \"center\", behavior: \"instant\"});\n return this._isInViewport(node);\n }\n\n return true;\n }\n }\n\n mouseEventTest(node, name, x, y) {\n let frameOffset = this._frameOffset();\n x -= frameOffset.left;\n y -= frameOffset.top;\n\n let element = document.elementFromPoint(x, y);\n\n let el = element;\n while (el) {\n if (el == node) {\n return true;\n } else {\n el = el.parentNode;\n }\n }\n\n let selector = element \u0026\u0026 this._getSelector(element) || \"none\";\n throw new MouseEventFailed([name, selector, x, y].join(\", \"));\n }\n\n _getAreaImage(node) {\n if (\"area\" == node.tagName.toLowerCase()) {\n let map = node.parentNode;\n if (map.tagName.toLowerCase() != \"map\") {\n throw new Error(\"the area is not within a map\");\n }\n\n let mapName = map.getAttribute(\"name\");\n if (typeof mapName === \"undefined\" || mapName === null) {\n throw new Error(\"area's parent map must have a name\");\n }\n\n mapName = `#${mapName.toLowerCase()}`;\n let imageNode = this.find(\"css\", `img[usemap='${mapName}']`)[0];\n if (typeof imageNode === \"undefined\" || imageNode === null) {\n throw new Error(\"no image matches the map\");\n }\n\n return imageNode;\n }\n }\n\n _frameOffset() {\n let win = window;\n let offset = { top: 0, left: 0 };\n\n while (win.frameElement) {\n let rect = win.frameElement.getClientRects()[0];\n let style = win.getComputedStyle(win.frameElement);\n win = win.parent;\n\n offset.top += rect.top + parseInt(style.getPropertyValue(\"padding-top\"), 10)\n offset.left += rect.left + parseInt(style.getPropertyValue(\"padding-left\"), 10)\n }\n\n return offset;\n }\n\n _getSelector(el) {\n let selector = (el.tagName != 'HTML') ? this._getSelector(el.parentNode) + \" \" : \"\";\n selector += el.tagName.toLowerCase();\n if (el.id) { selector += `#${el.id}` };\n el.classList.forEach(c =\u003e selector += `.${c}`);\n return selector;\n }\n\n _isInViewport(node) {\n let rect = node.getBoundingClientRect();\n return rect.top \u003e= 0 \u0026\u0026\n rect.left \u003e= 0 \u0026\u0026\n rect.bottom \u003c= window.innerHeight \u0026\u0026\n rect.right \u003c= window.innerWidth;\n }\n\n select(node, value) {\n if (this.isDisabled(node)) {\n return false;\n } else if (value == false \u0026\u0026 !node.parentNode.multiple) {\n return false;\n } else {\n this.trigger(node.parentNode, \"focus\");\n\n node.selected = value;\n this.changed(node);\n\n this.trigger(node.parentNode, \"blur\");\n return true;\n }\n }\n\n changed(node) {\n let element;\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(\"change\", true, false);\n\n // In the case of an OPTION tag, the change event should come\n // from the parent SELECT\n if (node.nodeName == \"OPTION\") {\n element = node.parentNode\n if (element.nodeName == \"OPTGROUP\") {\n element = element.parentNode\n }\n element\n } else {\n element = node\n }\n\n element.dispatchEvent(event)\n }\n\n trigger(node, name, options = {}) {\n let event;\n\n if (EVENTS.MOUSE.indexOf(name) != -1) {\n event = document.createEvent(\"MouseEvent\");\n event.initMouseEvent(\n name, true, true, window, 0,\n options[\"screenX\"] || 0, options[\"screenY\"] || 0,\n options[\"clientX\"] || 0, options[\"clientY\"] || 0,\n options[\"ctrlKey\"] || false,\n options[\"altKey\"] || false,\n options[\"shiftKey\"] || false,\n options[\"metaKey\"] || false,\n options[\"button\"] || 0, null\n )\n } else if (EVENTS.FOCUS.indexOf(name) != -1) {\n event = this.obtainEvent(name);\n } else if (EVENTS.FORM.indexOf(name) != -1) {\n event = this.obtainEvent(name);\n } else {\n throw \"Unknown event\";\n }\n\n node.dispatchEvent(event);\n }\n\n obtainEvent(name) {\n let event = document.createEvent(\"HTMLEvents\");\n event.initEvent(name, true, true);\n return event;\n }\n\n getAttributes(node) {\n let attrs = {};\n for (let i = 0, len = node.attributes.length; i \u003c len; i++) {\n let attr = node.attributes[i];\n attrs[attr.name] = attr.value.replace(\"\\n\", \"\\\\n\");\n }\n\n return this._json.stringify(attrs);\n }\n\n getAttribute(node, name) {\n if (name == \"checked\" || name == \"selected\") {\n return node[name];\n } else {\n return node.getAttribute(name);\n }\n }\n\n value(node) {\n if (node.tagName == \"SELECT\" \u0026\u0026 node.multiple) {\n let result = []\n\n for (let i = 0, len = node.children.length; i \u003c len; i++) {\n let option = node.children[i];\n if (option.selected) {\n result.push(option.value);\n }\n }\n\n return result;\n } else {\n return node.value;\n }\n }\n\n deleteText(node) {\n let range = document.createRange();\n range.selectNodeContents(node);\n window.getSelection().removeAllRanges();\n window.getSelection().addRange(range);\n window.getSelection().deleteFromDocument();\n }\n\n containsSelection(node) {\n let selectedNode = document.getSelection().focusNode;\n\n if (!selectedNode) {\n return false;\n }\n\n if (selectedNode.nodeType == 3) {\n selectedNode = selectedNode.parentNode;\n }\n\n return node.contains(selectedNode);\n }\n\n isCyclic(object) {\n if (Array.isArray(object) \u0026\u0026 object.every(n =\u003e n instanceof Node)) {\n return false;\n }\n\n try {\n this._json.stringify(object);\n return false;\n } catch (e) {\n return true;\n }\n }\n\n // This command is purely for testing error handling\n browserError() {\n throw new Error(\"zomg\");\n }\n}\n\nwindow._cuprite = new Cuprite;\n","contextId":1,"returnByValue":true},"id":10}
>>> {"method":"Runtime.evaluate","params":{"expression":"/* global $ */\ndocument.addEventListener('DOMContentLoaded', function() {\n // kill bootstrap transitions\n $.support.transition = false\n\n // kill all CSS transitions\n})\n","contextId":1,"returnByValue":true},"id":11}
<<< {"id":5,"result":{"windowId":2,"bounds":{"left":0,"top":0,"width":1200,"height":900,"windowState":"normal"}}}
>>> {"method":"Browser.getWindowForTarget","params":{"targetId":"4DB9991144C865BC1A76C00D74208FF9"},"id":5}
<<< {"id":6,"result":{}}
>>> {"method":"Browser.setWindowBounds","params":{"windowId":2,"bounds":{"windowState":"normal"}},"id":6}
<<< {"id":8,"result":{"identifier":"1"}}
<<< {"id":9,"result":{"identifier":"2"}}
<<< {"id":10,"result":{"result":{"type":"object","value":{"_json":{}}}}}
>>> {"method":"Browser.setWindowBounds","params":{"windowId":2,"bounds":{"width":1200,"height":900,"windowState":"normal"}},"id":7}
<<< {"id":7,"result":{}}
<<< {"id":11,"result":{"result":{"type":"undefined"}}}
>>> {"method":"Emulation.setDeviceMetricsOverride","params":{"width":1200,"height":900,"deviceScaleFactor":1,"mobile":false},"id":12}
<<< {"method":"CSS.mediaQueryResultChanged","params":{}}
<<< {"id":12,"result":{}}
>>> {"method":"Page.getNavigationHistory","params":{},"id":13}
<<< {"id":13,"result":{"currentIndex":0,"entries":[{"id":2,"url":"about:blank","userTypedURL":"about:blank","title":"","transitionType":"typed"}]}}
>>> {"method":"Network.setCookie","params":{"name":"tracking","value":"%7B%22full%22%3Atrue%2C%22version%22%3A%222018-05-25%22%7D","domain":"127.0.0.1"},"id":14}
<<< {"id":14,"result":{"success":true}}
>>> {"method":"Page.navigate","params":{"url":"http://127.0.0.1:45389/companyslug-2"},"id":15}
<<< {"method":"Network.requestWillBeSent","params":{"requestId":"193AC8117FB0EA3616AF24A7BDB479D3","loaderId":"193AC8117FB0EA3616AF24A7BDB479D3","documentURL":"http://127.0.0.1:45389/companyslug-2","request":{"url":"http://127.0.0.1:45389/companyslug-2","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36"},"mixedContentType":"none","initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"timestamp":4239057.925907,"wallTime":1552574369.111231,"initiator":{"type":"other"},"type":"Document","frameId":"4DB9991144C865BC1A76C00D74208FF9","hasUserGesture":false}}
<<< {"method":"Network.requestWillBeSent","params":{"requestId":"193AC8117FB0EA3616AF24A7BDB479D3","loaderId":"193AC8117FB0EA3616AF24A7BDB479D3","documentURL":"http://127.0.0.1:45389/wayne-enterprises-2","request":{"url":"http://127.0.0.1:45389/wayne-enterprises-2","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36"},"mixedContentType":"none","initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"timestamp":4239058.184127,"wallTime":1552574369.369451,"initiator":{"type":"other"},"redirectResponse":{"url":"http://127.0.0.1:45389/companyslug-2","status":301,"statusText":"Moved Permanently","headers":{"X-Frame-Options":"SAMEORIGIN","X-Xss-Protection":"1; mode=block","X-Content-Type-Options":"nosniff","Location":"http://127.0.0.1:45389/wayne-enterprises-2","Content-Type":"text/html; charset=utf-8","Cache-Control":"no-cache","X-Request-Id":"a74f0c18-da7f-4e2a-9606-9f36339af481","X-Runtime":"0.245659","Server":"WEBrick/1.4.2 (Ruby/2.5.3/2018-10-18)","Date":"Thu, 14 Mar 2019 14:39:29 GMT","Content-Length":"117","Connection":"Keep-Alive","Set-Cookie":"locale=de; path=/; expires=Sun, 14 Apr 2019 13:39:29 -0000"},"headersText":"HTTP/1.1 301 Moved Permanently\r\nX-Frame-Options: SAMEORIGIN\r\nX-Xss-Protection: 1; mode=block\r\nX-Content-Type-Options: nosniff\r\nLocation: http://127.0.0.1:45389/wayne-enterprises-2\r\nContent-Type: text/html; charset=utf-8\r\nCache-Control: no-cache\r\nX-Request-Id: a74f0c18-da7f-4e2a-9606-9f36339af481\r\nX-Runtime: 0.245659\r\nServer: WEBrick/1.4.2 (Ruby/2.5.3/2018-10-18)\r\nDate: Thu, 14 Mar 2019 14:39:29 GMT\r\nContent-Length: 117\r\nConnection: Keep-Alive\r\nSet-Cookie: locale=de; path=/; expires=Sun, 14 Apr 2019 13:39:29 -0000\r\n\r\n","mimeType":"text/html","requestHeaders":{"Host":"127.0.0.1:45389","Connection":"keep-alive","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","Accept-Encoding":"gzip, deflate, br","Cookie":"tracking=%7B%22full%22%3Atrue%2C%22version%22%3A%222018-05-25%22%7D"},"requestHeadersText":"GET /companyslug-2 HTTP/1.1\r\nHost: 127.0.0.1:45389\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.75 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nCookie: tracking=%7B%22full%22%3Atrue%2C%22version%22%3A%222018-05-25%22%7D\r\n","connectionReused":false,"connectionId":12,"remoteIPAddress":"127.0.0.1","remotePort":45389,"fromDiskCache":false,"fromServiceWorker":false,"encodedDataLength":536,"timing":{"requestTime":4239057.927005,"proxyStart":-1,"proxyEnd":-1,"dnsStart":0.658,"dnsEnd":0.728,"connectStart":0.728,"connectEnd":0.989,"sslStart":-1,"sslEnd":-1,"workerStart":-1,"workerReady":-1,"sendStart":1.106,"sendEnd":1.162,"pushStart":0,"pushEnd":0,"receiveHeadersEnd":255.864},"protocol":"http/1.1","securityState":"neutral"},"type":"Document","frameId":"4DB9991144C865BC1A76C00D74208FF9","hasUserGesture":false}}
>>> {"method":"Runtime.callFunctionOn","params":{"functionDeclaration":"function() { return window.location.href }","arguments":[],"executionContextId":1},"id":16}
>>> {"method":"Target.detachFromTarget","params":{"sessionId":"10A96BAE9B51A6B48F861DE89CB669A2"},"id":8}
F
Failures:
Got 0 failures and 3 other errors:
1.1) Failure/Error: page.visit "/companyslug-#{company.id}"
Capybara::Cuprite::DeadBrowser:
Chrome is dead
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/client.rb:41:in `wait'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/page.rb:196:in `command'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/page.rb:77:in `visit'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/driver.rb:31:in `visit'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara/session.rb:274:in `visit'
# ./spec/features/company/vcard_spec.rb:35:in `block (2 levels) in <top (required)>'
1.2) Failure/Error: raise DeadBrowser unless message
Capybara::Cuprite::DeadBrowser:
Chrome is dead
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/client.rb:41:in `wait'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/page.rb:196:in `command'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/runtime.rb:81:in `call'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/runtime.rb:32:in `evaluate'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/frame.rb:19:in `frame_url'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/driver.rb:43:in `frame_url'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/driver.rb:36:in `current_url'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara/session.rb:217:in `current_url'
# /bundle/2.5.3/gems/capybara-screenshot-1.0.14/lib/capybara-screenshot/rspec.rb:55:in `block in after_failed_example'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara.rb:351:in `using_session'
# /bundle/2.5.3/gems/capybara-screenshot-1.0.14/lib/capybara-screenshot/rspec.rb:54:in `after_failed_example'
# /bundle/2.5.3/gems/capybara-screenshot-1.0.14/lib/capybara-screenshot/rspec.rb:84:in `block (2 levels) in <top (required)>'
1.3) Failure/Error: @sock.write(data)
Errno::EPIPE:
Broken pipe
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/web_socket.rb:61:in `write'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/web_socket.rb:61:in `write'
# /bundle/2.5.3/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi.rb:228:in `send_frame'
# /bundle/2.5.3/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi.rb:191:in `frame'
# /bundle/2.5.3/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi.rb:154:in `close'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/web_socket.rb:65:in `close'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/client.rb:56:in `close'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:214:in `quit'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:209:in `restart'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:236:in `rescue in command'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:232:in `command'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/page.rb:89:in `close'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/targets.rb:80:in `reset'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser.rb:205:in `reset'
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/driver.rb:131:in `reset!'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara/session.rb:127:in `reset!'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara.rb:314:in `block in reset_sessions!'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara.rb:314:in `reverse_each'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara.rb:314:in `reset_sessions!'
# /bundle/2.5.3/gems/capybara-2.18.0/lib/capybara/rspec.rb:22:in `block (2 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# Capybara::Cuprite::DeadBrowser:
# Chrome is dead
# /bundle/2.5.3/gems/cuprite-0.5.0/lib/capybara/cuprite/browser/client.rb:41:in `wait'
Finished in 7.19 seconds (files took 7.42 seconds to load)
1 example, 1 failure`
@vermaxik that's pretty weird I see no events at all after {"method":"Page.navigate","params":{"url":"http://127.0.0.1:45389/companyslug-2"},"id":15}
there must be plenty of them about rendering, network stuff and so on, but it's empty. Do you have frame_url
in your test? Could you please show the test itself?
No frame_url
, and it's really wierd, because yesterday everything works and today with a new version on Chrome everyspecs go down.
Cuprite configration:
Capybara.register_driver :cuprite do |app|
disable_css_transitions = Rails.root.join('spec', 'support', 'features', 'disable_css_transitions.js')
Capybara::Cuprite::Driver.new(
app,
js_errors: false,
window_size: [1200, 900],
browser_options: { 'no-sandbox': nil },
process_timeout: 6,
extensions: [disable_css_transitions]
)
Spec example:
describe 'a vcard is shown' do
before do
page.visit "/companyslug-#{company.id}"
end
it 'company data is set', js: true do
within('.body header') do
expect(page).to have_content 'Wayne Enterprises'
expect(page).to have_content 'Awesome Street 42, US-12345 Gotham City'
expect(page).to have_link 'Telephone number'
expect(page).to have_link 'moc.sesirpretne-enyaw@enyaw_ecurb'
expect(page).to have_link 'Web Site', href: company.homepage
expect(page).to have_link 'Company contact'
expect(page).to have_selector "img[src*='#{company.logo['144x108']}']"
expect(page).to have_selector "a[href='#contact-inquiry-form-modal']"
expect(page).not_to have_link('001555123456')
end
within('.contact-details') do
expect(page).to have_selector "a[href='#contact-inquiry-form-modal']"
end
link = find('a.visible-xs', visible: false)
expect(link[:href]).to end_with('#contact-inquiry-form-modal')
find(".body header a[data-toggle='popover']").trigger('click')
within('.popover') do
expect(page).to have_link('001555123456')
end
end
end
end
Just tried an unstable version of chrome: Google Chrome 74.0.3729.6 dev
and all specs works again without any changes
@vermaxik Unfortunately I cannot reproduce it on my machine, if you could write an isolated spec I could try to hunt this down. But all looks like the version 73 is buggy indeed
@route thanks a lot for helping. We are webmock in this app and I'm assuming this is an issue with Chrom 73. I tried Chrome 73 build in another app without webmock and it works. I'll let know if find a solution to make it workable with webmock.
Got it thanks!
I had the same issue with Google Chrome 73.0.3683.86. Thanks for the issue report - this saved my time understanding what the cause was.
Hallo,
With a new version of Google Chrome, I have the same issue as here https://github.com/machinio/cuprite/issues/48
Environment:
` Got 0 failures and 3 other errors: