Rspec features macro wont work - ruby-on-rails

I created a macro for my create_post_spec.rb
rails v-5.2
ruby v-2.5.1
capybara v-3.2'
my macro
spec/support/features/session.rb
module Features
def sign_in(user)
visit new_user_session_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_on "Log in"
end
end
then include in my rails_helper
Rspec.confifure do |config|
config.include Feature, type: feature
end
in my
spec/feature/create_post_spec.rb
require "rails_helper"
RSpec.describe "Create post" do
let(:user){ User.create(email: "example#mail.com", password: "password",
password_confirmation: "password")}
scenario "successfuly creating post" do
sign_in user
visit root_path
click_on "Create post"
fill_in "Title", with: "Awesome title"
fill_in "Body", with: "My rspec test"
click_on "Publish"
expect(page).to have_current_path root_path
end
scenario "unsuccessful creating post" do
sign_in user
visit root_path
click_on "Create post"
fill_in "Title", with: "Awesome title"
fill_in "Body", with: ""
click_on "Publish"
expect(page).to have_css ".error"
end
scenario "non-logged in user cant create post" do
end
end
i get an undefined method sign_in,
But if i use "feature" in my block
RSpec.feature "Create post....." do
it works
i wonder why it won't work if i use "describe"
RSpec.describe "Create post....." do

The difference between RSpec.feature and Rspec.describe is that RSpec.feature adds type: :feature and capybara_feature: true metadata to the block. The important thing there is the type: :feature metadata since it's what you're using to trigger the include of your module. You can use describe by adding your own metadata
RSpec.describe "Create post", type: :feature do
...
end
or you can have RSpec automatically add the type based on the directory the spec file is in by changing the file directory to spec/features/xxx.rb (note the plural features) and ensuring
RSpec.configure.do |config|
config.infer_spec_type_from_file_location!
end
is enabled in your rails_helper - see https://relishapp.com/rspec/rspec-rails/docs/directory-structure

Related

Id path on capybara

I have a problem.
I'm trying to use capybara to do integration tests, but I can not get the id on my page for it to make the visit when I test the context "edit new tarefa". I'm using devise, so I create the user at the beginning of the code.
Below is the code:
require 'rails_helper'
describe "Tarefas", :type => :feature do
feature "New Tarefa" do
background do
user = FactoryGirl.create(:user)
login_as(user, :scope => :user)
end
context "create new tarefa" do
it "preenchendo os campos" do
visit '/tarefas/new'
within("#new_tarefa") do
fill_in 'tarefa_titulo', with: 'user#example.com'
fill_in 'tarefa_descricao', with: 'password'
fill_in 'tarefa_data', with: '18/06/1990 20:00'
end
click_button 'submit'
expect(page).to have_content 'Mostra a tarefa selecionada'
end
end
context "edit new tarefa" do
it "alterando os campos" do
visit "tarefas/#{Tarefa.last.id}/edit"
within("#new_tarefa") do
fill_in 'tarefa_titulo', with: 'user#exa12mple.com'
fill_in 'tarefa_descricao', with: 'passw213ord'
fill_in 'tarefa_data', with: '18/06/1990 21:00'
end
click_button 'submit'
expect(page).to have_content 'Mostra a tarefa selecionada'
end
end
end
end
You should not rely on the tarefa you have created in "create new tarefa" to be available in you next spec as:
It won't work since the ordering is random.
It would create a coupling where one spec relies on the outcome of another.
Instead you want to use database_cleaner to clean out the DB after each spec and use let and let! to setup the requirements for each spec:
require 'rails_helper'
# You can use `feature` as a top level block.
# No need to nest it in descibe.
RSpec.feature "New Tarefa" do
let(:user) { FactoryGirl.create(:user) }
let(:tarefa) { FactoryGirl.create(:tarefa) }
background do
login_as(user, scope: :user)
end
context "create new tarefa" do
it "preenchendo os campos" do
visit '/tarefas/new'
within("#new_tarefa") do
fill_in 'tarefa_titulo', with: 'user#example.com'
fill_in 'tarefa_descricao', with: 'password'
fill_in 'tarefa_data', with: '18/06/1990 20:00'
end
click_button 'submit'
expect(page).to have_content 'Mostra a tarefa selecionada'
end
end
context "edit new tarefa" do
it "alterando os campos" do
# tarefa is created when you reference it.
visit "tarefas/#{tarefa.to_param}/edit"
within("#new_tarefa") do
fill_in 'tarefa_titulo', with: 'user#exa12mple.com'
fill_in 'tarefa_descricao', with: 'passw213ord'
fill_in 'tarefa_data', with: '18/06/1990 21:00'
end
click_button 'submit'
expect(page).to have_content 'Mostra a tarefa selecionada'
end
end
end

