
within should support xpath
Reported by Zach Dennis | February 3rd, 2009 @ 10:46 PM | in 0.5
The current #within method supports only css selectors. When trying to use xpath it still tries to use CSS. For example, in scope.rb the scoped_dom method always uses #css_at:
def scoped_dom
Webrat::XML.css_at(@scope.dom, @selector)
end
There are some dom traversal techniques in which xpath is better suited than css (such as traversing down the dom and then back up which css can't do). xpath can usually be spotted by checking if the selector string starts with backslashes and since backslashes aren't used with css selectors AFAIK there shouldn't be any confusion or edge cases.
WDYT?
Comments and changes to this ticket
-
Bryan Helmkamp February 8th, 2009 @ 11:41 PM
- Assigned user set to Bryan Helmkamp
- State changed from new to open
- Milestone set to 0.5
Zach,
I agree it should be supported. At first glance, I'm wondering if we should add within_xpath instead of overloading the within API to take either style. On the whole, I explicit to implicit in the Webrat API, and am trying to move in that direction.
In either form, I'd like to get this into the 0.5 release.
WDYT?
-Bryan
-
Zach Dennis February 9th, 2009 @ 08:33 PM
I agree with you Bryan, being explicit seems like a better route to go. If it becomes a need to have a single consolidated interface it can always be revisited that later.
-
tomtt March 3rd, 2009 @ 06:53 AM
The problem with just adding within_xpath is that methods like click_link_within will still not be able to use xpath. I do not know the codebase very well, but it seems to me that by allowing the selector to be a string (assuming it is a css selector) or an XPath object and passing that selector all the way down, then all that needs to be done is not convert the selector to an XPath object if it already is one. Am I right?
-
tomtt March 3rd, 2009 @ 08:20 AM
Here is a duck punch that solved my immediate need. For a real patch, it should check if selector is an XPath object.
# Webrat does not accept xpath selectors. This is a quick hack to make # it work for me (assumes xpaths start with /, everything else is css) module Webrat class Scope protected def scoped_dom if @selector =~ /^\.?\/\/?/ Webrat::XML.xpath_at(@scope.dom, @selector) else Webrat::XML.css_at(@scope.dom, @selector) end end end end
-
tomtt March 4th, 2009 @ 09:07 AM
Another duckpunch which is slightly more elegant I believe. It tries to call css_at with the selector, if it raises a syntax error the selector is passed to xpath_at. If that fails then the original exception is raised.
My knowledge of css vs xpath selectors is limited so this may be a Very Bad Idea.
# Webrat does not accept xpath selectors. This is a quick hack to make # it work for me (assumes xpaths start with //, everything else is css) module Webrat class Scope protected def xpath_scoped_dom Webrat::XML.xpath_at(@scope.dom, @selector) end def scoped_dom begin Webrat::XML.css_at(@scope.dom, @selector) rescue Nokogiri::CSS::SyntaxError, Nokogiri::XML::XPath::SyntaxError => e begin # That was not a css selector, mayby it's an xpath selector? xpath_scoped_dom rescue # Raise original css syntax error if selector is not xpath either raise e end end end end end
-
tomtt March 16th, 2009 @ 02:22 PM
@linoj: you are right, i had fixed it in my code, but thought it not worth another ticket update. But here you go:
# Webrat does not accept xpath selectors. This is a quick hack to make # it work for me. It tries to call css_at with the selector, if it # raises a syntax error the selector is passed to xpath_at. If that # fails then the original exception is raised. module Webrat class Scope protected def xpath_scoped_dom Webrat::XML.xpath_at(@scope.dom, @selector) end def scoped_dom begin Webrat::XML.css_at(@scope.dom, @selector) rescue Nokogiri::CSS::SyntaxError, Nokogiri::XML::XPath::SyntaxError => e begin # That was not a css selector, mayby it's an xpath selector? xpath_scoped_dom rescue # Raise original css syntax error if selector is not xpath either raise e end end end end end
-
tomtt March 18th, 2009 @ 09:01 PM
I have forked webrat on github and committed this fix for it. It has been working well for me in practice. The only caveat I can think of is if you'd want to use an xpath expression that is also a valid css selector. I can not currently think of one though. If somebody can give me an example of an html fragment and a string that can be both a valid css selector and a valid xpath but that should produce different results then I will find a way to code for that as well.
http://github.com/tomtt/webrat/t... 61d859b2ffcb208d6b92d4d2f00b1a880b7899a8
-
tomtt December 2nd, 2009 @ 08:26 AM
Thanks for that, there is one minor tweak I made: just raising does not halt the exception chain. I have updated my github webrat fork accordingly:
http://github.com/tomtt/webrat/tree/xpath_fix
http://github.com/tomtt/webrat/commit/bbdd1c1cd6cd374afe31255c5fcbb... -
tomtt December 2nd, 2009 @ 08:45 AM
In fact, that was probably not the right thing to do. Sorry, please ignore that commit, you need to reraise the original exception to not break apps that catch it. I have added a spec to check that the correct type of error is raised.
http://github.com/tomtt/webrat/commit/2aeb68899edd7abdc77fedb7c552b...
-
Deleted User January 5th, 2010 @ 07:14 PM
See also
http://objectliteral.blogspot.com/2009/09/clicking-on-links-in-webr...For 0.6.0 I am using
{mkd-extraction-90c8d48709e810f68642dca8ed82a220}
module Webrat
class Scopeend end
-
Deleted User January 5th, 2010 @ 07:15 PM
Sigh. Preview does not work. How about plain text:
module Webrat
class Scopeprotected def xpath_scoped_dom #HaveXpath.new(@selector).matches.first hs = have_xpath(@selector) hs.matches(@scope.dom) #Webrat::XML.xpath_at(@scope.dom, @selector) end def scoped_dom begin @scope.dom.css(@selector).first #Webrat::XML.css_at(@scope.dom, @selector) rescue Nokogiri::CSS::SyntaxError => e#, Nokogiri::XML::XPath::SyntaxError => e begin # That was not a css selector, mayby it's an xpath selector? xpath_scoped_dom rescue Exception => e2 # Raise original css syntax error if selector is not xpath either raise e2 end end end
end end
-
dannyhawkins (at me) January 12th, 2010 @ 11:49 AM
I've just added the following:
def scoped_dom
if @selector =~ /^\.?\/\/?/ @scope.dom.xpath(@selector).first else @scope.dom.css(@selector).first end end
Which seems to work very well. Any reason why this shouldn't be used?
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป
Ruby Acceptance Testing for Web applications.