rspec error in ruby with before each do - ruby-on-rails

I am working through the Learn Rails By Example book and came across an interesting problem. I'll apologize in advance if I am just doing something wrong. Here is the problem.
In section 3.5, the exercise it asks you to do the following:
You may have noticed some repetition in the Pages controller spec (Listing 3.20). In particular, the base title, “Ruby on Rails Tutorial
Sample App”, is the same for every title test. Using the RSpec
before(:each) facility, which executes a block of code before each
test case, fill in Listing 3.33 to define a #base_title instance
variable that eliminates this duplication. (This code uses two new
elements: a symbol, :each, and the string concatenation operator +.
We’ll learn more about both in Chapter 4, and we’ll see before(:each)
again in Section 6.2.1.) Note that, with the base title captured in an
instance variable, we are now able to align :content with the first
character inside each left parenthesis (. This is my preferred
convention for formatting code broken into multiple lines.
Here is how my pages_controller_spec.rb looks:
describe PagesController do
render_views
before(:each) do
# Define #base_title here.
base_title = "Ruby on Rails Tutorial Sample App"
end
describe "GET 'home'" do
it "should be successful" do
get 'home'
response.should be_success
end
it "should have the right title" do
get 'home'
response.should have_selector("title",
:content => #base_title + " | Home")
end
end
When I load the rails server and open the webpage, everything works perfect. The title shows up as it should per the base_title. However, when I run rspec, I receive the following errors. I'd really like to get this cleared up in rspec. What do you think is wrong?
1) PagesController GET 'home' should have the right title
Failure/Error: :content => #base_title + " | Home")
NoMethodError:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.+
# ./spec/controllers/pages_controller_spec.rb:20
Failed examples:
rspec ./spec/controllers/pages_controller_spec.rb:17 # PagesController GET 'home' should have the right title

I think you need #base_title = "Ruby on Rails Tutorial Sample App" at line 6, not base_title. A variable defined as you do there does not automatically become an instance variable

Related

RoR Tutorial - A direct test the full_title helper

I am working on the RoR Tutorial chapter 5 exercises and I can't seem to figure out what text to use in place of the "FILL_IN" I've tried reading the error messages by trying to match the actual with the expected. What am I doing wrong? Also, can someone explain how the <expected> and <actual> work in this test since I don't see the words "expected" or "actual" anywhere.
require 'test_helper'
class ApplicationHelperTest < ActionView::TestCase
test "full title helper" do
assert_equal full_title, "Kim's Cool Rails Site"
assert_equal full_title("Help"), "Kim's Cool Rails Site | Help"
end
end
can someone explain how the <expected> and <actual> work
Often a term between angle brackets, like <expected> and <actual> indicates a value that needs to be replaced. In this case, it mentions:
assert_equal <expected>, <actual>
which gives a description of the parameters taken by the assert_equal method. We're meant to replace them with our real-life values. For example,
result = 1 + 1
assert_equal 2, result
Here we've replaced <expected> with 2, and <actual> with result, to test that 1 + 1 = 2, as we expect it to.
I can't seem to figure out what text to use in place of the "FILL_IN"
So the relevant lines in your code are:
assert_equal full_title, FILL_IN
assert_equal full_title('help'), FILL_IN
In both lines, you should replace FILL_IN with whatever the result of the previous parameter is - in this case, full_title, and full_title('help')
So, if full_title gives "Kim's Cool Rails Site", then the first line should be:
assert_equal full_title, "Kim's Cool Rails Site"
And if full_title('Help') gives "Kim's Cool Rails Site | Help", then the second line should be:
assert_equal full_title('Help'), "Kim's Cool Rails Site | Help"
** UPDATES **
So the error you're getting basically says: We expected to see "Ruby on Rails Tutorial Sample App" and instead we say "Kim's Cool Rails Site".
In the example I gave, I just used "Kim's Cool Rails Site" as an example because I didn't know the actual title of your site. You needed to replace "Kim's Cool Rails Site" with whatever the actual title of your site is (ie, whatever full_path returns). So, judging from the error message, the exact code you need for the first line will be:
assert_equal full_title, "Ruby on Rails Tutorial Sample App"
You'll need to figure out the exact text you need for the second line yourself, but you'll basically just have to replace "Kim's Cool Rails Site | Help" with whatever you expect full_title('Help') to return.
I believe this is what you were after....
require 'test_helper'
class ApplicationHelperTest < ActionView::TestCase
test "full title helper" do
assert_equal full_title, "Ruby on Rails Tutorial Sample App"
assert_equal full_title("Help"), "Help | Ruby on Rails Tutorial Sample App"
end
end

Eliminate need for full_title test helper (railstutorial.org [Michale harlt] Chapter 5.6 exercise 4)

I just completed the Chapter 5 exercises from "The Ruby on Rails tutorial" by Michael Hartl (which is really great) But exercise 4 from section 5.6, I just don't understand how it works.
I have created integration tests using rspec located in spec/requests/static_pages_spec.rb:
shared_examples_for "all static pages" do
it { should have_selector('h1', text: heading) }
it { should have_title(full_title(page_title)) }
end
The full_title function is located in a support directory under spec/support/utilities.rb:
def full_title(page_title)
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
"#{base_title} | #{page_title}"
end
end
Which works great. In exercise 4 in 5.6 we are tasked to remove it by adding a helpers directory and application_helper_spec.rb file spec/helpers/application_helper_spec.rb:
require 'spec_helper'
describe ApplicationHelper do
describe "full_title" do
it "should include the page title" do
expect(full_title("foo")).to match(/foo/)
end
it "should include the base title" do
expect(full_title("foo")).to match(/^Ruby on Rails Tutorial Sample App/)
end
it "should not include a bar for the home page" do
expect(full_title("")).not_to match(/\|/)
end
end
end
and edit utilities.rb to contain just one line spec/support/utilities.rb:
include ApplicationHelper
and all of my tests pass!
My question is how..? How, after removing the full_title util function and only adding the application_helper_spec to test full_title do my original spec tests pass?
If you read the question carefully, he's suggesting that there's redundancy in the code that you can refactor further:
"Eliminate the need for the full_title test helper in Listing 5.29 by
writing tests for the original helper method, as shown in Listing
5.41."
If we look at listing 5.29, he follows with:
"Of course, this is essentially a duplicate of the helper in Listing
4.2, but having two independent methods allows us to catch any typos in the base title. This is dubious design, though, and a better
(slightly more advanced) approach, which tests the original full_title
helper directly, appears in the exercises (Section 5.6)."
So, actually, you have already defined this function in your app/helpers/application_helper.rb file. A simple include statement in your spec/support/utilities.rb file will load all of your functions from app/helpers/application_helper.rb and that is why your tests still pass.
Have fun with the rest of the tutorial!

Is there special meaning `foo` string in Rspec?

I'm reading railstutorial chapter 5.6.4.
According to the page the following two code serve same tests.
But I can't understand why it works without having the argument page_title.
Is there special meaning for "foo" string in Rspec?
spec/support/utilities.rb
def full_title(page_title)
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
"#{base_title} | #{page_title}"
end
end
spec/helpers/application_helper_spec.rb
require 'spec_helper'
describe ApplicationHelper do
describe "full_title" do
it "should include the page title" do
expect(full_title("foo")).to match(/foo/)
end
it "should include the base title" do
expect(full_title("foo")).to match(/^Ruby on Rails Tutorial Sample App/)
end
it "should not include a bar for the home page" do
expect(full_title("")).not_to match(/\|/)
end
end
end
spec/support/utilities.rb
include ApplicationHelper
No, the string "foo" does not have any special meaning to RSpec, it is just being used as an example in the test to check if the full_title helper is working correctly.
To answer the other part of your question, if no page title is passed in, then the if statement will take the first path because the page_title variable is empty and you will be returned the base title only. Here is what each of the tests are actually doing:
# This is expected to return "Ruby on Rails Tutorial Sample App | foo", which
# will match /foo/.
it "should include the page title" do
expect(full_title("foo")).to match(/foo/)
end
# This returns the same as above ("Ruby on Rails Tutorial Sample App | foo"),
# but this test is checking for the base title part instead of the "foo" part.
it "should include the base title" do
expect(full_title("foo")).to match(/^Ruby on Rails Tutorial Sample App/)
end
# This returns just "Ruby on Rails Tutorial Sample App" because the page title
# is empty. This checks that the title doesn't contain a "|" character but that
# it only returns the base title.
it "should not include a bar for the home page" do
expect(full_title("")).not_to match(/\|/)
end
This is a "rspec to English" translation of the tests that might help you:
If I give the full_title method the string "foo", the result should:
contain "foo"
contain the base title which is "Ruby on Rails Tutorial Sample App"
not be "|"
The idea behind tests is to make sure your code works using some meaningful examples of the behaviour of the code. You can't test for every possible scenario so you choose one (or more) that describes the functionality of your method the best.
In this case it's passing a string argument "foo" which is often used as a placeholder in programming.

Rails RSpec: Controller Testing, checking if errors Array of model is filled with entries if new record cannot be created due to validation error

I have a still pretty simple Rails application that I want to develop using BDD with Cucumber and TDD with RSpec. Currently, I am hanging at a test where I want to check that if a new instance of an Organizer (that's the model I have) cannot be created due to a validation error. I would like to check that the errors Array of the object to be created is not empty so that I can be sure that error messages are available for showing them in the view.
require 'spec_helper'
describe OrganizersController do
render_views
describe "POST 'create'" do
describe "with invalid arguments" do
before(:each) do
request.env["HTTP_REFERER"] = organizers_new_path
#organizer_args = { :name => "" }
end
it "should return a non-empty list of errors" do
post 'create', :organizer => #organizer_args
#organizer.errors.empty?.should_not be_true
end
end
end
end
I am developing based on Rails 3.2.9 with RSpec 2 and cucumber-rails.
Any suggestions are appreciated. Thanks!
You should use assigns method to get instance variable from controller action:
assigns(:organizer).errors.empty?.should_not be_true
The latest preferred syntax is:
expect(assigns(:organizer).errors.empty?).to_not be_true
thanks for the answer guys but I'd like to suggest a slightly nicer syntax:
expect(assigns(:organizer).errors).to_not be_empty
(unrelated to the question 👇)
Basically whenever you have a method that ends with ? you'll have the corresponding rspec matcher that starts with be_ e.g.
1.odd? #=> true
expect(1).to be_odd

Understanding RSpec 2's generated specs

I think I may be biting off more than I can chew by trying to learn RSpec on my own...there doesn't appear to be any complete documentation on RSpec 2?!? at least none that I have been able to find...
Anyway, I, in a feeble attempt to integrate RSpec, started by examining the 29 specs created by the scaffold generator in Rails 3. Some I understand but much still escapes me. Hoping someone can help (or point me to decent RSpec 2 documentation).
For example in the first code block below (def mock_clown...) I can assume mock_clown is creating a mock of my Clown class to test against. But what exactly is going on? what is generating this "mock"? what does .as_null_object and .tap mean? This is very confusing as I can't find an example to compare this block to in any docs or tutorials I've come across...
#clowns_controller_spec.rb
require 'spec_helper'
describe ClownsController do
def mock_clown(stubs={})
(#mock_clown ||= mock_model(Clown).as_null_object).tap do |clown|
clown.stub(stubs) unless stubs.empty?
end
end
describe "GET index" do
it "assigns all clowns as #clowns" do
Clown.stub(:all) { [mock_clown] }
get :index
assigns(:clowns).should eq([mock_clown])
end
end
...
describe "POST create" do
...
describe "with invalid params" do
it "assigns a newly created but unsaved clown as #clown" do
Clown.stub(:new).with({'these' => 'params'}) { mock_clown(:save => false) }
post :create, :clown => {'these' => 'params'}
assigns(:clown).should be(mock_clown)
end
it "re-renders the 'new' template" do
Clown.stub(:new) { mock_clown(:save => false) }
post :create, :clown => {}
response.should render_template("new")
end
end
...
end
The best source of documentation for rspec is probably its github wikis. Here's a general link to all gems:https://github.com/rspec/rspec/wiki. Also, checkout the rdoc, linked to here.
As for specific answers, as_null_object causes the mock to record and ignore all method calls. (This is great, as you don't have to spec out every single method on an object, just the ones you care about.)
Tap is a Ruby 1.9 feature. From the documentation at this link:
Object#tap
Passes the object to the block and returns it (meant to be used for call chaining).
For learning Rspec 2 Webrat and Cucumber on your own, I definitely recommend checking out the RSpec Book. Awesome resource, and covers all aspects.

Resources