我在使用 Watir WebDriver 的 browser.execute_script 命令执行特定的 javascript 片段时遇到问题:
这是有问题的Javascript:
var bodyFrame = document.getElementsByName("BodyFrame")[0];
var bodyFrameDoc = bodyFrame.contentDocument || bodyFrame.contentWindow.document;
var mainFrame = bodyFrameDoc.getElementById("MainFrame");
var mainFrameDoc = mainFrame.contentDocument || mainFrame.contentWindow.document;
var row = mainFrameDoc.getElementById("DETAIL_1");
var rowNodes = row.childNodes;
var index;
for (index = 0; index < rowNodes.length; index++) {
if (rowNodes[index].firstChild.id === 'ID1') {
rowNodes[index].firstChild.value = 'ACCRUL';
}
if (rowNodes[index].firstChild.id === 'ID2') {
rowNodes[index].firstChild.value = 'OP';
}
if (rowNodes[index].firstChild.id === 'ID3') {
rowNodes[index].firstChild.value = 'Z';
}
if (rowNodes[index].firstChild.id === 'ID4') {
rowNodes[index].firstChild.value = 'FIRST';
}
if (rowNodes[index].firstChild.id === 'ID5') {
rowNodes[index].firstChild.value = 'AUT';
}
if (rowNodes[index].firstChild.id === 'ID6') {
rowNodes[index].firstChild.value = 'AU1000';
}
if (rowNodes[index].firstChild.id === 'ID7') {
rowNodes[index].firstChild.value = 'm tax m entity m jc';
}
if (rowNodes[index].firstChild.id === 'ID8') {
rowNodes[index].firstChild.value = 'MR5001100';
}
if (rowNodes[index].firstChild.id === 'ID9') {
rowNodes[index].firstChild.value = 'T';
}
if (rowNodes[index].firstChild.id === 'ID10') {
rowNodes[index].firstChild.value = '453.36';
}
}
为什么我必须使用这样的暴行?好吧,因为我正在为其开发测试的产品太糟糕了。每个单元格都使用相同的 id 属性,因此我不能直接在文档中的对象上进行分区。更糟糕的是,该文档有两帧深。帧接收。
使用明显的解决方案(使用 watir-webdriver 的 API)是不可行的,因为填充 32 个网格行的任务需要一半!一个小时。
我可以让上面的 Javascript 在浏览器的开发者工具中运行。(该产品支持的浏览器只有 IE8、9,兼容模式。)我无法访问 jQuery 或任何花哨的 javascript 库。使用这个 javascript 几乎可以立即填充行。
当我使用 browser.execute_script 命令运行它时,我得到一个
Selenium::WebDriver::Error::JavascriptError: JavaScript error
奇怪的是,如果我只是使用
return document.getElementsByName("BodyFrame")[0];
然后我收到 Net::HTTP 库的错误,Selenium 在堆栈中的某处使用该库来来回发送命令到浏览器。(更具体地说:ERRNO::ERRCONNREFUSED)
帮助?
编辑:这是我用来执行代码(并生成少量 Javascript)的直接脚本:
def quick_fill(data = {})
reference_element.focus;
quick_filler = ->(element_id, value) {
"if (rowNodes[index].firstChild.id === '#{element_id}') {
rowNodes[index].firstChild.value = '#{value}';
}"
}
row_id = row.attribute(:id)
element_ids = Hash[data.keys.map { |key| [key, send("#{key}_element").attribute(:id)] }]
javascript = <<-JAVASCRIPT
var bodyFrame = document.getElementsByName("BodyFrame")[0];
var bodyFrameDoc = bodyFrame.contentDocument || bodyFrame.contentWindow.document;
var mainFrame = bodyFrameDoc.getElementById("MainFrame");
var mainFrameDoc = mainFrame.contentDocument || mainFrame.contentWindow.document;
var row = mainFrameDoc.getElementById("DETAIL_1");
var rowNodes = row.childNodes;
var index;
for (index = 0; index < rowNodes.length; index += 1) {
#{element_ids.map { |method, element_id| quick_filler.call(element_id, data[method]) }.join("\n") }
}
JAVASCRIPT
puts javascript
sleep(0.500)
browser.execute_script(javascript)
end
此方法的数据参数是键值对的哈希,其中键是提供给页面对象访问器的方法的名称,值是我尝试填写的值。作为中间过程的一部分,我从页面对象元素(作为每个元素的标识符提供)中获取 id 元素。
页面类的设置方式有一些特殊的结构:这是基本思想:
class MyPage
include PageObject
table(:some_table, ...)
def add_line_item(data = {})
GridRow.new(some_table_element.last_row, browser).quick_fill(data)
end
class GridRow
include PageObject
#page object accessors
text_field(:my_field) { row.text_field_element(id: 'ID1') }
#etc
def quick_fill(data = {})
#see above
end
def initialize(row, browser, visit = false)
@row = row
super(browser, visit)
end
end
end
所以示例调用将是(来自黄瓜测试)
on_page(MyPage) do |page|
page.add_line_item(:my_detail => 'myValue')
end
除此之外,还有一个不幸的问题是需要多次调用“attach_window”才能到达该页面(由于页面位于某种模式对话框中)。这个问题可能很大程度上与这种交互有关。这是我能想到的唯一会导致问题的事情。
这个 SO 问题的重点是希望有第二双眼睛可以排除任何明显的错误。我计划采用另一种解决方法。