The author, Michael Hartl, says:
Here the rule:
get "static_pages/home"
maps requests for the URI /static_pages/home to the home action in the StaticPages controller.
How? The type of request is given, the url is given, but where is the mapping to a controller and action? My tests all pass, though.
I also tried deleting all the actions in the StaticPagesController, which just looks like this:
class StaticPagesController < ApplicationController
def home
end
def about
end
def help
end
def contact
end
end
...and my tests still pass, which is puzzling. No, I deleted all my actions like this:
class StaticPagesController < ApplicationController
end
The 2nd edition of the book(online) is really frustrating. Specifically, the section about making changes to the Guardfile is impossible to follow. For instance, if I instruct you to edit this file:
blah blah blah
dog dog dog
beetle beetle beetle
jump jump jump
and make these changes:
blah blah blah
.
.
.
go go go
.
.
.
jump jump jump
...would you have any idea where the line 'go go go' should be in the code?
And the hint for exercise 3.5-1 is flat out wrong. If the author would put up a comment section at the end of every chapter, the rails community could self-edit the book.
Tests:
require 'spec_helper'
describe "StaticPages" do
let(:base_title) { "Ruby on Rails Tutorial Sample App" }
describe "Home page" do
it "should have the h1 'Sample App'" do
visit '/static_pages/home'
page.should have_selector('h1', :text => 'Sample App')
end
it "should have the title 'Home'" do
visit "/static_pages/home"
page.should have_selector(
'title',
:text => "#{base_title} | Home")
end
end
describe 'Help page' do
it "should have the h1 'Help'" do
visit "/static_pages/help"
page.should have_selector('h1', :text => 'Help')
end
it "should have the title 'Help'" do
visit '/static_pages/help'
page.should have_selector(
'title',
:text => "#{base_title} | Help")
end
end
describe 'About page' do
it "should have the h1 'About'" do
visit '/static_pages/about'
page.should have_selector('h1', :text => 'About')
end
it "should have the title 'About'" do
visit '/static_pages/about'
page.should have_selector(
'title',
:text => "#{base_title} | About")
end
end
describe 'Contact page' do
it "should have the h1 'Contact'" do
visit '/static_pages/contact'
page.should have_selector('h1', :text => 'Contact')
end
it "should have the title 'Contact'" do
visit '/static_pages/contact'
page.should have_selector(
'title',
:text => "#{base_title} | Contact")
end
end
end
As you can see here:
http://guides.rubyonrails.org/routing.html#http-verb-constraints
it is just a shorthand for
match 'static_pages/home' => 'static_pages#home', :via => :get
Basically Rails infers from your url static_pages/home that you are referring to the StaticPagesController's home action.
Also, when you 'deleted' all your actions, you left the action definitions - which is what the test checks. It just checks if it can go to the home action of your staticpages controller. It doesn't matter if it does nothing, as long as it exists(at least that's what I think your tests does - care to post the tests also?)
If you delete
...
def home
end
...
from your controller, I'm pretty sure your tests will fail
I found an answer to this conundrum. First of all, this is a rails 'problem' not an rspec problem; if I add a route to routes.rb such as:
get "static_pages/dog"
...and then enter the url
http://localhost:3000/static_pages/dog
in my browser, rails complains:
Unknown action
The action 'dog' could not be found for StaticPagesController
Then if I add the dog action to the controller, then create a view,
everything works fine and dandy.
But if I then delete the dog action, and then use the same url,
http://localhost:3000/static_pages/dog
in my browser, this time I get a different result--instead of getting an error the view displays.
As it turns out, that inconsistent behavior is a rails 'feature' called default rendering, explained here:
http://guides.rubyonrails.org/layouts_and_rendering.html#rendering-by-default-convention-over-configuration-in-action
According to the docs, all that's needed to render a page is a route and a view--the action is optional.
Related
In my application there is an admin part, which is restricted to superadmins (users with a property superadmin: true). I've got a shop list, which I want to get paginated and tested.
When debugging the current code with save_and_open_page I get a blank page. If I log in not as a superadmin, I get redirected to application's root and when trying to debug with save_and_open_page is see the root page.. If I do not log in at all, then I'll get redirected to the sign in page. So the basic functionality should work.
I'm having no clue why it does not work with superadmin and why I do not see the shops list when debugging with save_and_open_page.
This is my spec/controllers/shops_controller_spec.rb (copied basically from here) :
require 'rails_helper'
RSpec.describe Admin::ShopsController, type: :controller do
context "GET methods" do
describe "#index action" do
before(:all) {
amount = Rails.application.config.page_size
amount.times { FactoryGirl.create(:shop) }
}
before(:each) {
login_as(FactoryGirl.create(:user, superadmin: true), :scope => :user)
}
context "with entries == config.page_size" do
it "has no second page" do
get :index
expect(response).not_to have_selector("a", :href => "/shops?page=2", :content => "2")
# visit admin_shops_path
# expect(page).to have_no_xpath("//*[#class='pagination']//a[text()='2']")
end
end
context "with entries > config.page_size" do
before { FactoryGirl.create(:shop) }
it "has a second page with too many entries" do
visit "/admin/shops"
save_and_open_page
expect(page).to have_xpath("//*[#class='pagination']//a[text()='2']")
end
it "correctly redirects to next page" do
visit admin_shops_path
find("//*[#class='pagination']//a[text()='2']").click
expect(page.status_code).to eq(200)
end
end
end
end
end
As you can see, I tried to test in different ways (the "expect block" is taken from this SO-question), but none of them work. Using get :index I receive
Admin::ShopsController GET methods #index action with entries == config.page_size has no second page
Failure/Error: expect(page).not_to have_selector("a", :href => "/shops?page=2", :content => "2")
ArgumentError:
invalid keys :href, :content, should be one of :count, :minimum, :maximum, :between, :text, :id, :class, :visible, :exact, :exact_text, :match, :wait, :filter_set
Here is my AdminController.rb if it helps:
class AdminController < ApplicationController
layout 'admin'
before_action :authenticate_user!, :verify_is_superadmin
before_action :set_locale
before_action :get_breadcrumbs
private
def get_breadcrumbs
splitted_url = request.original_fullpath.split("/")
# Remove first object
splitted_url.shift
result = splitted_url.map { |element| element.humanize.capitalize }
session[:breadcrumbs] = result
# debug
end
def set_locale
I18n.locale = params[:locale] || session[:locale] || I18n.default_locale
# session[:locale] = I18n.locale
end
def verify_is_superadmin
(current_user.nil?) ? redirect_to(root_path) : (redirect_to(root_path) unless current_user.superadmin?)
end
end
Update
Using Thomas' answer I ended up putting my code in spec/features and it looks like this right now:
require "rails_helper"
RSpec.feature "Widget management", :type => :feature do
before(:each) {
amount = Rails.application.config.page_size
amount.times { FactoryGirl.create(:shop) }
}
before(:each) {
login_as(FactoryGirl.create(:user, superadmin: true), :scope => :user)
}
scenario "with entries == config.page_size" do
visit admin_shops_path
#save_and_open_page
expect(page).to have_no_xpath("//*[#class='pagination']//a[text()='2']")
end
scenario "with entries > config.page_size" do
FactoryGirl.create(:shop)
visit admin_shops_path
expect(page).to have_xpath("//*[#class='pagination']//a[text()='2']")
end
scenario "with entries > config.page_size it correctly redirects to next page" do
FactoryGirl.create(:shop)
visit admin_shops_path
find("//*[#class='pagination']//a[text()='2']").click
expect(page.status_code).to eq(200)
end
end
Everything works!
You've got a number of issues here.
Firstly the other SO question you linked to isn't using Capybara so copying its examples for matchers is wrong.
Secondly you are writing controller tests, not view tests or feature tests. controller tests don't render the page by default, so to test elements on the page you want to be writing either view tests or feature tests. Capybara is designed for feature tests and isn't designed for controller tests. This is why the default capybara/rspec configuration file only includes the Capybara DSL into tests of type 'feature'. It also includes the Capybara RSpec matchers into view tests since they are useful with the rendered strings provided there.
Thirdly, you are mixing usage of get/response, and visit/page in the same file which just confuses things.
If you rewrite these as feature tests, then to check you don't have a link with a specific href in capybara you would do
expect(page).not_to have_link(href: '...')
If you want to make sure that a link doesn't exist with specific text and a specific href
expect(page).not_to have_link('link text', href: '...')
Note: that checks there is not a link with both the given text and the given href, there could still be links with the text or the href
I have set up guard following Michael's RoR Tutorials and intentionally wrote a test (on contact page title) so it fails. But Guard/RSpec tells me it passed and I am confused what's going on. This is my static_pages_spec.rb file:
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the content 'Welcome to the PWr App'" do
visit '/static_pages/home'
expect(page).to have_content('Welcome to the PWr App')
end
it "should have the title 'Home'" do
visit '/static_pages/home'
expect(page).to have_title("PWr | Home")
end
end
describe "Help page" do
it "should have the content 'Help'" do
visit '/static_pages/help'
expect(page).to have_content('Help')
end
it "should have title 'Help'" do
visit '/static_pages/help'
expect(page).to have_title("PWr | Help")
end
end
describe "About page" do
it "should have the content 'About me'" do
visit '/static_pages/about'
expect(page).to have_content('About Me')
end
it "should have title 'About Me'" do
visit '/static_pages/about'
expect(page).to have_title("PWr | About")
end
end
describe "Contact page" do
it "should have the content 'Contact'" do
visit '/static_pages/contact'
expect(page).to have_content('Contact')
end
it "should have title 'Contact'" do
visit '/static_pages/contact' do
expect(page).to have_title("FAIL")
end
end
end
end
And this is my contact.html.erb:
<% provide(:title, 'Contact') %>
<h1>Contact</h1>
<p1>
If you need to contact me just call the number below: </br>
+48 737823884
</p>
And results from my terminal:
18:43:57 - INFO - Running: spec/requests/static_pages_spec.rb
........
Finished in 0.08689 seconds
8 examples, 0 failures
Randomized with seed 55897
[1] guard(main)>
As you can see, in the spec file close to the end I have expect(page).to have_title("FAIL") and in the contact page html/erb I clearly have <% provide(:title, 'Contact') %> but the test passes. Why is this? What am I doing wrong?
The problem is that you are passing your expectation as a block to the visit method - ie notice the extra do-end. I do not believe that visit uses blocks, so basically that bit of code gets ignored.
it "should have title 'Contact'" do
visit '/static_pages/contact' do
expect(page).to have_title("FAIL")
end
end
Your spec should behave as expected if you remove the block.
it "should have title 'Contact'" do
visit '/static_pages/contact'
expect(page).to have_title("FAIL")
end
Getting the following errors when I run 'bundle exec rspec spec/requests/static_pages_spec.rb:
9 examples, 2 failures
Failed examples:
rspec ./spec/requests/static_pages_spec.rb:56 # Static pages Contact page should have the title 'Contact page'
rspec ./spec/requests/static_pages_spec.rb:51 # Static pages Contact page should have the content 'Contact page'
I can't figure out how to get the two tests to pass here.
Trying to get through the tutorial here, learning, very new (I believe this is the code):
describe "Contact page" do
it "should have the content 'Contact'" do
visit '/static_pages/contact'
expect(page).to have_content('Contact')
end
it "should have the title 'Contact'" do
visit '/static_pages/contact'
expect(page).to have_content("Ruby on Rails Tutorial Sample App | Contact")
end
end
end
Additionally, the html file:
<% provide(:title, 'Contact') %>
<h1>Contact</h1>
<p>
Contact Ruby on Rails Tutorial about the sample app at the
contact page.
</p>
You're expecting the title with have_content and expecting the content with have_title.
Try
expect(page).to have_title('Contact')
and
expect(page).to have_content("Ruby on Rails Tutorial Sample App | Contact")
Actually you need to reword this last one a little because this is not the content you have in the view but you get the idea.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Rspec test should pass but fails
Why am I getting this error?
C:\Sites\sample_app>rspec
?[32m.?[0m?[31mF?[0m?[32m.?[0m?[31mF?[0m?[32m.?[0m?[31mF?[0m
Failures:
1) PagesController GET 'home' should have the right title
?[31mFailure/Error:?[0m ?[31mresponse.should have_selector("title",?[0m
?[31mNoMethodError:?[0m
?[31mundefined method has_selector?' for #<ActionController::TestResponse:0x4162ce0>?[0m
?[36m # ./spec/controllers/pages_controller_spec.rb:14:inblock (3 levels) in '?[0m
2) PagesController GET 'contact' should have the right title
?[31mFailure/Error:?[0m ?[31mresponse.should have_selector("title",?[0m
?[31mNoMethodError:?[0m
?[31mundefined method has_selector?' for #<ActionController::TestResponse:0x3eab898>?[0m
?[36m # ./spec/controllers/pages_controller_spec.rb:27:inblock (3 levels) in '?[0m
3) PagesController GET 'about' should have the right title
?[31mFailure/Error:?[0m ?[31mresponse.should have_selector("title",?[0m
?[31mNoMethodError:?[0m
?[31mundefined method has_selector?' for #<ActionController::TestResponse:0x3f1ccb0>?[0m
?[36m # ./spec/controllers/pages_controller_spec.rb:41:inblock (3 levels) in '?[0m
Finished in 5.15 seconds
?[31m6 examples, 3 failures?[0m
Failed examples:
?[31mrspec ./spec/controllers/pages_controller_spec.rb:12?[0m ?[36m# PagesController GET 'home' should have the right title?[0m
?[31mrspec ./spec/controllers/pages_controller_spec.rb:25?[0m ?[36m# PagesController GET 'contact' should have the right title?[0m
?[31mrspec ./spec/controllers/pages_controller_spec.rb:39?[0m ?[36m# PagesController GET 'about' should have the right title?[0m
Randomized with seed 501
Application_helper.rb
module ApplicationHelper
# Retrun a title on a per-page basic.
def title
base_title = "Ruby on Railys tut sample app"
if #title.nil?
base_title
else
"#{base_title} | #{#title}"
end
end
end
Pages_controller_spec.rb
require 'spec_helper'
describe PagesController do
render_views
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 => "Ruby on Rails Tutorial Sample App | Home")
end
end
describe "GET 'contact'" do
it "should be successful" do
get 'contact'
response.should be_success
end
it "should have the right title" do
get 'contact'
response.should have_selector("title",
:content =>
"Ruby on Rails Tutorial Sample App | Contact")
end
end
describe "GET 'about'" do
it "should be successful" do
get 'about'
response.should be_success
end
it "should have the right title" do
get 'about'
response.should have_selector("title",
:content =>
"Ruby on Rails Tutorial Sample App | About")
end
end
end
If you need something else just add and thanks
You need the base_title method to return the exact string you are testing for. In this case "Ruby on Rails Tutorial Sample App". Currently you have it setting the title as "Ruby on Railys tut sample app".
I'm creating a multilanguage CMS with Rails, Rspec (for test) and capybara.
the problem appear when i wrote this test
it "redirect and create a new post" do
visit posts_path
create_new_post = I18n.t('posts.index.create_new_post')
click_link create_new_post
current_path.should == new_post_path
end
problem is in last line and i got this
expected: "/posts/new"
got: "/en/posts/new" (using ==)
i want to use something like "new_post_path", not "/en/posts/new"
the main problem depicted when i use something like this
it "redirect to show link" do
visit posts_path
page.should have_content 'show'
click_link 'show'
current_path.should == post_path(#post)
end
any help is appreciate.
Check this StackOverflow question for some ideas on this subject. My preferred way is this answer on the same question. But, using your current code, to get your expectations right you would perhaps do something like this (assuming you want to test all of your locales):
I18n.available_locales.each do |locale|
it "should redirect and create a new post" do
visit posts_path(locale)
create_new_post = I18n.t('posts.index.create_new_post')
click_link create_new_post
current_path.should == new_post_path(locale)
end
it "should redirect to show link" do
visit posts_path(locale)
page.should have_content 'show'
click_link 'show'
current_path.should == post_path(locale, #post)
end
end