Проблемы с Selenium WebDriver executeScript (с использованием watir-webdriver в Ruby)
У меня проблемы с выполнением определенного фрагмента кода JavaScript с помощью команды browser.execute_script Watir WebDriver:
Вот этот 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, поэтому я не могу напрямую зонировать объект в документе. Что еще хуже, документ в два кадра. Frameception.
Использование очевидного решения (с использованием API watir-webdriver) неосуществимо, поскольку задача заполнения 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 вопроса состоит в том, чтобы, надеюсь, просто иметь второй взгляд, который может исключить любые очевидные ошибки. У меня есть другой обходной путь, который я планирую использовать.