有没有办法在 Capybara 中通过文本查找任何元素?
Is there a way to find any elements by text in Capybara?
我想在我的页面上找到任何带有给定文本的元素,但是当我将它传递给没有元素的查找时,它返回一个错误
find(material.attachment_filename) #material.attachment_filename is "01. pain killer.mp3"
但如果我这样做:
find('a',text: material.attachment_filename)
运行正常,报错为:
Selenium::WebDriver::Error::InvalidSelectorError:
Given css selector expression "01. pain killer.mp3" is invalid: SyntaxError: An invalid or illegal string was specified
Capybara 的查找需要 3 个参数(一个 Capybara 选择器类型、一个定位器字符串和一个选项散列)。如果未指定选择器类型,则默认为 :css ,这意味着定位器字符串需要是 CSS 选择器。
这意味着 find(material.attachment_filename)
在您的情况下等同于
find(:css, "01. pain killer.mp3")
如您所见,这将引发错误,因为“01. pain killer.mp3”无效 CSS。如果你想找到任何包含文本的元素,你可以做类似
find('*', text: "01. pain killer.mp3")
它会找到任何包含文本的元素,但是它也会找到所有祖先元素,因为它们也包含文本,所以您可能想要的是使用正则表达式来确保元素包含只有那个内容
find('*', /\A#{Regexp.escape(material.attachment_filename)}\z/)
应该解释为
find('*', /\A01\. pain killer\.mp3\z/)
注意:如果您的页面上的内容不仅仅是简单的内容,那将会非常慢,因为这意味着将所有元素从 selenium 转移到 capybara 以检查文本内容。
一个更高效的解决方案是使用 XPath,它支持按文本内容查找元素(CSS 不支持)
find(:xpath, XPath.descendant[XPath.string.n.is(material.attachment_filename)]) #using the XPath library - contains (assuming Capybara.exact == false)
find(:xpath, XPath.descendant[XPath.string.n.is(material.attachment_filename)], exact: true) #using the XPath library - equals (you could also pass exact:false to force contains)
如果文本不包含需要转义的 XPath 特殊字符(例如撇号),您可以使用字符串来定义 XPath:
find(:xpath, ".//*[contains(., '#{material.attachment_filename}')]") #contains the text
find(:xpath, ".//*[text()='#{material.attachment_filename}']") #equals the text
如果该元素实际上是您正在寻找的 link,那么您可能想要使用
find_link("01. pain killer.mp3")
或
find(:link, "01. pain killer.mp3")
我想在我的页面上找到任何带有给定文本的元素,但是当我将它传递给没有元素的查找时,它返回一个错误
find(material.attachment_filename) #material.attachment_filename is "01. pain killer.mp3"
但如果我这样做:
find('a',text: material.attachment_filename)
运行正常,报错为:
Selenium::WebDriver::Error::InvalidSelectorError:
Given css selector expression "01. pain killer.mp3" is invalid: SyntaxError: An invalid or illegal string was specified
Capybara 的查找需要 3 个参数(一个 Capybara 选择器类型、一个定位器字符串和一个选项散列)。如果未指定选择器类型,则默认为 :css ,这意味着定位器字符串需要是 CSS 选择器。
这意味着 find(material.attachment_filename)
在您的情况下等同于
find(:css, "01. pain killer.mp3")
如您所见,这将引发错误,因为“01. pain killer.mp3”无效 CSS。如果你想找到任何包含文本的元素,你可以做类似
find('*', text: "01. pain killer.mp3")
它会找到任何包含文本的元素,但是它也会找到所有祖先元素,因为它们也包含文本,所以您可能想要的是使用正则表达式来确保元素包含只有那个内容
find('*', /\A#{Regexp.escape(material.attachment_filename)}\z/)
应该解释为
find('*', /\A01\. pain killer\.mp3\z/)
注意:如果您的页面上的内容不仅仅是简单的内容,那将会非常慢,因为这意味着将所有元素从 selenium 转移到 capybara 以检查文本内容。
一个更高效的解决方案是使用 XPath,它支持按文本内容查找元素(CSS 不支持)
find(:xpath, XPath.descendant[XPath.string.n.is(material.attachment_filename)]) #using the XPath library - contains (assuming Capybara.exact == false)
find(:xpath, XPath.descendant[XPath.string.n.is(material.attachment_filename)], exact: true) #using the XPath library - equals (you could also pass exact:false to force contains)
如果文本不包含需要转义的 XPath 特殊字符(例如撇号),您可以使用字符串来定义 XPath:
find(:xpath, ".//*[contains(., '#{material.attachment_filename}')]") #contains the text
find(:xpath, ".//*[text()='#{material.attachment_filename}']") #equals the text
如果该元素实际上是您正在寻找的 link,那么您可能想要使用
find_link("01. pain killer.mp3")
或
find(:link, "01. pain killer.mp3")