Capybara::Poltergeist::ObsoleteNode 当 angular 更新使用 ng-repeat 呈现的 table 行
Capybara::Poltergeist::ObsoleteNode when angular updates a table row rendered with ng-repeat
我正在测试 angular 水豚、黄瓜和闹鬼的实时更新。
我有以下失败的步骤定义:
Then(/^I should see the following inventory:$/) do |table|
rows = find(".inventory table").all('tr')
page_table = rows.map { |r| r.all('th,td').map { |c| c.text.strip } }
table.dup.diff!(page_table)
end
错误:
The element you are trying to interact with is either not part of the
DOM, or is not currently visible on the page (perhaps display: none is
set). It's possible the element has been replaced by another element
and you meant to interact with the new element. If so you need to do a
new 'find' in order to get a reference to the new element.
(Capybara::Poltergeist::ObsoleteNode)
但是,如果我用预期块(重试)包装断言(实际上只是 #find),则测试通过。
w/预期块:
Then(/^I should see the following inventory:$/) do |table|
sleeping(0.1).seconds.between_tries.failing_after(20).tries do
rows = find(".inventory table").all('tr')
page_table = rows.map { |r| r.all('th,td').map { |c| c.text.strip } }
table.dup.diff!(page_table)
end
end
我讨厌这个解决方案,因为 cucumber/capybara 应该 已经有一个重试机制。因此,如果重试超时为 5 秒,那么您实际上可能会重试 5 秒 * 20 次重试 + 额外的 2 秒。现在,我可以在查找操作上添加 wait: 0
,但这些解决方案看起来都像是 hack。
我正在使用 poltergeist 1.9.8,但已尝试升级到 2.1,但仍然没有成功。有解决办法吗?
Capybaras 重试机制内置于它的匹配器中,您在此测试中没有使用它。您还使用了 #all
,它的缺点是元素 returns 不能自动重新加载,因此仅当元素不会更改或已经更改时才需要使用。 #all
也有效地具有您使用它的方式的 0 等待时间,因为空元素数组(无匹配项)是有效响应,因此没有等待行为。如果在测试中可见行数发生变化,那么您可以使用 count
选项强制 #all
等待并实现类似
Then(/^I should see the following inventory:$/) do |table|
rows = find(".inventory table").all('tr', count: table.raw.size)
page_table = rows.map { |r| r.all('th,td').map { |c| c.text.strip } }
table.dup.diff!(page_table)
end
这将使 #all
等待页面上出现预期的行数,这应该意味着行已完成更改并调用 all('th,td')
查找文本变得安全。
如果行数不会改变(只有行数),一个选项是将所有内容连接在一起并检查 table 的文本 - 它不会是 100 % 正在测试 table 完全匹配,但在您控制数据的测试环境中它可能已经足够好了。这是未经测试的,但按照以下内容应该可以做到这一点
Then(/^I should see the following inventory:$/) do |table|
expect(find(".inventory table")).to have_content(table.raw.flatten.join)
end
另一种尝试方法是利用 Capybara::Node::synchronize 重试 - 类似于
Then(/^I should see the following inventory:$/) do |table|
inv_table = find(".inventory table")
inv_table.synchronize do
page_table = inv_table.all('tr').map { |r| r.all('th,td').map { |c| c.text.strip } }
table.dup.diff!(page_table)
end
end
#synchronize
应该允许 Capybara 最多重试块 Capybara.default_max_wait_time 直到它通过——默认情况下它只会重试 driver.invalid_elements
和 Capybara::ElementNotFound - 如果您还希望它重试 diff 返回的错误! (最多 max_wait_time 秒)你必须传递选项才能像 inv_table.synchronize max_wait_time, errors: page.driver.invalid_element_errors + [Capybara::ElementNotFound, WhateverErrorDiffRaisesOnFailure] do ...
一样同步
我正在测试 angular 水豚、黄瓜和闹鬼的实时更新。
我有以下失败的步骤定义:
Then(/^I should see the following inventory:$/) do |table|
rows = find(".inventory table").all('tr')
page_table = rows.map { |r| r.all('th,td').map { |c| c.text.strip } }
table.dup.diff!(page_table)
end
错误:
The element you are trying to interact with is either not part of the DOM, or is not currently visible on the page (perhaps display: none is set). It's possible the element has been replaced by another element and you meant to interact with the new element. If so you need to do a new 'find' in order to get a reference to the new element. (Capybara::Poltergeist::ObsoleteNode)
但是,如果我用预期块(重试)包装断言(实际上只是 #find),则测试通过。
w/预期块:
Then(/^I should see the following inventory:$/) do |table|
sleeping(0.1).seconds.between_tries.failing_after(20).tries do
rows = find(".inventory table").all('tr')
page_table = rows.map { |r| r.all('th,td').map { |c| c.text.strip } }
table.dup.diff!(page_table)
end
end
我讨厌这个解决方案,因为 cucumber/capybara 应该 已经有一个重试机制。因此,如果重试超时为 5 秒,那么您实际上可能会重试 5 秒 * 20 次重试 + 额外的 2 秒。现在,我可以在查找操作上添加 wait: 0
,但这些解决方案看起来都像是 hack。
我正在使用 poltergeist 1.9.8,但已尝试升级到 2.1,但仍然没有成功。有解决办法吗?
Capybaras 重试机制内置于它的匹配器中,您在此测试中没有使用它。您还使用了 #all
,它的缺点是元素 returns 不能自动重新加载,因此仅当元素不会更改或已经更改时才需要使用。 #all
也有效地具有您使用它的方式的 0 等待时间,因为空元素数组(无匹配项)是有效响应,因此没有等待行为。如果在测试中可见行数发生变化,那么您可以使用 count
选项强制 #all
等待并实现类似
Then(/^I should see the following inventory:$/) do |table|
rows = find(".inventory table").all('tr', count: table.raw.size)
page_table = rows.map { |r| r.all('th,td').map { |c| c.text.strip } }
table.dup.diff!(page_table)
end
这将使 #all
等待页面上出现预期的行数,这应该意味着行已完成更改并调用 all('th,td')
查找文本变得安全。
如果行数不会改变(只有行数),一个选项是将所有内容连接在一起并检查 table 的文本 - 它不会是 100 % 正在测试 table 完全匹配,但在您控制数据的测试环境中它可能已经足够好了。这是未经测试的,但按照以下内容应该可以做到这一点
Then(/^I should see the following inventory:$/) do |table|
expect(find(".inventory table")).to have_content(table.raw.flatten.join)
end
另一种尝试方法是利用 Capybara::Node::synchronize 重试 - 类似于
Then(/^I should see the following inventory:$/) do |table|
inv_table = find(".inventory table")
inv_table.synchronize do
page_table = inv_table.all('tr').map { |r| r.all('th,td').map { |c| c.text.strip } }
table.dup.diff!(page_table)
end
end
#synchronize
应该允许 Capybara 最多重试块 Capybara.default_max_wait_time 直到它通过——默认情况下它只会重试 driver.invalid_elements
和 Capybara::ElementNotFound - 如果您还希望它重试 diff 返回的错误! (最多 max_wait_time 秒)你必须传递选项才能像 inv_table.synchronize max_wait_time, errors: page.driver.invalid_element_errors + [Capybara::ElementNotFound, WhateverErrorDiffRaisesOnFailure] do ...