I've been using Capybara for integration/request testing, but have only just realised I can't do view testing with it.
This SO answer suggests Webrat and Capybara can be used in tandem; but the RSpec docs suggest one must choose between the two. Here's another github thread that suggests webrat can be used for views and capybara for integration.
I've found that if I include Webrat in my gemfile, I can use webrat for views with no problem, but my capybara-styled integration tests no longer work. Specifically, I get an error with the following simple example:
it "should have a Home page at '/'" do
visit '/'
page.should have_selector('title', :content => "Home page")
end
I get the error:
No response yet. Request a page first.
What's the best way (if any?) to get webrat and capybara to like eachother?
There's generally no reason to use both Webrat and Capybara. Pick one (probably Capybara). View tests are a bad idea and shouldn't be necessary in general; usually your integration tests should cover that ground.
In other words, fix your testing strategy and the problem will go away.
In general, I agree with Marnen about "just pick one of them, probably Capybara", but one possible reason to use both of them is gradual migration.
Say, you have a large test suite and you're migrating it to Capybara, but you'd like to let some of your old tests to stay "Webrat-driven" for some time.
Although, I didn't find ideal solution for this case, here's what I did:
# features/support/env.rb
...
if ENV['WITH_WEBRAT'].nil?
require 'capybara/rails'
require 'capybara/cucumber'
...
else
require 'webrat'
...
end
...
# config/cucumber.yml
...
default: --profile capybara
capybara: <% std_opts %> --tags ~#webrat features
webrat: <% std_opts %> --tags #webrat features WITH_WEBRAT=1
...
# features/webrat.feature
#webrat
...
# features/capybara.feature
...
Now, you can do cucumber to run your capybara-only test suite or cucumber -p webrat for your legacy Webrat features.
Not ideal, but it worked for me.
Related
I an trying to organize code by making partial html.erb files that are shared frequently(e.g. _form.html.erb)
I want to check whether my partial code works well with different models/controllers, so I am manually doing CRUD from the views.
It would be nicer to test my code automatically using Rspec but I have no idea. Can anyone give me some guidance how to test controller code with Rspec?
To test controller and views together you write feature specs and request specs .
Request specs are lower level specs where you send HTTP requests to your application and write expectations (aka assertions in TDD lingo) about the response. They are a wrapper around ActionDispatch::IntegrationTest. Request specs should be considered the replacement for controller specs, the use of which are discouraged by by the RSpec and Rails teams.
# spec/requests/products_spec.rb
require 'rails_helper'
RSpec.describe "Products", type: :request do
describe "GET /products" do
let!(:products) { FactoryBot.create_list(:product, 4) }
it "contains the product names" do
get "/products"
expect(response).to include products.first.name
expect(response).to include products.last.name
end
end
end
Feature specs are higher level specs that focus on the user story. They often serve as acceptance tests. They use a browser simulator named Capybara which emulates a user clicking his way through the application. Capybara can also run headless browsers (headless chrome, firefox, phantom js, webkit etc) and "real" browsers through selenium. The minitest equivalent is ActionDispatch::SystemTestCase but RSpec features do not wrap it (it took minitest/testunit years to catch up here).
# Gemfile
gem 'capybara'
# spec/features/products_spec.rb
require 'rails_helper'
RSpec.feature "Products" do
let!(:products) { FactoryBot.create_list(:product, 4) }
scenario "when a user views a product" do
visit '/'
click_link 'Products'
click_link products.first.name
expect(page).to have_content products.first.name
expect(page).to have_content products.first.description
end
end
This specs tests the products#index and products#show action as well as the root page and the associated views.
Both types of specs have their strengths and weaknesses. Feature tests are good for testing large swaths of the application but are heavy. Request specs are faster and its easier to replicate a specific request that causes a bug/issue but you're basically just matching HTML with regular expressions which is highly limited.
To check whether partial code works well with different models/controllers. You can add render_views in controller specs.
How to test controller code with Rspec?
Read the official doc https://relishapp.com/rspec/rspec-rails/docs/controller-specs
And this page may help: https://thoughtbot.com/blog/how-we-test-rails-applications
I'm writing a piece of test code for my Rails 4 app, and I was wondering if there's a way to automate it in order to submit a URL to the web every time its run.
Typing a specific URL (http://website.com/add?application=Test&...&severity=ERROR) into a browser search bar populates my database with certain data, and I want to test if changing the parameters of the URL yields the correct results. Is there a way to make my test code do this by itself?
You need 2 gems:
faker for generating random stuffs like email addresses, names, phone numbers, etc.
rspec-rails, a test automation tool for Ruby on Rails.
There will be some configuration to enable these things. Since you are an intern, I give you a minimum sample.
In the following steps, the path / refers to the root of your rails application, not the root of the file system.
Step 1: install these gems
In the /Gemfile, add these lines:
group :test do
gem 'rspec-rails'
gem 'faker'
end
Then run bundle install.
After the gems are installed, run rails generate rspec:install, which generates the folder /spec/ and some files in it.
Step 2: write tests
Finally you can write tests.
Run rails generate rspec:request add, it will give you a test script file at /spec/requests/adds_spec.rb. It looks like
require 'rails_helper'
RSpec.describe "Adds", type: :request do
describe "GET /adds" do
it "works! (now write some real specs)" do
get adds_path
expect(response).to have_http_status(200)
end
end
end
Now modify it
require 'rails_helper'
RSpec.describe "Add", type: :request do
let(:application) {Faker::Lorem.word}
let(:severity) {%w(trace debug info error fatal).sample}
# other params ...
describe "GET /add" do
it "creates some record" do
get add_path(application: application, severity: severity)
my_model = MyModel.last!
expect(my_model.application).to == application
# other expectations ...
end
end
end
Then run it with bundle exec rspec spec.
P.S. You may need database_cleaner to clean up database after each test. You may also need factory_girl_rails to help you create fixtures. You may need capybara to mimic human using browsers. You may ... So find yourself a textbook about Rails.
I've been reading a ton of docs and SO questions/ answers on all the changes as Rspec has evolved, want to be sure of the answer...
My goal is to use native Rspec-rails (I have 3.2.2) to do integrated controller/view tests that look for 1) CSS classes and 2) ID selectors. In other words given this view snippet:
<!-- staticpages/dashboard -->
<div class="hidden">Something</div>
<div id="creation">This</div>
This should pass (however it should be semantically written):
describe StaticpagesController do
render_views
it "should find everything" do
get :dashboard
expect(response.body).to have_selector("div#creation")
expect(response.body).to have_css("hidden")
expect(response.body).to_not have_selector("div#nothinghere")
end
end
I would like to do this without additional gems like Capybara; is that possible?
Here's a high level of what I've learned so far:
in Rspec 1, the have_tag feature allowed you to do this (http://glenngillen.com/thoughts/using-rspec-have-tag)
in Rspec 2, the have_tag was replaced with webrat's have_selector (have_tag vs. have_selector)
in Rspec 3, webrat support has been removed (http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/)
In my own experimentation, the code above generated:
Expect<long response.body here>.to respond to `has_selector?`
So that has indeed been deprecated. Still, I'd love to know if there's some other way to do this that I don't know about.
IF it turns out I need Capybara to do these fancy matchers, is there a way to do this in my integrated controller/view specs? My understanding is that I have to add type: :feature to the describe StaticpagesController line to use Capybara's matchers. However, the minute I do that, render_views is no longer available (since it's limited to type: :controller). Note, render_views also dies if, per this post (https://www.relishapp.com/rspec/rspec-rails/v/2-99/docs/controller-specs/use-of-capybara-in-controller-specs), I manually include Capybara::DSL into my controller spec. Anyway, I would really like to not have to rewrite my current controller specs into a bunch of feature specs...
It would seem that you want feature specs (with Capybara) more than controller specs as you're not testing any of the things controller specs are typically used to test such as:
whether a template is rendered
whether a redirect occurs
what instance variables are assigned in the controller to be shared with the view
the cookies sent back with the response
Also, you probably want to consider writing feature specs for new apps over controller specs since controller tests will probably be dropped in Rails 5 in favor of the writing of integration/feature tests.
For a description of the different kinds of specs that you could write, and what they're typically used for,
see this SO answer.
Working on a new Rails 3.2.9 app with rspec and capybara.
I have the following in the Gemfile:
gem 'rspec-rails'
gem 'capybara'
and the following in spec/spec_helper.rb:
require 'rspec/rails'
require 'capybara/rspec'
and in spec/requests/asdf_spec.rb:
require 'spec_helper'
describe 'Asdf' do
describe "GET /asdfs" do
it "should list asdfs" do
visit asdfs_path
end
end
end
This test is failing:
Failure/Error: visit asdfs_path
NoMethodError:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested_1:0x007fa7b68961a0>
# ./spec/requests/asdfs_spec.rb:19:in `block (4 levels) in <top (required)>'
So it looks like Capybara isn't getting loaded. Ack, why not? I feel like I've done this exact same thing a dozen times before... probably blanking on something stupid.
So it was a capybara version 2 change. I found this:
http://alindeman.github.com/2012/11/11/rspec-rails-and-capybara-2.0-what-you-need-to-know.html
which explains:
Upon upgrading to capybara 2.0, capybara will not be available by
default in RSpec request specs. Instead, a new type of spec--the
feature spec--has been created for use with capybara.
To upgrade to capybara 2.0, you'll need to do a few things:
Upgrade rspec-rails to 2.12.0 or greater
Move any tests that use capybara from spec/requests to spec/features. Capybara
tests use the visit method and usually assert against page.
Just some additional info for anybody having the same problem with the Capybara upgrade to 2.x. Check out rspec-rails docs under the Upgrading to Capybara 2 section.
Basically, In order to use the Capybara DSL(page & visit) you must move your existing specs into the spec/features directory. So you can only use page & visit in acceptance tests. No more page & visit in controller and request specs. Only the rack-test DSL (get|post|put|delete|head/response.body) is allowed in controller and request specs.
This is not recommended but there is a way to keep your specs working as they are:
RSpec.configure do |c|
c.include Capybara::DSL, :example_group => {
:file_path => "spec/requests"
}
end
The docs state that if you go this route then you are overriding the intended behavior and you are taking a risk.
And definitely don't make this as a reason not to upgrade to Capybara 2.x. Feature specs are easy to get used to and are easy to read. feature is just an alias for describe, background is an alias for before, scenario for it, and given for let.
Hope this helps anyone confused by the new changes.
The issue is in capybara gem itself.
gem 'capybara', '1.1.2' solves this issue ( Version 2.0.x fails )
I have an application that I'm testing with rspec2 (2.6.4), capybara and selenium.
When I run any request spec directly with rspec, the test passes.
When I run the request specs with autotest they all fail with a message saying 'Cannot find a User with ID= **.
When autotest reloads the first request test automatically, it passes
Autotest then reloads all tests and when it reaches the request tests they all fail again
Users are being created by factory-girl and logged in using devise as follows:
before(:each) do
#user = Factory(:user)
login_as #user
end
after(:each){
logout
}
and in the spec helper I have
def login(user)
post login_path, :login => user.login, :password => 'testing'
end
These are the relevant gems i have installed (group :test)
gem "rspec"
gem "rspec-rails"
gem "autotest-rails"
gem "selenium-webdriver", ">= 0.2.2"
gem 'capybara', :git => 'git://github.com/jnicklas/capybara.git'
gem 'launchy'
gem 'database_cleaner'
This has been baffling me for a while now - any thoughts anyone? Even any thoughts on how to start looking at the stack trace to see where the two calls are differing?
Solved, sort of. What is really going on here remains a mystery, but here is an accurate summary of what the problem really is, and how I resolved it. Autotest is not the culprit - the problem is running all the tests in one batch. Running rspec spec/**/* causes the same error. This is a clue that the issue is to do with a failure to clean up the database properly between tests. I am using devise, and so am ultimately relying on warden for rack-based authentication. Following the Warden documentation I put a call to Warden.test_reset! in the after(:suite) block. If I move this to the after(:all) block, the tests pass the same whether run individually, as request tests, or all the tests in one block.
So what did we learn? I think the problem (for me at least) was ultimately caused by a confusing naming of the rspec hooks. I think of a "suite" of rooms in a hotel as being less than "all" the rooms in a hotel. But apparently a "suite" of rspec examples is more than "all" the examples. In fact a suite of rspec examples is just "all the examples under the spec directory". Cleaning up warden after they have all been run has no effect. We need to clean them up after each spec - and to do that need to run test_reset! in the after(:all) block.
Hope this helps someone ...