I've got a problem with Factory bot and logging in as a designated user. I'm trying to run a simple Edit test in rspec. Here it is:
require "rails_helper"
RSpec.describe "Treat management", :type => :system do
before do
treat = FactoryBot.create(:treat)
user = build(:user, email: 'wojtek@gmail.com', password: 'password')
login_as(user)
driven_by(:selenium_chrome_headless)
end
it "enables me to edit treats" do
visit root_path
click_button 'Edit'
fill_in 'Name', with: 'A new name'
fill_in 'Content', with: 'A new content'
click_button "Update Treat"
expect(page).to have_text("Treat was edited successfully")
end
end
And here is my Treat factory. Treats have a name, content and a giver and a receiver foreign keys
FactoryBot.define do
factory :treat do
name {'my first factory treat'}
content {'this is my first treat created by a factory'}
giver factory: :user
receiver factory: :user
end
end
And of course the user factory. Users are defined by email and password
FactoryBot.define do
factory :user do
email {Faker::Internet.email}
password {'password'}
end
end
And you have to know the edit buttom is only present when the logged user is also the giver. I have asked around and supposedly my Treat factory is is well configured. Please help me solve this. If any other parts of code are required please let me know in comments and I'll update accordingly. And of course I know that there is a simplier way to write this test but the use of the factories is a requirement.
1
I have tried hardcoding the user in the factory (without the Faker gem) but that trigers the validation error - the email has been taken.
Right now FactoryBot.create(:treat)
will create a User
for giver
and User
for receiver
based on the Factory definition.
FactoryBot.define do
factory :treat do
name {'my first factory treat'}
content {'this is my first treat created by a factory'}
giver factory: :user # tells the factory to create a User from the User Factory
receiver factory: :user # tells the factory to create a User from the User Factory
end
end
You are calling this in your test but then creating a third user to test with
before do
treat = FactoryBot.create(:treat) # 2 users created
# changed to `create` since as @max pointed out `build` does not actually create a `User`
user = create(:user, email: 'wojtek@gmail.com', password: 'password') # third user
end
This third user is neither the giver
or receiver
of the Treat
which is why your test fails.
Instead you can override definitions in the Factory
by passing arguments to create. In this case you want the User
object under test to be the giver
of the Treat
so we can achieve this as follows (I used modified version of @max 's test scheme as it is the preferred way to set this up)
require "rails_helper"
RSpec.describe "Treat management", type: :system do
let(:user) { create(:user) }
before do
driven_by(:selenium_chrome_headless)
end
context 'A Treat#giver' do
let!(:treat) {create(:treat, giver: user)}
before do
login_as(user)
end
it "can edit Treats they've given" do
visit root_path
click_button 'Edit'
fill_in 'Name', with: 'A new name'
fill_in 'Content', with: 'A new content'
click_button "Update Treat"
expect(page).to have_text("Treat was edited successfully")
end
end
end
Here we replace the default creation of a "giver" user with the specific user returned by user
method defined in the let
block. This ensures that user == treat.giver
so that your test can succeed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.