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.
Related
In the exercise, a test is written for the full_title helper and one has to fill in code. Here is the test
require 'test_helper'
class ApplicationHelperTest < ActionView::TestCase
test "full title helper" do
assert_equal full_title, FILL_IN
assert_equal full_title("Help"), FILL_IN
end
end
How does the assert_equal method work here? I'm confused as to what I should put in for the expected and actual.
expected is the value represents the proper behavior, and actual is the what actually gets returned. If full_title is the thing that you're testing, then it should be the actual parameter and the output that you what the method to have should be the expected parameter.
You want to test with the assertion using this format:
assert_equal( expected, actual, [msg] )
So you want to test that the expected value "full_title" in this case will equal the actual value. The last part [msg] is an optional message parameter you can include to clarify your feedback if your test fails. The FILL_IN part is where you insert your actual value. So if full_title has a value of "Welcome To My Site", you would test that value by writing an assertion like:
assert_equal full_title, "Welcome To My Site"
and if the value of full_title("Help") should be "Welcome To My Site | Help"
then you would test it like so:
assert_equal full_title, "Welcome To My Site | Help"
and if you can include the optional message parameter, to make your failure message a bit clearer:
assert_equal full_title, "Welcome To My Site | Help", "This was not the correct title"
and in the event that you're test fails, that message will show up as part of your logs.
There is a Rails guide which goes into more details on how to use assertions: http://guides.rubyonrails.org/testing.html
I am also going through the tutorial and noticed a slight difference from MisterCal's answer in how to write the test.
assert_equal( expected, actual, [msg] )
is the right format but his example uses the full_title method call as the expected when that is the actual result that you are getting.
Below the string is the expected and the helper method call is the actual value you get when calling it. Don't forget to call the method with an argument otherwise you will trigger the default parameter you set earlier
assert_equal "Welcome To My Site | Help", full_title("Help"), "This was not the correct title"
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
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!
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
How can i add a translation test to my specs ? Something like :
flash[:error].should == I18n.translate 'error.discovered'
this does not work of course. How to make it work ?
I want to make sure that i get a certain error back.
In my code, a Rails 3 project, using RSpec 2, that is exactly the line I write:
describe "GET 'index'" do
before do
get 'index'
end
it "should be successful" do
response.should be_redirect
end
it "should show appropriate flash" do
flash[:warning].should == I18n.t('authorisation.not_authorized')
end
end
So I am not sure why you say it is not possible?
Not sure if this is optimal, but in my Rails3/RSpec2 apps, I test all my locale translations in RSpec in the following way:
I set the available locales in my config/initializers/i18n.rb file:
I18n.available_locales = [:en, :it, :ja]
and in my spec files that need translation checking I have tests that looks something like:
describe "Example Pages" do
subject { page }
I18n.available_locales.each do |locale|
describe "example page" do
let(:example_text) { t('example.translation') }
before { visit example_path(locale) }
it { should have_selector('h1', text: example_text) }
...
end
...
end
end
I wasn't sure how to get just the t() method to be usable in the specs without needing I18n.t so I just added a small convenience method to spec/support/utilities.rb:
def t(string, options={})
I18n.t(string, options)
end
Update: These days I tend to use the i18n-tasks gem to handle testing related to i18n, and not what I wrote above or have answered on StackOverflow previously.
I wanted to use i18n in my RSpec tests primarily to make sure that I had translations for everything ie there were no translations missed. i18n-tasks can do that and more through static analysis of my code, so I don't need to run tests for all I18n.available_locales anymore (apart from when testing very locale-specific functionality, like, for example, switching from any locale to any other locale in the system).
Doing this has meant I can confirm that all i18n keys in the system actually have values (and that none are unused or obsolete), while keeping the number of repetitive tests, and consequently the suite running time, down.
Assuming the code in the controller is:
flash[:error] = I18n.translate 'error.discovered'
You could stub 'translate':
it "translates the error message" do
I18n.stub(:translate) { 'error_message' }
get :index # replace with appropriate action/params
flash[:error].should == 'error_message'
end