使用 xpath,找到一个 HTML 具有给定部分 id 的元素(可能是正则表达式)

With xpath, locate an HTML element with a partial id given (possibly regex)

Ruby1.9.3,Rails3.1.10,RSpec2.13.0,水豚 2.2.1

我在使用嵌套表单的应用程序页面上。该表单将成员添加到队列中。如果某个成员已经保存,则该成员的 id(在 HTML 中)为 queue_queue_members_attributes_0_user_id,然后是 1、2 等等。当我通过 JavaScript 单击 link 到 Add New Member 时,新 select 框的 HTML id 类似于:queue_queue_members_attributes_1421760178806_user_id

如您所见,为每个新的 select 框生成一个 运行dom 数字字符串,其中 nested-attribute 尚未保存。我需要知道这个 HTML 元素的 ID,以便有效地测试 Capybara。

我在一个将成员添加到队列的页面上。如果成员已经存在,则其 select 框的 id 为 0、1,依此类推。如果我单击 "Add New Member",新 select 框的 ID 是一个 运行domly 生成的数字,在本例中为 1421760178806。

原始尝试

下面是我为规范制作的辅助方法。它最初有效。然而,最近我需要测试队列成员。当我添加一个队列成员工厂,并使用新的队列工厂实例创建一个时,这个问题就开始了。因为现在我有 2 select 个框匹配 xpath 查询

def select_member(member)
  find(:xpath, "//select[contains(@id, '_user_id')]/option[@value='#{member.id}']").select_option
end

Failure/Error: select_member(@test_user)
Capybara::Ambiguous:
Ambiguous match, found 2 elements matching xpath "//select[contains(@id, '_user_id')]/option[@value='6647']"

根据我的更改,成员在创建时通过 FactoryGirl 添加到队列中。这意味着我的 xpath 表达式匹配两个 select 框——一个 id 为 0,另一个 1421760178806。我只希望它匹配后一个数字(除了一个“0”之外的任何数字)。我的测试只添加一个成员,所以我不担心 ids >0.

第二次尝试

我发现 this SO question 最初很有帮助,直到我 运行 陷入另一个错误。

def select_member(member)
  find(:xpath, "//select[matches(@id, '[0-9]{2,}_user_id')]/option[@value='#{member.id}']").select_option
end

Failure/Error: select_member(@test_user)
Capybara::Webkit::InvalidResponseError:
INVALID_EXPRESSION_ERR: DOM XPath Exception 51

使用更新的 gems 移动到 Rails 4,我能够在发布一个月后解决我的问题。以下内容对 Rails 3 项目仍然有帮助。

经过大量研究和挖掘,我发现我们的应用程序将 xpath 作为默认的 Capybara 选择器。我不确定为什么,但我认为这是因为我们的观点因 forms-in-forms-in-tables 而变得复杂。现在 Twitter Bootstrap 和 Rails 4 的视图很整洁,我决定将默认的 Capybara 选择器更改为默认选项 -- :css。这允许我根据元素的(更清洁的)id、名称或标签 selectfill_in

关于嵌套表单问题,我通过创建规范辅助方法解决了它。在其中,我找到了包含表单元素的 table。使用 xpath,我在该实例中找到了 table 的最后一行。最后一行选择作为 Capybara 中的 within do 块。

# xpath selector - locate last nested row within a given table id
def last_row(id)
  find(:xpath, "//table[@id='#{id}']//tbody/tr[last()]")
end

within last_row("queues") do
  # css selector - select item based on label
  select "Extension User 2", from: "Queue member"
  select "1", from: "Penalty"
end

我确信以上内容可以以某种方式更改为 CSS,但我在测试中对这两个选择器还是陌生的。请随意评论 css 选择器版本。