How to use RSpec and FactoryGirl for simple sign in

I just started using factory_girl and I tried using:
user = FactoryGirl.create(:user)
but that doesn't seem to work. Here is my code:
RSpec.feature "Send a message" do
scenario "Staff can send a message" do
visit "/"
group = Group.create!(name: "Group A")
user = FactoryGirl.create(:user)
fill_in "Email", with: "staff#example.com"
fill_in "Password", with: "password"
click_button "Sign in"
person = Person.create!(groups: [group], phone_number: "+161655555555")
message = Message.create(body: "Test Message", group_ids: [group.id])
fill_in "Enter a Message:", with: "Test Message"
check "message_group_#{group.id}"
click_button "Send Message"
expect(page).to have_content("Messages on their way!")
expect(page).to_not have_content("Body can't be blank")
expect(page).to_not have_content("Group ids can't be blank")
end
Here is my factory:
FactoryGirl.define do
factory :user do
email "cam#example.com"
password "password"
end
end
Simple right? What could be going wrong?
user = FactoryGirl.create(:user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
Also, if you use devise, you can add next lines to spec/support/warden.rb and use method login_as(user) instead of submitting login form.
RSpec.configure do |config|
config.include Warden::Test::Helpers, type: :feature
config.include Warden::Test::Helpers, type: :request
config.before :suite do
Warden.test_mode!
end
config.after :each do
Warden.test_reset!
end
end

How to factor Capybara rspec testing code?

I need to test a system in which everything is available only after a user is signed in using Devise. Every time I use "it" I have to include the signup code.
Is there a way to factor the code below so that the "let's me make a new post" test and similar tests won't have to include the sign up?
describe "new post process" do
before :all do
#user = FactoryGirl.create(:user)
#post = FactoryGirl.create(:post)
end
it "signs me in" do
visit '/users/sign_in'
within(".new_user") do
fill_in 'Email', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_button 'Log in'
expect(page).to have_content 'Signed in successfully'
end
it "let's me make a new post" do
visit '/users/sign_in'
within(".new_user") do
fill_in 'Email', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_button 'Log in'
visit '/posts/new'
expect( find(:css, 'select#post_id').value ).to eq('1')
end
end
Your first option is to use the Warden methods provided, as per the documentation on this page:
https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara
Your second option is just to login for real in your tests as you have done in your examples. You can streamline this though by creating some helper methods to do the login work rather than duplicating the code in all of your tests.
To do this, I would create a support directory within your spec directory, and then a macros directory within that. Then create a file spec/support/macros/authentication_macros.rb:
module AuthenticationMacros
def login_as(user)
visit '/users/sign_in'
within('.new_user') do
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
end
click_button 'Log in'
end
end
Next, update your RSpec config to load your macros. In either spec_helper.rb or rails_helper.rb if you're using a newer setup:
# Load your support files
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Include the functions defined in your modules so RSpec can access them
RSpec.configure do |config|
config.include(AuthenticationMacros)
end
Finally, update your tests to use your login_as function:
describe "new post process" do
before :each do
#user = FactoryGirl.create(:user)
#post = FactoryGirl.create(:post)
login_as #user
end
it "signs me in" do
expect(page).to have_content 'Signed in successfully'
end
it "let's me make a new post" do
expect( find(:css, 'select#post_id').value ).to eq('1')
end
end
Obviously, make sure you have password defined in your user factory.

Undefined method "Get" and "Let" with Rspec 3 - rails 4

I've decided to start a new project using the new Rspec 3 (+ capybara/factory_girl) and am having trouble learning the new syntax. Right now I have
user_pages_spec.rb (Feature)
scenario "Signing Up" do
let(:submit) { "Sign up" }
scenario "With valid information" do
background do
fill_in "Username", with: "example"
fill_in "Email", with: "example#example.com"
fill_in "Password", with: "foobar123"
fill_in "Password confirmation", with: "foobar123"
end
scenario "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
Fails with undefined method 'let'. And:
static_pages_spec.rb (controller)
describe StaticPagesController do
describe "GET 'home'" do
it "returns http success" do
get :home
expect(response).to be_success
end
end
end
with "undefined method 'get'. (This is just the default controller spec)
When upgrading existing project from RSpec 2.x to 3.0 had same problem.
It was fixed for me with an explicit setting of the type.
Could you try this:
describe StaticPagesController, type: :controller do
EDIT:
I found now that the more structural cause and solution is that
in RSpec 3, I needed to add:
config.infer_spec_type_from_file_location!
in the config block in spec_helper.rb
You are getting undefined method let because capybara defines scenario an alias of it and feature as alias of describe. However, let is available in an example group context (a describe or context block) but not an individual example (and it block). So your example is equivalent to:
it "Signing Up" do
let(:submit) { "Sign up" }
it "With valid information" do
background do
fill_in "Username", with: "example"
fill_in "Email", with: "example#example.com"
fill_in "Password", with: "foobar123"
fill_in "Password confirmation", with: "foobar123"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
...but should be:
feature "Signing Up" do
let(:submit) { "Sign up" }
context "With valid information" do
background do
fill_in "Username", with: "example"
fill_in "Email", with: "example#example.com"
fill_in "Password", with: "foobar123"
fill_in "Password confirmation", with: "foobar123"
end
scenario "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
Or, if you want to stick with pure RSpec constructs (rather than the capybara aliases):
describe "Signing Up" do
let(:submit) { "Sign up" }
context "With valid information" do
before do
fill_in "Username", with: "example"
fill_in "Email", with: "example#example.com"
fill_in "Password", with: "foobar123"
fill_in "Password confirmation", with: "foobar123"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end

Keeping user in the database between tests using Capybara?

My issue is that I have to create a new user and login for each individual capybara test.
An example is below:
require 'spec_helper'
describe "users" do
describe "user registration" do
it "should create a new user and log in" do
# Register a new user to be used during the testing process
visit signup_path
fill_in 'Email', with: 'testuser'
fill_in 'Password', with: 'testpass'
fill_in 'Password confirmation', with: 'testpass'
click_button 'Create User'
current_path.should == root_path
page.should have_content 'Thank you for signing up!'
end
end
describe "user login" do
it "should log in" do
# log in
visit login_path
fill_in 'Email', with: 'testuser'
fill_in 'Password', with: 'testpass'
click_button 'Log In'
current_path.should == root_path
page.should have_content 'Logged in!'
end
end
end
The login test fails because the user no longer exists in the database for that test.
This could be fixed simply by putting both in one test, but I believe that is bad practice.
Also I have another file which currently is registering and logging in between each test using a before_do, which also seems to be quite bad... you can see that code here.
For the record this is my first rails app so perhaps I am trying to do this the wrong way. I would like to dry it up as much as possible..
Is capybara really this bad to use on pages that require user login?
I have done it this way.
require "spec_helper"
describe "Users" do
subject { page }
describe "User Registration" do
before { visit signup_path }
let(:submit) { "Sign up" }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
end
describe "with valid information" do
before do
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar12"
fill_in "Password confirmation", with: "foobar12"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after registration" do
before { click_button submit }
it { should have_content 'Thank you for signing up!' }
end
describe "after registration signout and login" do
let(:user) { User.find_by_email('user#example.com') }
before do
click_button submit
visit signout_path
sign_in user # sign_in is a method which u can define in your spec/support/utilities.rb . Define once and use at multiple places.
end
it { should have_content 'Logged In!' }
it { should have_link('Logout') }
end
end
end
end
# spec/support/utilities.rb
def sign_in(user)
visit sign_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
end
your every describe and it block will run after the before block in parent that's why we need to click_button in every block in above test cases.

Resources