Closed jonleighton closed 11 years ago
+1 for not being able to query <title>
after upgrading to 2.0.
find("title").should have_content("some text")
now fails.
+1 for troubles with <title>
in 2.0
it { should have_selector('title', text: 'Some Title') }
will fail on <head><title>Some Title</title></head>
Wouldn't you guys rather have an explicit API for testing the page title, rather than changing the behaviour of #text just for this? That seems much more sensible to me.
OK with me...just point me to it.
There isn't one, because no one has bothered to build one.
Wish I could help...but I've never worked on a gem and would only cause more problems...
Maybe there should be a way to get content of every tag, even if it is not visible.
I think the problem is that the railstutorial makes heavily use of this feature (check the title) and people tend to copy these examples.
Yup, that's my problem. I learned TDD & RSpec from railstutorial.org and as such most of my projects carry with them some basic structure gleaned from there. After upgrading projects to 2.0 my title specs are failing everywhere.
FWIW, it's a little confusing to a relative newb like me when this is happening:
it { should have_selector('title', text: 'Some Title') } # <= fails
it { should have_selector('title') } # <= passes
it { should have_text('Some Title') } # <= passes
…and according to http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers#has_selector%3F-instance_method we should be able to find elements containing text:
. Now maybe those docs are for 1.x…but that's not clear either...to me anyway.
If there's an alternative way to easily test the title in a feature spec let me know and I'll go away…leaving you all to continue your great work!
+1 for not being able to query
Adding a #has_title?
matcher sounds like a decent solution to me. I'll tweet about in and see if I can get someone to step up to do the work.
IMO the behavior of 2.0 is completely broken. In 1.1.4 page.find("title").text
returns the text, in 2.0 it returns an empty string. Returning an empty string is just wrong when the element does contain text.
My original reason for wanting the has_text
matcher (#522) was to be able to test specifically for 'text visible to the user'.
The title tag is visible text, it's shown in the browser chrome.
Given that, I think it would be ideal if the title text was included.
@gucki: the title tag is an element and it is decidedly not visible by default. Try adding this CSS selector to a page:
head, title { display: block }
Boom, there is the title element and it is quite distinct from the title shown in the browser chrome. This element is not visible, and if we follow the logic that the text of invisible elements is not shown, then it makes sense that the title element has no text. I agree that that's a matter of debate and discussion, but I wouldn't go so far as to say that the current behaviour is broken. It's just a different interpretation.
I think the solution to this problem is two-fold:
#text
or a separate method.@jnicklas Well, it is visible :)
I do think it makes more semantic sense for has_text
to include text from the title element. Since the whole idea behind has_text
is to move away from the logical model of XML's notion of text and towards the notion of human readable text.
I think your suggested solution for #1 and #2 are a good idea, regardless.
@jnicklas As you say, the elemenI itself is not visible - not only its content. So think it'd be more intuitive if page.find(element)
would return nil
if the element is not visible. But when page.find(element)
returns an element, it should properly return its attributes and content as they are - no matter if it's visible or not.
It seems a bit unintuitive to me too that page.find("title").text shouldn't work, but if it's architecturally messy to make it work, then we may have to do without it. Jonas is the judge. :)
+1 for this problem, and also:
<html>
<head>
<title>Title Text</title>
</head>
<body>
<h1>Some heading</h1>
<p>Some paragraph</p>
</body>
</html>
page.has_xpath? "//title"
# => true
page.has_xpath? "//title", text: "Title Text"
# => false
page.should have_xpath "//title"
#=> true
page.should have_xpath "//title", text: "Title Text"
#=> Capybara::ExpectationNotMet Exception: expected to find xpath "//title" with text "Title Text." but there were no matches. Also found "", which matched the selector but not all filters.
Which indicates the title tag is found, but the text inside it remains invisible.
Although a page.title
would be a nice shorthand to have, it will only provide support for that one tag. How about meta tags, canonical links, etc.? In my humble opinion, #find
etc. can return nothing when content is invisible, but xpaths should return visible and invisible content, so it can be used as a more "advanced" fallback for niche situations..
I'd be happy to help code it, once there is agreed on what to do with this btw!
Thanks.
Would be great to have a method that retrieves the text of an element independent of it's visibility. That method could also be used to retrieve the page title. So in my opinion no need for an extra page-title-method but wouldn't hurt of course.
If you keep the behaviour as earlier I would having #text returning always the text and e.g. #visible_text returning only text that is visible.
Best regards Tobias
+1 can't query title text, but the following works ok:
<head><title>marflar</title></head>
should have_xpath("//title[contains(.,'marflar')]")
Is there anything wrong with just doing that?
The content of the title tag is definatively visible, so it should also be possible to check it.
completely agree, the page title is the first thing checked in requests specs.
I also ran into this roadblock today and stumbled upon this solution; http://stackoverflow.com/a/13755730
Seems to work out pretty well for me, so lots of kudos to the creator (not me)!
I'm copy/pasting the solution because I want to save you guys a click.
I had the same issues when I upgraded to Capybara 2.0, and managed to solve them by creating the following custom RSpec matcher using Capybara.string:
spec/support/utilities.rb
RSpec::Matchers::define :have_title do |text|
match do |page|
Capybara.string(page.body).has_selector?('title', text: text)
end
end
Now, in a spec file where subject { page }, I can use:
it { should have_title("My Title") }
it { should_not have_title("My Title") }
+1 for not being able to query <title>
after upgrading to 2.0.
Thanks @john-patrik. That's a great find and just what I needed. Something like this could be in Capybara by default as per @jnicklas's 2nd proposed solution above: https://github.com/jnicklas/capybara/issues/844#issuecomment-11411003
Has there been an official decision or progress made here? Both solutions would work and I feel a solution (even if it proves to be less than perfect) is better than none at all. -I hate not being able to get through a tutorial :)
Closed by #960
I'd like to express my frustration about the breaking of backwards compatibility on the behavior of have_selector('title', text: ...)
. As others on this thread have noted, many people use have_selector
because of its use in the Ruby on Rails Tutorial. As the author that tutorial, it is my job to keep it up to date, and the lack of support for the previous behavior of have_selector
is both frustrating for me and (because the necessary fix adds extra code) increases the complexity for beginning users. It is my hope that future iterations of Capybara will take more care to preserve current (and, in this case, logical) behavior.
@mhartl we've gone out of our way to make this more intuitive for Capybara 2.1. We've added more control over whether to return only visible text or all text and we've added a new api for querying and asserting on the page title.
I'm sorry that behaviour broke this significantly for you, we didn't anticipate that this change would affect users. We had a lengthy beta period for Capybara 2.0, and this issue was not reported during that time. If it had, we could have done something about it sooner.
However, I don't agree that the way you are suggesting to query for the page title is a good idea. Once Capybara 2.1 is released, you should update the tutorial to suggest the use of have_title
, which will be the official API from now on. have_selector("title", text: "something")
might work or it might not, it depends on the driver. Imo, it's a perfectly valid interpretation for the title element not to have any text.
@mhartl it just occured to me that since Capybara 2.1 will default Capybara.ignore_hidden_elements
to true
, and the title element is invisible, it won't be possible to query its content this way, visible text or not.
@jnicklas I actually never liked using have_selector
in this context; in the original Rails 2.3 version of the book I used Webrat's have_tag
, but that disappeared when Webrat was deprecated. Using have_selector
was the closest, if imperfect, substitute. I agree that have_title
is much better, and I'll plan to update the tutorial accordingly. Thanks!
For reference, Capybara now has have_title
in 2.1.0.beta1 as described here:
http://www.elabs.se/blog/60-introducing-capybara-2-1#asserting_against_the_page_title
Awesome. I can confirm that this works with the Rails Tutorial sample app and have updated the beta book accordingly.
I noticed that the selenium-webdriver gem dependency didn't install automatically. Is that intentional? To get it to work, I had to add it explicitly to my Gemfile:
group :test do
gem 'selenium-webdriver', '2.0'
gem 'capybara', '2.1.0.beta1'
end
@mhartl See issue #1018 for the Selenium fix.
This work for me
get :home assert_select "title", "Ruby on Rails Tutorial Sample App | Home"
can see http://stackoverflow.com/questions/3971449/verifying-page-title-with-rspec
the solution @john-patrik posted above worked for me http://stackoverflow.com/questions/13573525/rspec-capybara-2-0-tripping-up-my-have-selector-tests/13755730#13755730
I have one afternoon and half of the morning only with the title problem. Finally I found a solution and I just sign up to write it:
expect(page.title).to eq("My title")
Good luck
Capybara master has a new
has_text?
matcher which excludes invisible content such as<title>
elements anddisplay: none
elements.Its implementation uses the
Node#text
method, so the implication is that the behaviour ofNode#text
has now changed from returning all text to only returning visible text. This presents two problems:Node#text
directly, orhas_content?
(which is now just an alias ofhas_text?
)<title>
element. This could be a valid user requirement and was previously supported by the#text
method.I propose adding a
#visible_text
method and using that to implementhas_text?
, leaving the implementations of#text
and#has_content?
as they are in 1.1. (#has_content?
can be deprecated but I believe#text
remains useful for checking e.g.<title>
text.) WDYT?Related: #522
cc @mkdynamic