We have a issue on our e-commerce site where users occasionally hit "checkout" twice and have their card charged twice.
It's a common enough bug and easy to fix, but I'd like to test the solution in our capybara setup. Once I've called click_button('checkout'), is it possible for me to pretend I'm a user hitting the browsers back button and then call click_button('checkout') a second time?
You may want to try:
When(/^I go back$/) do
page.evaluate_script('window.history.back()')
end
This will require running the senario in a javascript capable driver (selenium/celerity/akephalos)
You can use page.driver.go_back, if you are using webkit as your capybara javascript driver via the capybara-webkit gem. Also requires :js => true for the scenario.
At least with capybara 2.10 and selenium-webdriver 2.53 this works:
When(/^I go back$/) do
page.go_back
end
It's basically a shortcut for jbarr's answer. For details more see the capybara documentation on go_back .
BTW: The counter part is page.go_forward.
I've used this method in Webrat. I'm sure something similar for Capybara would work.
When(/^I go back$/) do
visit request.env['HTTP_REFERER']
end
Side note: the "redirect_to :back" method didn't work for me for whatever reason.
Thanks! This question and answer helped me a lot!
Just to add to #Jake Mallory's answer, selenium is now part of capybara and you can fairly easily run javascript in the test by adding :js => true (and possibly a couple more tweaks) as described in these two tutorials:
http://www.opinionatedprogrammer.com/2011/02/capybara-and-selenium-with-rspec-and-rails-3/
http://railscasts.com/episodes/257-request-specs-and-capybara?view=asciicast
Related
I'm trying to test the ability to vote on an event. I've created the event via factory_girl. When the user participated to the event, he should have the ability to vote.
The vote button is visible to capybara as well as visible to me when I manually test for its presence in the browser. When I use click_on "vote", there is no error. Now comes the weird thing. When I manually test the vote button via the browser, I now see the vote form and have a /vote/... path in my browser. When I use click_on "vote" in Capybara and check for the path, the path equals the start page.
I've tried everything I can think of to figure out why Capybara is hitting the wrong path.
My question is, is there a possibility to see some 'advanced' logging or something else? Like why a redirect happened or something else?
You can use byebug to step through your spec. Also, I find chromedriver to be very useful. It runs your tests in chrome environment so you can eyeball your test and confirm that it is doing what it is supposed to.
Byebug:
https://github.com/deivid-rodriguez/byebug
Chrome driver:
http://collectiveidea.com/blog/archives/2011/09/27/use-chrome-with-cucumber-capybara/
I got a strange problem with minitest and capybara.
I am using rails 3.2.8 and test with minitest/capybara/poltergeist. Until now every went fine. I always could test my javascript stuff.
For a new project I downloaded rails 4 to get into it a little bit. And since minitest will be the testing framework I thought it would be easy. It was not. Truth be told, I am not a hero when it comes to setting up all the stuff. I just follow Ryan Bates. After a lot of adding and removing and updating a lot of gems I decided it wasn't worth to continue to use Rails 4. I had so many issues with getting into the groove with my integration tests. All the stuff I knew did not work as expected. The axe fell when almost everything worked until I wanted to test a javascript thing. I got this error:
.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/minitest-4.6.1/lib/minitest/spec.rb:190:in `it': wrong number of arguments (2 for 1) (ArgumentError)
because of this
describe "blabla" do
it "does not do what i want it to do", js: true do
pending
end
end
It will not accept the js: true argument. Funny thing is that the describe block will accept the js: true argument.
When I went back to Rails 3.2.8, because I thought it was a Rails 4 thing, this baby followed me right into a new testsuite. I tried hard to find an answer on Google but I can't find any. My other rails 3.2.8 projects still test fine, no complains about the javascript argument. But with the new apps: no javascript testing.
I am at a loss here. I have no idea where this is coming from. Since my other 3.2.8 apps still work fine, it has probably something to do with renewed gem versions? Has anybody seen this error message? I checked the complaining minitest/spec.rb file from the error message, line 190 for several minitest versions and nothing changed in the it-method.
Please let me know if you want to see stuff (Gemfile? test_helper.rb?) if you have any clue about what might be wrong. Thanks in advance!
Casper
Minitest's spec DSL does not accept a second parameter for the it blocks. The minitest-metadata gem adds support for the second argument, and the example shows how to configure Capybara to use it. Perhaps your existing projects use minitest-metadata and configure Capybara with it, and your new projects don't?
I want both, testing Ajax Content and normal toggled content through Javascript.
My Setup is:
- Rails 3.1
- Rspec (Edge)
- Cucumber (Edge)
- Capybara (Edge)
For expample, I want to have a Form, which shows particular fields only, if a certain type of this model is selected:
Article can be an external article (url)
or an internal.
Type "externa_url" should show 2 input fields and 2 checkboxes more then Type "article",
which has a body textarea instead.
Whats the best way to implement this, also with testing?
Should it be Server sided, so that partials are loaded, if a certain article type is selected,
or with javascript, toggle the needed html?
Actually inspired by Fransico (in the comments), I write down my knowledge.
I write my own answer, it may helps others too....
First I want to mention, I answer my question with – do integration testing only.
With cucumber and selenium.
And specific javascript testing with jasmine.
But, when integration testing with cucumber (edge) rails (3.1), capybara and selenium you have to be aware of some things:
Look, that you have all your gems updated!
1) Activate your driver, if you haven't already
features/support/capybara.rb
Capybara.javascript_driver = :selenium
2) At the moment only Firefox <=4 works with webdriver selenium for rails, as I found out hardly after hours of configuring and installing each component from scratch, like rack etc.
3) Capybara itself not handles much, which serves you for klicking e.g. on lists, jquery-tokeninput especially.
3.1) I use this for selecting an Item from the tokens in the list:
When(/^I select the option containing "([^\"]*)" in the Tag List/) do |text|
find("li:contains('#{text}')").click
end
You may find this method with "locate" instead of find, don't try this, api / driver has changed to find.
Find waits automatically and check for a Ajax respond in addition of dom finding elements.
4) Add your own helper / finder / click routines for your JS / Ajax responded code,
keep in mind, it is "only" an integration test, you may want to test your JS code with yasmine or another js test framework.
For furthter information also check Screencasts from Ryan Bates (http://railscasts.com), he covers several Topics on Testing Rails; check the latest one for Javascript e.g.
Or this blog: http://openmonkey.com/2010/04/09/javascript-testing-with-cucumber-capybara/
(thnx francisco)
hope this helps someone else as well.
I started migrating from cucumber + webrat to cucumber + capybara. Now the behavior of "I should see " seems to be somewhat different. Most of these fail now, although I didn't change anything on the page. I replaced the snippet that should be found with some stuff that is on every page and for some text it works and for other text it doesn't. I can't find any pattern in what is found in the page's content and what is not.
Webrat used to print what the page content is that it found, in case it did not contain the required phrase. Is there anyway to have capybara show what text it got from the page in which it tried to find the text?
Then show me the page calls webrat/capybara's underlying save_and_open_page method. Found that useful when working with steak.
Try adding this step:
Then show me the page
If you want to have the browser open the page when the page fails you use the 'launchy' gem.
Add it to your gem file, and then in /features/support create a file called debugging.rb with contents:
After do |scenario|
save_and_open_page if scenario.failed?
end
If you're using Javascript or Ajax in your pages and want to see what's going on, I've found that the Poltergeist driver is very good at letting you get into the DOM and find out what's going wrong.
If you setup your Capybara driver with the remote debugging option:
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, inspector: true)
end
You can then put the following line in your steps:
page.driver.debug
Which fires up a new Chromium browser with the current DOM state set, letting you get at the console. (On my version of Linux, I had to symlink chromium to chromium-browser but it otherwise worked fine).
Source Info: http://jonathanleighton.com/articles/2012/poltergeist-0-6-0/
Then show me the response didn't work for me with cucumber 1.1. I found useful to write a step using capybara's command:
print page.html
This outputs the current state of the DOM
You could also use "Then show me the response" which outputs the HTML to the console if you don't want to use a browser.
You could always have it take a screen shot when something failed. I debug a LOT of failing features that way.
Given I have a rails app
And I'm using cucumber
And I'm using capybara
And I have an action that results in a redirect_to "http://some.other.domain.com/some_path"
When I test this action
Then the in-app portion of the test works fine
But I see this error: No route matches "/some_path" with {:method=>:get} (ActionController::RoutingError)
So capybara is properly redirected to "http://some.other.domain.com/some_path" but for some reason it thinks it should handle the path portion of the url inside my app. NOTE capybara has no problem at all with "http://some.other.domain.com/" -- my tests pass if I redirect to a url without a path portion.
Is this a bug?
I think I had the same problem as you: I just wanted to confirm, that my code redirects to that given URL with the correct status code, but I don't want to do anything on that URL.
The problem is, that the site returns the redirect as expected, but Rack::Test interprets everything to the application under test, and that URL probably doesn't exist. But we can just catch the error and see what the response looked like. This will probably not work with anything else than capybara's default driver.
begin
click_button('Pay with Paypal')
rescue ActionController::RoutingError
end
expect(page.status_code).to eq(302)
expect(page.response_headers['Location']).to include('paypal.com/cgi-bin/websrc')
Here's an example I wrote up about using capybara-mechanize and VCR to test an external redirect.
http://blog.tddium.com/2011/10/04/testing-external-redirects-vcr-capybara-mechanize/
I've found a cool solution for Capybara (which can be adapted into Cucumber).
begin
click_button 'Accept'
rescue ActionController::RoutingError
# Capybara doesn't redirect externally, so matches '/cb' but that route doesn't exist
expect(page.current_url).to eq "https://example.com/cb?param=123"
end
Which driver are you using? The Rack-Test driver isn't going to allow you to request stuff from other domains. If Capybara is doing this with Selenium or Culerity, it's definitely a bug. If you want to help out in getting it fixed, writing a failing spec would be very appreciated :)
#javascript is a currently working solution, though there's also a mechanize driver in the works, which uses rack-test up to the point where you hit an external request.
It's a bit new and I haven't tried it yet, but am meaning to change my external #javascript tests to using it (tagged with #live or #external or similar) for the speed boost.
Using this little snippet:
external_redirect "https://api.twitter.com/oauth/authenticate?x_auth_access_type=read&oauth_token=TOKEN" do
click_link "Continue with Twitter"
end
def external_redirect(url)
yield
rescue ActionController::RoutingError # goes to twitter.com/oauth/authenticate
current_url.must_equal url
else
raise "Missing external redirect"
end
I had a similar situation where I was integrating my app with the company's SSO platform. The way I got around this was to get the site running Selenium via appending the #javascript tag against the scenario.