I want to find any element with a given text on my page, but when I pass it to find without an element it gives me back an error
find(material.attachment_filename) #material.attachment_filename is "01. pain killer.mp3"
But if i do:
find('a',text: material.attachment_filename)
It works fine, and the given error is:
Selenium::WebDriver::Error::InvalidSelectorError:
Given css selector expression "01. pain killer.mp3" is invalid: SyntaxError: An invalid or illegal string was specified
Capybara's find takes 3 arguments (a Capybara selector type, a locator string, and an options hash). If the selector type isn't specified it defaults to :css which means the locator string needs to be a CSS selector.
This means that find(material.attachment_filename)
in your case is equivalent to
find(:css, "01. pain killer.mp3")
which will raise an error as you've seen because "01. pain killer.mp3" isn't valid CSS. If you want to find any element containing the text you could do something like
find('*', text: "01. pain killer.mp3")
which will find any element containing the text, however that's also going to find all the ancestor elements too since they also contain the text, So what you'd probably want is to use a regex to make sure the element contains only that content
find('*', /\A#{Regexp.escape(material.attachment_filename)}\z/)
which should be interpreted as
find('*', /\A01\. pain killer\.mp3\z/)
Note: That is going to be pretty slow if your page has anything more than simple content on it because it means transferring all the elements from selenium to capybara to check the text content.
A more performant solution would be to use XPath which has support for finding elements by text content (CSS does not)
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)
If the text won't contain XPath special characters (ex. apostrophes) that need escaping, you can use a string to define the XPath:
find(:xpath, ".//*[contains(., '#{material.attachment_filename}')]") #contains the text
find(:xpath, ".//*[text()='#{material.attachment_filename}']") #equals the text
If the element is actually a link you're looking for though then you would probably want to use
find_link("01. pain killer.mp3")
or
find(:link, "01. pain killer.mp3")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With