Before block in Rspec test run after the context - ruby-on-rails

I'm migrating an app from rails 4 to rails 6 and the test are now broken.
I'm not so good in testing, i must improve, but I cannot understand why a before block run after the test.
require 'rails_helper'
RSpec.describe Admin::TrainingEmailsController, type: :controller do
describe "GET #create", :uses_mail do
context "with valid attributes" do
before(:each) do
binding.pry
end
describe "sends the value letter request email" do
binding.pry
it { expect(1+1).to eq(2) }
end
end
end
end
I add a couple of pry, and the when I run rspec "sends the value letter request email" run before the before block and so my ActionMailer::Base.deliveries.last is empty
I try with before, before(:all) and before(:each)

It doesn't.
describe block is not running a test yet. It's just defining it.
only it or specify blocks, when run are executing a test. Put binging.pry inside the it block to see it:
describe "sends the value letter request email" do
binding.pry
let(:mail) { ActionMailer::Base.deliveries.last }
let(:request_sender) { "ValueLetters#vl.balancedview.org" }
let(:accepted_participants_emails) do
training.participants.accepted.
map(&:email)
end
it do
binding.pry # <-- here
expect(mail.to).to match(accepted_participants_emails) }
end
end

Related

login_as works for first test only

I'm trying to write some system tests with RSpec but don't get the login_as doesn't work for the second test. It always fails because the user gets redirect to /login. Do I have to put the let! blocks elsewhere?
describe "Users" do
describe "dashboard" do
let!(:user_a) { create(:user, lastname: "Z") }
let!(:user_b) { create(:user, lastname: "A") }
before do
login_as(user_a)
puts "############"
puts "# this one prints a different user for each test"
puts user_a.to_json
puts "############"
visit "/users"
end
it "list users alphabetically" do # rubocop:disable RSpec/MultipleExpectations
expect(find_all('a[class^="Table__Row"]')[0].find_all('div[class^="Table__Column"]')[1]).to have_content(user_b.firstname)
expect(find_all('a[class^="Table__Row"]')[1].find_all('div[class^="Table__Column"]')[1]).to have_content(user_a.firstname)
end
it "list the right amount of users" do
expect(find_all('a[class^="Table__Row"]').length).to eq(2)
end
end
end
Any idea what could be wrong? I've set config.use_transactional_fixtures to true in my rails_helper.rb.
Maybe using before(:all) instead will solve your problem. Before without an argument means before(:each), as seen in before(:each) vs just before

Rspec before(:each) works but before(:all) does not

My ProductCategory spec:-
require 'rails_helper'
RSpec.describe ProductCategory, type: :model do
before(:each) do
#product_category = create(:product_category)
end
context "validations" do
it "should have valid factory" do
expect(#product_category).to be_valid
end
it "should have unique name" do
product_category_new = build(:product_category, name: #product_category.name)
expect(product_category_new.save).to be false
end
end
end
The spec runs fine, but when I use before(:all) instead of before(:each), second example fails -
expected false got true I know the difference between before(:all) and before(:each) but I am not able to find the exact reason why second example fails with before(:all)
before :all only runs once before all the examples, so the #product_category is created once. If you have a something like a DatabaseCleaner truncation running after each test, the record is no longer in the database in the second test, thus passing the validation.
before :each on the other hand will be run before each example, so the record will be there in the second example even if the database was cleaned in the meantime.

Rspec test with login devise just working one time

I'm trying to test some views with devise and rspec. In this test, the first one passes. The second is redirect to sign_in page.
The login_as just working in the first test.
If I add 3 tests the last fails and the first 2 passes.
If I change :all to :each the first one fails and the second passes
require 'rails_helper'
RSpec.describe StoresController, type: :controller do
context "with valid params" do
user = FactoryBot.build(:user)
before(:all) do
login_as(user, :scope => :user)
end
it "renders the index template" do
get :index
expect(response).to render_template("index")
end
it "creates a new store" do
get :new
expect(response).to render_template("new")
end
end
end
before(:all) will run only once. That's why only the first test pass.
Use before(:each) or simply before do
Also, the user variable should be created for each test, meaning that it should be declared inside the before block:
before do
user = FactoryBot.create(:user)
login_as(user, :scope => :user)
end

Why i can not get current_user while writing test case with Rspec and Capybara

I have to write integration test case for my one feature listing page and that feature index method has code like below
def index
#food_categories = current_user.food_categories
end
Now when i try to write a test case for this it throws an error
'undefined method features for nil class' because it can not get the current user
Now what i have do is below
I have write the login process in the before each statement and then write the test case for the features listing page
Can you please let me know that how i can get the current_user ?
FYI, I have used devise gem and working on integration test case with Rspec
Here is my spec file
And here is my food_categories_spec.rb
Update: you confuse functional and integration tests. Integration test doesn't use get, because there's no controller action to test, instead you must use visit (some url). Then you have to examine content of a page, not response code (latter is for functional tests). It may look like:
visit '/food_categories'
page.should have_content 'Eggs'
page.should have_content 'Fats and oils'
In case you'll need functional test, here's an example:
# spec/controllers/your_controller_spec.rb
describe YourController do
before do
#user = FactoryGirl.create(:user)
sign_in #user
end
describe "GET index" do
before do
get :index
end
it "is successful" do
response.should be_success
end
it "assings user features" do
assigns(:features).should == #user.features
end
end
end
# spec/spec_helper.rb
RSpec.configure do |config|
#...
config.include Devise::TestHelpers, :type => :controller
end

Clearing out ActionMailer::Base.deliveries after RSpec test

I have the following RSpec test for my UserMailer class:
require "spec_helper"
describe UserMailer do
it "should send welcome emails" do
ActionMailer::Base.deliveries.should be_empty
user = Factory(:user)
UserMailer.welcome_email(user).deliver
ActionMailer::Base.deliveries.should_not be_empty
end
end
This test passed the first time, but failed the second time I ran it. After doing a little bit of debugging, it appears that the 1st test added an item to the ActionMailer::Base.deliveries array and that item never got cleared out. That causes the first line in the test to fail since the array is not empty.
What's the best way to clear out the ActionMailer::Base.deliveries array after an RSpec test?
RSpec.describe UserMailer do
before do
# ActionMailer::Base.deliveries is a regular array
ActionMailer::Base.deliveries = []
# or use ActionMailer::Base.deliveries.clear
end
it "sends welcome email" do
user = create(:user)
UserMailer.welcome_email(user).deliver_now
expect(ActionMailer::Base.deliveries).to be_present
end
end
You can clear the deliveries after each test quite easily, adding this into your spec_helper.rb.
RSpec.configure do |config|
config.before { ActionMailer::Base.deliveries.clear }
end
I'd suggest reading my article about the correct emails configuration in Rails where I talk also about testing them correctly.
As Andy Lindeman points out, clearing the deliveries is done automatically for mailer tests. However, for other types, simply add , :type => :mailer to the wrapping block to force the same behavior.
describe "tests that send emails", type: :mailer do
# some tests
end

Resources