Note 2022-12-06: This is a consolidation of three posts, two posted on 2012-07-17, and one posted on 2012-07-23.
POST 1:
One of my frustrations with Rails is that there are few if any ‘include’ or ‘require’ statements. Now I am going to do something about it. At least something for myself.
I went through the Hartl tutorial (as do most Code Academy students, and many aspiring Rails devs). He uses RSpec and Capybara for testing. RSpec can be used for any Ruby project, while Capybara is used for web projects. I think it can be used for other Ruby web frameworks, and other testing frameworks besides RSpec.
One thing I find in the tutorial and the tests is that Hartl will just call methods and instantiate variables. I don’t always know whether he is calling something from RSpec or Capybara.
At one point, he says this: Because of subject { page }
, the call to should
automatically uses the page
variable supplied by Capybara (Section 3.2.1). This is in refernce to the file spec/requests/static_pages_spec.rb.
But where in Capybara does “page” come from?
You see it in code like this:
subject {page}
The “subject” method is used for the models as well:
subject {@user}
But there is no “page” model, or a “page” factory. But it raises another question in my mind: What is “subject”?
I am pretty sure “subject” is from RSpec, either
http://rubydoc.info/gems/rspec-core/RSpec/Core/Subject/ExampleGroupMethods#subject-instance_method
or
http://rubydoc.info/gems/rspec-core/RSpec/Core/Subject/ExampleMethods#subject-instance_method
In the Hartl specs (2nd edition) you see this (via grep -r subject * | grep page)
requests/static_pages_spec.rb:5: subject { page }
requests/authentication_pages_spec.rb:5: subject { page }
requests/micropost_pages_spec.rb:5: subject { page }
requests/user_pages_spec.rb:5: subject { page }
In the Hartl tutorial, at say, like http://ruby.railstutorial.org/chapters/filling-in-the-layout#sec:pretty_rspec, he says
Because of subject { page }, the call to should automatically uses the page variable supplied by Capybara (Section 3.2.1).
So where does “page” come from? I am looking around the Capybara docs, and on http://rubydoc.info/github/jnicklas/capybara/file/README.md I see this:
Full reference: Capybara::Node::Matchers
Capybara has a rich set of options for querying the page for the existence of certain elements, and working with and manipulating those elements.
page.has_selector?(‘table tr’)
page.has_selector?(:xpath, ‘//table/tr’)
page.has_no_selector?(:content)
page.has_xpath?(‘//table/tr’)
page.has_css?(‘table tr.foo’)
page.has_content?(‘foo’)
After some googling and some digging, and it looks like “page” is part of the Capybara::DSL module:
http://rubydoc.info/github/jnicklas/capybara/master/Capybara/DSL
It looks like it returns a Capybara::Session object.
At some point I will make a separate page or post with just the methods that pop out of nowhere, and whether they are RSpec or Capybara.
POST 2:
I made some progress on this.
If something is a class, like “page” in the Hartl tutorial (like on say spec/requests/static_pages_spec.rb)
you could just do
puts "Here is page.class: #{page.class}"
which would give you
Here is page.class: Capybara::Session
I don’t know why I didn’t think of that before.
In that file he also calls some voodoo methods. In before do he has:
sign_in FactoryGirl.create(:user)
and
visit users_path
sign_in and visit are methods. You can get these by doing this:
meth = self.method(:sign_in)
puts "Here is method of sign_in: #{meth.owner}"
meth2 = self.method(:visit)
puts "Here is method of visit: #{meth2.owner}"
or you could do that on one line each like this:
puts "Here is method of sign_in: #{self.method(:sign_in).owner} "
puts "Here is method of visit: #{self.method(:visit).owner} "
Which will give you:
Here is method of sign_in: Object
Here is method of visit: Capybara::DSL
Granted, getting “Object” is not too helpful. But it is some progress.
Someone on the Rails core team has a post about finding methods here.
POST 3:
In two previous posts, I wrote about my frustrations with methods in Rails tests that just seem to float in space and appear out of nowhere, and that the Hartl tutorial mixes RSpec and Capybara, and that it would be nice to know which is which.
In the last post, I wrote that sometimes when you try to find which class contains a method you get “Object”, which is not very helpful.
puts "Here is method of sign_in: #{self.method(:sign_in).owner} "
puts "Here is method of visit: #{self.method(:visit).owner} "
Here is the output:
Here is method of sign_in: Object
Here is method of visit: Capybara::DSL
The “sign_in” method is from one of the tests in the Hartl tutorial. I was explaining this to someone about an hour ago, and I realized why self.method says that “sign_in” is part of the “Object” class: Because it is not defined in a class. In the application, Hartl defines it in a module, but in the tests it is simply defined in a file that contains neither a class or a module.
In the root of the Rails tutorial app, you can run a grep command to find that method:
This will give you the following result
app/helpers/sessions_helper.rb:3: def sign_in(user)
spec/support/utilities.rb:3:def sign_in(user)
So here is the file spec/support/utilities.rb:
include ApplicationHelper
def sign_in(user)
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
# puts "Here is method of click_button: #{self.method(:click_button).owner} - "
# Sign in when not using Capybara as well.
cookies[:remember_token] = user.remember_token
end
As I stated, in app/helpers/sessions_helper.rb the method is in a module called SessionsHelper
Image from Pericopes Book of Henry II, an 11th century manuscript housed at Bavarian State Library, webpage information here, image from World Document Library, image assumed allowed under Fair Use.