Rails RSpec form datepicker and select failing test assertion - ruby-on-rails

I'm getting to grips with testing in rails, and I've been following this tutorial.
However, unlike the tutorial in my form I have a date select field. This seems to be causing a problem where the assert_select doesn't recognise it, and so the test is failing.
The code in new.html.erb_spec:
RSpec.describe "aquatics/new", type: :view do
current_user = User.first_or_create!(email: 'me#mail.com', password: 'password', password_confirmation: 'password')
before(:each) do
assign(:aquatic, Aquatic.new(
nick_name: "nickname",
common_name: "common name",
scientific_name: "scientific name",
sex: 'male',
purchased_on: '2022-02-02',
length: 10,
max_lifespan: 5,
user: current_user,
notes: "These are the testing notes"
))
end
it "renders new aquatic form" do
render
assert_select "form[action=?][method=?]", aquatics_path, "post" do
assert_select "input[name=?]", "aquatic[nick_name]"
assert_select "input[name=?]", "aquatic[common_name]"
assert_select "input[name=?]", "aquatic[scientific_name]"
assert_select "input[name=?]", "aquatic[purchased_on]"
assert_select "input[name=?]", "aquatic[sex]"
assert_select "input[name=?]", "aquatic[length]"
assert_select "input[name=?]", "aquatic[max_lifespan]"
assert_select "input[name=?]", "aquatic[notes]"
end
end
end
The failure:
1) aquatics/new renders new aquatic form
Failure/Error: assert_select "input[name=?]", "aquatic[purchased_on]"
Minitest::Assertion:
Expected at least 1 element matching "input[name="aquatic[purchased_on]"]", found 0..
Expected 0 to be >= 1.
# ./spec/views/aquatics/new.html.erb_spec.rb:26:in `block (3 levels) in <main>'
# ./spec/views/aquatics/new.html.erb_spec.rb:22:in `block (2 levels) in <main>'
I assume this is something to do with it being a selection field rather than an input, because if I comment out the purchased_on test line it throws the same error for the sex field.
I've tried changing the input[name=?] to date_select[name=?] and similar actions, but no luck. TIA.

date_select adds 3 select tags for Year, Month, and Date
You are verifying input tag, you should verify select tags.
date_select("aquatic", "purchased_on")
Above date_select will generate below html
<select id="aquatic_purchased_on_1i" name="aquatic[purchased_on(1i)]">
...
<option value="2021">2021</option>
<option value="2022" selected="selected">2022</option>
<option value="2023">2023</option>
...
</select>
<select id="aquatic_purchased_on_2i" name="aquatic[purchased_on(2i)]">
<option value="1">January</option>
<option value="2" selected="selected">February</option>
...
<option value="12">December</option>
</select>
<select id="aquatic_purchased_on_3i" name="aquatic[purchased_on(3i)]">
...
<option value="10">10</option>
<option value="11" selected="selected">11</option>
<option value="12">12</option>
...
</select>
You can verify it as below
assert_select "select[name=?]", "aquatic[purchased_on(1i)]"
assert_select "select[name=?]", "aquatic[purchased_on(2i)]"
assert_select "select[name=?]", "aquatic[purchased_on(3i)]"

Related

asserting value of selector

The following Minitest snippet
puts response.body.inspect
# assert response.body.include?("Log out of all other sessions")
assert_select "input[type='submit']" do
assert_select "[value=?]", "Log out of all other sessions"
end
is failing as Expected at least 1 element matching "[value="Log out of all other sessions"]", found 0..
Yet the inspection has the following string:
<form class=\"button_to\" method=\"post\" action=\"/active_sessions/destroy_all\">
<input type=\"hidden\" name=\"_method\" value=\"delete\" autocomplete=\"off\" />
<button type=\"submit\">Log out of all other sessions</button>
</form>
The value in the view is set via i18n:
<%= button_to t('user.auth.session_delete_all'), destroy_all_active_sessions_path, method: :delete %>
uncommenting assert response.body.include?("Log out of all other sessions") asserts.
How should the failing assertion be cast?

Capybara::ElementNotFound: Unable to find field "Key name"

