Rspec: click_link in email body - ruby

I have feature spec test:
describe "Reset password" do
let(:last_email) { ActionMailer::Base.deliveries.last }
it "should be success" do
# ...
page.should have_content t("users.passwords.sent")
last_email.to.first.should eq user.email
last_email.body.should have_content t("mail.body.recovery_instructions")
# Here is click_link
page.should have_content t("passwords.updated")
end
end
How I can click link which is located in last_email.body ?

You can try something like this:
link = last_email.body.raw_source.match(/href="(?<url>.+?)">/)[:url]
visit link

Related

how can i always focus to page using capybara

I am working on testing rspec and using capybara for interact with form.
I have a problem when i run my file spec if i not focus to page i couldn't submit the form and got the 400 error code so how can focus to page when fill_in text box or click button.
here is the error code
"status": 400,
"result": {
"error": "Grabbing app data from app store failed. Please try again."
}
here is my code interact with form
select_visible(#state, "form label[for='state']+div.field a.chosen-single")
select_visible(#platform, "form label[for='platform']+div.field a.chosen-single")
if #appstore_search != nil && #appstore_search != ""
page.find("#autocomplete_chosen a").click
page.find("#autocomplete_chosen div.chosen-drop div.chosen-search input[type='text']").set(#appstore_search)
if page.has_css?("#autocomplete_chosen ul.chosen-results li.active-result")
page.find("#autocomplete_chosen ul.chosen-results li:nth-child(3)").click
else
fill_in('name', :with => #appstore_search)
end
else
fill_in('name', :with => #name)
end
click_button 'Save'
if page.find("form label[for='platform']+div")[:class].include?("field invalid")
#warning_platform = page.find("form label[for='platform']+div.field.invalid aside.error-message").text
puts #warning_platform
end
if page.find("form label[for='name']+div")[:class].include?("field invalid")
#warning_name = page.find("form label[for='name']+div.field.invalid aside.error-message").text
puts #warning_name
end
if page.has_css?('#alerts ul li')
#message = page.find("#alerts ul li").text
puts #message
end
Please help me fix this problem or suggest me other solution.

How to include shared examples without subject

I am using RSpec and Capybara. I want to test navigation panel with click_link with shared examples for concrete pages. But I can't use it_should_behave_like because I don't want to change subject after clicking links. Is there any way to include a shared example with expect(page).to?
EDIT:
Here is my code:
require 'spec_helper'
describe "SomeController" do
subject { page }
content_list = {
home: 'Some text on the home page',
about: 'Some text on the about page',
order: 'Some text on the order page'
}
shared_examples_for 'with layout' do
it { should have_content 'Some text on the layout' }
it { should have_title 'Title' }
end
describe 'Home page' do
before { visit root_path }
it_should_behave_like 'with layout'
it { should have_content content_list[:home] }
end
describe 'About page' do
before { visit about_path }
it_should_behave_like 'with layout'
it { should have_content content_list[:about] }
end
describe 'Order page' do
before { visit order_path }
it_should_behave_like 'with layout'
it { should have_content content_list[:order] }
end
it 'should have correct links on the layout' do
visit root_path
click_link 'Some link text'
expect(page).to have_content content_list[:about]
find('.logoLink').click
expect(page).to have_content content_list[:home]
click_link 'Another link text'
expect(page).to have_content content_list[:about]
click_link 'One more link text'
expect(page).to have_content content_list[:order]
end
end
I am checking the same things when visiting pages with route names and when visiting them clicking. I wanted to refactor it.
it_should_behave_like doesn't implicitly change the subject, so you shouldn't have a problem per se.
For example, the following passes:
shared_examples "so" do
it "should have access to variables from calling rspec scope" do
expect(subject).to eql("foo")
expect(page).to eql("bar")
end
end
describe "so test" do
let(:subject) {"foo"}
let(:page) {"bar"}
it_should_behave_like "so"
end
Given the code you shared, it's possible to reduce some duplication by passing a parameter to the shared example you have and introducing variables for each page's content. You can also make use of a lambda function to reduce duplication in the big, sequential example you have at the end. These techniques are shown below (not tested):
require 'spec_helper'
describe "SomeController" do
subject { page }
content_list = {
home: 'Some text on the home page',
about: 'Some text on the about page',
order: 'Some text on the order page'
}
home_content = content_list[:home]
about_content = content_list[:about]
order_content = content_list[:order]
shared_examples_for 'with layout' do |content|
it { should have_content 'Some text on the layout' }
it { should have_title 'Title' }
it { should have_content content }
end
describe 'Home page' do
before { visit root_path }
it_should_behave_like 'with layout', home_content
end
describe 'About page' do
before { visit about_path }
it_should_behave_like 'with layout', about_content
end
describe 'Order page' do
before { visit order_path }
it_should_behave_like 'with layout', order_content
end
it 'should have correct links on the layout' do
click_and_expect = lambda do |link_text, content|
click_link link_text
expect(page).to have_content content
end
visit root_path
click_and_expect['Some link text', about_content]
find('.logoLink').click
expect(page).to have_content home_content
click_and_expect['Another link text', about_content]
click_and_expect['One more link text', order_content]
end
end
However, to respond to one of your comments, I don't know how to easily eliminate the conceptual duplication between the should have_content content in the shared example and the expect(page).to have_content content in the final example. You can replace the former code with the latter code, since page is defined in both cases, but that still leaves you with the duplication of that string.
If you're willing to break up the sequential example at the end into a series of independent examples, then you can use a shared example across both. As is, though, the only way I know to share that code is through an eval of the same string.

Ruby on Rails 3 Tutorial gravatar_for test error

So I am working through the Ruby on Rails 3 Tutorial. I am currently on section 7.1.3 Testing the User show page using factories.
The code is working and pulls the proper gravatar image however I keep getting an error when running my tests.
Here is the error:
Failure/Error: before { visit user_path(user) }
ActionView::Template::Error:
undefined method `downcase' for nil:NilClass
Here is the code from the show.html.erb file:
<% provide(:title, #user.name) %>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
<%= #user.name %>, <%= #user.email %>
Here is the code from the users_helper.rb file:
module UsersHelper
# Returns the Gravatar (http://gravatar.com/) for the given user.
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
Here is the code from factories.rb file:
FactoryGirl.define do
factory :user do
name "Curtis Test"
email "test#gmail.com"
password "foobar"
password_confirmation "foobar"
end
end
Here is the code from the test file user_pages_spec.rb
require 'spec_helper'
describe "User Pages" do
subject { page }
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
it { should have_selector('h1', text: user.name) }
it { should have_selector('title', text: user.name) }
end
describe "signup page" do
before { visit signup_path }
it { should have_selector('title', text: full_title('Sign Up')) }
end
end
I discovered my problem. It had nothing to do with FactoryGirl. The problem was in my user model (user.rb), the line that was causing the issue was
before_save { |user| user.email = user.email.downcase! }
The bang after the downcase was causing the email address to be saved as nil since the return of the downcase! is nil. Once I removed that and made the line look like the following it worked just fine.
before_save { |user| user.email = user.email.downcase }
The way I found it was to load the rails console in test environment and tried to create a new user. I noticed that everything was fine but the email was null.
In general, you can debug issues such as this one by referring to the Rails Tutorial sample app reference implementation.

Ruby on Rails RSpec put method doesn't see signed in user

so I've been using Michael Hartl's tutorial for some time and I can say it's really useful but there's a problem and I gues it's not on the tutorial's part. So in chapter "9.2.2 Requiring the right user" ther's a test for checking that a user can access neither other user's edit page nor submit a direct PUT reauest.
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong#example.com") }
before { sign_in user }
describe "visiting Users#edit page" do
before { visit edit_user_path(wrong_user) }
it { should_not have_selector('title', text: full_title('Edit user')) }
end
describe "submitting a PUT request to the Users#update action" do
before { put user_path(wrong_user) }
specify { response.should redirect_to(root_path) }
end
end
So long all seems right but the test fails:
1) Authentication authorization as wrong user submitting a PUT request to the Users#update action ←[31mFailure/Error:←[0m ←[31mspecify { response.should redirect_to(root_path }←[0m←[31mExpected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/signin>←[0m←[36m # ./spec/requests/authentication_pages_spec.rb:107:in `block (5 levels) in <top (required)>'←[0m
Here's the User controller:
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update]
before_filter :correct_user, only: [:edit, :update]
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
private
def signed_in_user
unless signed_in?
puts "No user signed in"
store_location
redirect_to signin_path, notice: "Please sign in."
end
end
def correct_user
#user = User.find(params[:id])
puts "Incorrect user" unless current_user?(#user)
redirect_to(root_path) unless current_user?(#user)
end
end
So as you can see the problem is that when using RSpec put method, the test fails even before checking for the right user because it sees ther's no user signed in.
This is a small problem which can easily be omitted (incorrect user cannot make direct PUT request anyway) but it's a puzzle for me why doesn't it work correct and I can't get the answer for quite a time already.
It looks like the signed_in_user filter is redirecting back to the sign in page before the correct_user fires. That suggests that the user is not actually signed in correctly by the sign_in user call in the before block.
Have you defined sign_in in 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"
# Sign in when not using Capybara as well.
cookies[:remember_token] = user.remember_token
end

Rails Tutorial Chapter 7, Exercise 4 [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm having trouble with Exercise 4 in Chapter 7 of railstutorial.org.
Here are the tests:
describe "signup" do
before { visit signup_path }
describe "with invalid information" do
it "should not create a user" do
expect { click_button "Create my Account".not_to change(User, :count) }
end
end
describe "error messages" do
before { click_button "Create my account" }
it { should have_selector('title', text: "Sign up") }
it { should have_content('error') }
end
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
it "should create a user" do
expect do
click_button "Create my account"
end.to change(User, :count).by(1)
end
end
describe "after saving the user" do
before { click_button "Create my account" }
let(:user) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
end
end
Here is what it's supposed to test, users_controller.rb:
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
Here's the show.html.erb code as well:
<% provide(:title, #user.name) %>
<div class="row">
<aside class="span4">
<section>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</section>
</aside>
</div>
When I run my tests, I get this:
$ bundle exec rspec spec/requests/user_pages_spec.rb
........FF
Failures:
1) User Pages signup after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:57:in `block (4 levels) in <top (required)>'
2) User Pages signup after saving the user
Failure/Error: it { should have_selector('div.alert.alert-success', text: 'Welcome') }
expected css "div.alert.alert-success" with text "Welcome" to return something
# ./spec/requests/user_pages_spec.rb:58:in `block (4 levels) in <top (required)>'
Finished in 0.86152 seconds
10 examples, 2 failures
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:57 # User Pages signup after saving the user
rspec ./spec/requests/user_pages_spec.rb:58 # User Pages signup after saving the user
It should save the test user to the test db, but for some reason, user.name is turning out nil. Any ideas?
Thank you!
Without going over your code in detail to understand the context of everything, it's not that user.name is returning nil, it's that user is nil, and therefore has no method/property name as seen here:
undefined method `name' for nil:NilClass
You have this line here before the test case defining the symbol :user:
let(:user) { User.find_by_email('user#example.com') }
yet you reference the object user in your test:
it { should have_selector('title', text: user.name) }
Change the symbol :user to user in the former and your tests should pass.

Resources