I have a pretty simple user scaffold pages and some tests on them.
it 'update' do
visit '/users/new'
fill_in 'user[login]', with: 'login'
fill_in 'user[password]', with: 'password'
click_on 'Create User'
expect do
visit '/users/1/edit'
fill_in 'user_login', with: 'login'
fill_in 'user_password', with: 'password256'
click_on 'Update User'
# p User.all
end.to change { User.find_by(login: 'login').password }
end
In 10% probability (I'm also inclined to speculate that this might be due to the chrome window losing focus) I've got an error:
2) Users user update
Failure/Error:
expect do
visit '/users/1/edit'
fill_in 'user_login', with: 'login'
fill_in 'user_password', with: 'password256'
click_on 'Update User'
# p User.all
end.to change { User.find_by(login: 'login').password }
NoMethodError:
undefined method `password' for nil:NilClass
end.to change { User.find_by(login: 'login').password }
^^^^^^^^^
And screenshot by Capybara
With message from console by p Users.all
#<ActiveRecord::Relation [#<User id: 1, login: "loginlogin", password: [FILTERED], created_at: "2022-12-24 18:36:57.938067000 0000", updated_at: "2022-12-24 18:36:58.270584000 0000">]>
Source form is
<%= form_with(model: user) do |form| %>
<% if user.errors.any? %>
<div style="color: red">
<h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% user.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= form.label :login, style: "display: block" %>
<%= form.text_field :login %>
</div>
<div>
<%= form.label :password, style: "display: block" %>
<%= form.password_field :password %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
I've already tried to add sleep above and below every fill_in command, but it hadn't helped. Also i've tried to add
fill_options: { clear: true }
as fill_in parameter.
CodePudding user response:
The doubling up of form contents is generally caused by a bug in the chrome driver. One workaround when you experience it is to specify fill_options: { clear: :backspace }
to fill_in. Another likely issue here is that you're not letting the user get created sometimes. click_on 'Create User'
returns immediately after clicking on the button (or link) and doesn't wait for any behavior that click triggers. Because of this it's possible that immediately calling visit '/users/1/edit'
after it will end up cancelling the form submission you're using to create the user in the first place. Best practice is to expect on whatever change would occur in the page after the user is created before moving on to visit the new url. So something like
...
fill_in 'user[login]', with: 'login', fill_options: { clear: :backspace }
fill_in 'user[password]', with: 'password', fill_options: { clear: :backspace }
click_on 'Create User'
expect(page).to have_text('User created')
expect do
visit '/users/1/edit'
fill_in 'user_login', with: 'login'
...
Another thing to note is that unless this is always the first test run it's highly unlikely for the user to have an id of 1
so hardcoding urls like that isn't really going to work well as your test suite grows.