I've read the similar questions to this but they don't solve my issue. I'm new with js testing so I think I might be doing something wrong.
The form produces this HTML
<form class="new_category_item_key" id="new_category_item_key" action="/guides/dungeon-boss/categories?category_id=heroes" accept-charset="UTF-8" data-remote="true" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="authenticity_token" value="b7wiF07zYh/Nl727M3y0Uk1TbroMJFuGqTK6fYNlNted/5G4Wmz4BZLb7IazzyP5md/wWRb1D28ePhrzt2uMSA==" />
<label for="category_item_key_name">Key name</label>
<input type="text" name="category_item_key[name]" id="category_item_key_name" />
<select name="category_item_key[key_type]" id="category_item_key_key_type"><option value="1">Value</option>
<option value="2">Text</option>
<option value="3">Image</option></select>
<input type="submit" name="commit" value="Add New Key" />
</form>
and I have the following integration test on the form
setup do
#user = users(:michael)
#user1 = users(:archer)
#guide = Guide.find(1)
#mod_relationship = game_mods_relationships(:mod1)
#category = Category.find(1)
Capybara.current_driver = Capybara.javascript_driver # :selenium by default
end
test "adding keys mod success then fail" do
log_in_as(#user)
get edit_guide_category_path(#guide, #category)
assert_template 'categories/edit'
assert_difference 'CategoryItemKey.count', 1 do
fill_in 'Key name', with: "diablo"
click_button "commit"
end
end
when I run the test I get the following error
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find field "Key name"
Looking at the HTML I can see the field is there. If I try using the inputs id it still fails, if I remove the fill in line then it says it cant find the button to click which is also there. I assume its getting the right page because get edit_guide_category_path(#guide, #category) works for the other tests (but they are non js tests and don't use selenium).
Its probably something simple but I cant get it.
You're mixing up two different libraries -- You can't use get with Capybara, you use visit(url) to go to the page. You also shouldn't normally be asserting templates in a feature test, thats for lower level tests.

Capybara fill_in isn't working

I'm working in Rails 4.2.1 and doing testing using Capybara 2.4. I have an issue with some input fields not getting filled in using the capybara fill_in method.
I'm not getting an ElementNotFound error, I'm getting this:
expected: "2018-01-10"
got: ""
(compared using ==)
Here's the test code:
Note: fill_in works for the email, password and program name fields but not for the primary_training_start, primary_comp_start and primary_comp_end.
it 'create program' do
visit '/'
fill_in 'Email', with: 'john#doe.com'
fill_in 'Enter Your Password', with: 'test123'
click_on 'Log In'
fill_in 'Program Name', with: 'My Training'
find('.exclusive').click
click_on 'Next Step'
all('.creator-wayfinder li')[1].click
expect(page).to have_content('SET THE SCHEDULE')
fill_in 'primary_training_start', with: '2018-01-10'
fill_in 'primary_comp_start', with: '2018-02-10'
fill_in 'primary_comp_end', with: '2018-03-10'
expect(find_field('primary_training_start').value).to eq('2018-01-10')
expect(find_field('primary_comp_start').value).to eq('2018-02-10')
expect(find_field('primary_comp_end').value).to eq('2018-03-10')
click_on 'Show Program Schedule'
end
And here's the HTML for the primary_training_start field:
<div>
<mark>Start Training</mark>
<span class="datepicker" date-format="M/d/yyyy" date-set="{{program.training_calendar_details.primary_training_start}}">
<input required
ng-model="program.training_calendar_details.primary_training_start"
name="primary_training_start"
type="text" tabbable tabindex="0" />
</span>
<errors for="primary_training_start" model="program.training_calendar_details.primary_training_start"></errors>
</div>
I tried this: Capybara won't fill in form fields (although it finds them) but didn't have any luck.
Try having an id for input
<input required
ng-model="program.training_calendar_details.primary_training_start"
name="program[training_calendar_details][primary_training_start]"
id="primary_training_start"
type="text" tabbable tabindex="0" />
fill_in use first parameter as id

Rails Capybara not seeing fields

I feel like I'm going insane here. Doing a routine capybara test of my Post model. Specifically, making sure the new page redirects to the newly created post after a valid submission. So in my spec/requests folder, I've got this:
describe "Valid post submission --" do
it "should log in a user and redirect to new post" do
# Sign in works find, so I won't reproduce it
# Make a blogpost
Post.destroy_all
fill_in :name_here, with: "Post Name Here"
fill_in :content_here, with: "This is the content of a really short post."
screenshot_and_open_image
click_on "Post It"
screenshot_and_open_image
puts current_path
page.should have_selector 'h2', text: "prohibited this post"
page.should have_selector 'h1', text: "Post Name Here"
page.should have_selector '.alert', text: "Post was successfully created."
page.should have_selector 'title', text: full_title('Post Name Here')
end
The screenshots and puts are there to clarify what's going on. There are basically two different cases. In
I just leave the fields be and test for the default IDs ("post_name"
and "post_content"); obviously the above test is for case two:
I change the field ids to "name_here" and "content_here" to test if
the label names or anything else is interfering. That's the one the spec of which is
above.
In case 2 the post is getting rejected because Capybara can't find either field.
In case 1, only the content would be empty, but the name field would be filled with the content.
The precise error in case 1 is:
2) Posts Invalid post - should refresh with error if content empty
Screenshot: /Users/myusername/rails/appname/tmp/capybara/screenshot_2013-03-14-22-37-36.634.png
Failure/Error: fill_in :post_name, with: "Post Name Here"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'post_name' found
# (eval):2:in `fill_in'
# ./spec/requests/posts_spec.rb:43:in `block (3 levels) in <top (required)>'
Case 2 doesn't throw an error about not finding the appropriate content, I believe because the label has that id as well.
This is ridiculous, because I took a snapshot of the HTML durin the test, just before it errors. Here's case 2 -- both cases look 90% the same here, apart from that ID difference:
<form accept-charset="UTF-8" action="/posts" class="new_post" id="new_post" method="post">
<div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"></div>
<div class="field">
<label for="post_name">Name</label>
<br><input id="name_here" name="post[name]" size="30" type="text">
</div>
<div class="field text-area">
<label for="post_content">Content</label>
<br><textarea cols="50" id="content_here" name="post[content]" rows="20"></textarea>
</div>
<div class="actions btn-group">
<input class="btn" name="commit" type="submit" value="Post It">
</div>
</form>
Note the clear existence of the post_content field. In cases where both fail (Case 1), there are both content_here and name_here fields. So the fields are there. And capybara is generally working (this sort of thing works find in other parts of my app). And the problem isn't a conflict with the label name, because putting a different id on the input fields doesn't help capybara find them.
By the way, this all works perfectly in reality.
Any idea at all what's going on here? I'm super frustrated/clueless.
UPDATE -- Following user2172816's advice, I changed my HAML so the HTML looks like this:
<form accept-charset="UTF-8" action="/posts" class="new_post" id="new_post" method="post">
<div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"></div>
<div class="field">
<label for="post_name">Name</label>
<br><input id="name" name="post[name]" size="30" type="text">
</div>
<div class="field text-area">
<label for="post_content">Content</label>
<br><textarea cols="50" id="content" name="post[content]" rows="20"></textarea>
</div>
<div class="actions btn-group">
<input class="btn" name="commit" type="submit" value="Post It">
</div>
</form>
The test now looks like this:
# Make a blogpost
Post.destroy_all
fill_in "Name", with: "Post Name Here"
fill_in "Content", with: "This is the content of a really short post."
page.should have_selector 'h2', text: "prohibited this post"
page.should have_selector 'h1', text: "Post Name Here"
page.should have_selector '.alert', text: "Post was successfully created."
page.should have_selector 'title', text: full_title('Post Name Here')
But it's still erroring (in new parts of the same spec, too!):
1) Posts Invalid post - should refresh with error if content empty
Screenshot: /Users/username/rails/appname/tmp/capybara/screenshot_2013-03-14-23-54-38.072.png
Failure/Error: fill_in :name, with: "Post Name Here"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'name' found
# (eval):2:in `fill_in'
# ./spec/requests/posts_spec.rb:43:in `block (3 levels) in <top (required)>'
2) Posts Invalid post - should refresh with error if name empty
Screenshot: /Users/username/rails/appname/tmp/capybara/screenshot_2013-03-14-23-54-38.274.png
Failure/Error: fill_in :name, with: ""
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'name' found
# (eval):2:in `fill_in'
# ./spec/requests/posts_spec.rb:33:in `block (3 levels) in <top (required)>'
3) Posts Valid post submission -- should log in a user and redirect to new post
Screenshot: /Users/username/rails/appname/tmp/capybara/screenshot_2013-03-14-23-54-38.459.png
Failure/Error: fill_in :name, with: "Post Name Here"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'name' found
# (eval):2:in `fill_in'
# ./spec/requests/posts_spec.rb:67:in `block (3 levels) in <top (required)>'
The attribute "for" of label should be the "id" of the input element, i.e.
<label for="name_here">Name</label>
<br><input id="name_here" name="post[name]" size="30" type="text">
And in the spec you should call:
fill_in 'Name', with: "Post Name Here"

