How do I find an image on a page with Cucumber / Capybara in Rails 3
Asked Answered
T

8

24

I am using Cucumber / Capybara with Rails 3 and am trying to validate the existence of an image after upload. I'm not sure how to check the url of the image to validate it.

I have the following scenario:

Scenario: Create new listing
    Given I am on the new listing page
    When I fill in "listing_name" with "Amy Johnson Photography"
    And I attach the file "features/support/test_image.jpg" to "listing_images_attributes_0_photo" 

    And I press "Create"
    Then I should see "Amy Johnson Photography"
    And I should see the image "test_image.jpg"

Everything passes except the last step.

I've tried this for my step definition, which works great if it's text on the page, but doesn't for an image url:

Then /^I should see the image "(.+)"$/ do |image|
  if page.respond_to? :should
      page.should have_content(image)
    else
      assert page.has_content?(image)
    end
end

Then I've also tried something like this step definition instead:

Then /^I should see the image "(.+)"$/ do |image|
    html = Nokogiri::HTML(response.body)
    tags = html.xpath('//img[@src="/public/images/foo.png"]')
    # tags.length.should eql(num_of_images)
end

which causes the following error:

And I should see the image "test_image.jpg"                                                    # features/step_definitions/listing_steps.rb:41
      undefined method `body' for nil:NilClass (NoMethodError)
      ./features/step_definitions/listing_steps.rb:42:in `/^I should see the image "(.+)"$/'
      features/manage_listings.feature:24:in `And I should see the image "test_image.jpg"'

I'm assuming you need a nokogiri step to find this properly. Or if there's a better way, I'm open to suggestions. How can I validate that the image I just uploaded is on the page? Thanks.

Toft answered 27/1, 2011 at 4:2 Comment(3)
In your step definition you are getting a common capybara error. Try using 'page.body' instead of 'response.body' if I remember correctly.Dunk
I don't know if you can use a regex in xpath, but if you have access to your Listing instance, you could just use a string interpolation "//img[@src='/public/images/#{@listing_id}/foo.png']"Autum
This page contains a good CSS3 selector reference which will help you: reference.sitepoint.com/css/css3attributeselectorsAmylene
H
39

The solution with Nokogiri should work fine. The only problem is that the Cabybara API is different to Webrat, so instead of response.body, you must use page.body.

But theres an even better way to test for the image with Cabybara :

Then /^I should see the image "(.+)"$/ do |image|
    page.should have_xpath("//img[@src=\"/public/images/#{image}\"]")
end
Hathorn answered 27/1, 2011 at 4:12 Comment(6)
Thanks. That works great. One more thing. My folder names are variable based on the listing_id. How can I use a regex here that searches by only the image name (not the whole url)?Toft
XPath supports wildcards, so off the top of my head, I imagine you could write something like this: page.should have_xpath("//img[@src=\"/*/*/#{image}\"]")Hathorn
I can't seem to figure how to get this to work with URLs generated by Dragonfly. They look like this: /media/BAh_some_long_string_AwIw/12_11_52_810_5x5.jpg?s=7e360000, where 5x5.jpg is my file name. I've tried something like: //img[@src="/media/*/*#{image}?s=*"] but it doesn't work. Got any tips?Mcginley
@Ramon, in case you haven't found a solution yet, here it is: #5331731Delila
I haven't been able to get the regex working in an image source. If anyone knows a way please add it here. Cheers.Flitter
page.should have_xpath("//img[contains(@src,'#{image}')]") worked for me in order to only match part of the IMG url.Snot
A
13

Hi I'm not good with XPATH but with CSS you can try :

  if page.respond_to? :should
    page.should have_selector("img[src$='#{imagename}']")
  else
    assert page.has_selector?("img[src$='#{imagename}']")
  end

wish helps ! jramby

Amieeamiel answered 11/5, 2011 at 7:16 Comment(1)
This works too: page.should have_css("img[src$='#{imagename}']")Amylene
B
6

You can test it in this way, and also not depending on the path:

Then /^I should see the image "(.+)"$/ do |image|
    page.should have_xpath("//img[contains(@src, \"#{image}\")]")
end
Bascule answered 22/3, 2013 at 3:29 Comment(1)
This is what is used for images that are saved in dynamic paths such as Paperclip attachments.Grasso
M
6

page.should

is now deprecated. Use instead

expect(page).to

Full example :

Then /^I should see the image "(.+)"$/ do |image|
    expect(page).to have_xpath("//img[contains(@src, \"#{image}\")]")
end
Marlonmarlow answered 15/11, 2014 at 15:34 Comment(0)
A
3

Does this work?

page.should have_xpath('//img[@src="/public/images/foo.png"]')
Autum answered 27/1, 2011 at 4:16 Comment(1)
Thanks. That works great. One more thing. My folder names are variable based on the listing_id. How can I use a regex here that searches by only the image name (not the whole url)?Toft
C
0

If you have a lot of images that you would like to test you could create a has_image? matcher for Capybara.

It is easy and this post explains it step-by-step: Adding a has_image? Matcher to Capybara

Conglomeration answered 19/11, 2012 at 17:0 Comment(0)
M
-1

Yes, but these xpath tests won't deal with the fact that...

/public/images/foo.jpg
public/images/foo.jpg
http://mydomain.com/public/images/foo.jpg

...are all the same valid link to the image.

Melaniamelanic answered 28/9, 2011 at 10:6 Comment(0)
N
-1

this syntax worked for me and is more readable.

page.should have_css("img", :src => "/public/images/foo.png")

Numerate answered 30/4, 2014 at 1:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.