Why would this functional test be failing?

My haml :
- for status in current_account.job_statuses.active
= link_to status.name, '#', :class => params[:job_status_id].to_i == status.id ? "current status block" : "status block", :rel => status.id
My html :
<a rel="1" class="status block" href="#">in progress</a>
<a rel="2" class="status block" href="#">in progress</a>
<a rel="3" class="status block" href="#">in progress</a>
<a rel="4" class="status block" href="#">in progress</a>
My Test :
test 'index - job_status: set' do
job_status = #account.job_statuses.create! :name => 'foo'
job_status.reload
#job.update_attribute :job_status_id, job_status.id
#job.reload
get :index, :job_status_id => job_status.id.to_s
assert_response :success
assert_template 'jobs/index'
jobs = assigns(:jobs)
assert jobs.include?(#job)
assert_select 'div.status[rel=?]', job_status.id
end
But I get this failure :
3) Failure:
test_index_-_job_status:_set(NewJobsControllerTest)
[test/functional/new_jobs_controller_test.rb:127:in `block in <class:NewJobsControllerTest>'
test/test_helper.rb:221:in `run'
test/test_helper.rb:221:in `run']:
Expected at least 1 element matching "div.status[rel='16']", found 0.
<false> is not true.
Is this for an obvious dumb reason? I apologize if it is.. I can't figure it out.
Oh. It's always the little things we never think to check... After staring uselessly at that HAML I asked for for five minutes it hit me:
Those ain't DIVs. Those are As.
Cheers!

Resources