6

I was wondering whether anybody tests fields that were dynamically added by cocoon?

It's a great little time saver but all of the fields that are added dynamically have really long numerics added to the ID and name. This means that I have to skip testing that requires more than one (set of) field(s) on the page.

Bryan Ash
  • 4,385
  • 3
  • 41
  • 57
DazBaldwin
  • 4,125
  • 3
  • 39
  • 43
  • The question is not entirely clear: you want to test the fields are present? You want to set the fields? – nathanvda Apr 21 '14 at 11:27
  • 1
    Hey Nathan, thanks for the gem! I was just struggling with locating anything generated dynamically by it due to the long numerics that get attached to said elements. For instance, clicking add fields would give something like `` on refresh these get set to their index in the ActiveRecord object but it was unclear how to find an element that had been added on the fly – DazBaldwin Apr 21 '14 at 12:15
  • I generally use the count, I count to see if a new child has been added (or removed), and using css selectors you can easily find the second (n-th) association. – nathanvda Apr 22 '14 at 08:21
  • out of curiosity, whet do the numerics correspond to? – DazBaldwin Apr 22 '14 at 15:40
  • I am sorry, I do not understand that question? – nathanvda Apr 22 '14 at 17:26
  • in the comment above, what does the long numerical string (1398082250289) mean? where does it come from? How is it generated? – DazBaldwin Apr 22 '14 at 18:00
  • It is just an identifier to make sure it gets a unique id. It is the same thing rails does. And it must not be mistaken with an existing id. – nathanvda Apr 23 '14 at 07:55

5 Answers5

8

Afaik you could test for two things:

  • that the dynamic addition of the nested elements works
  • creating elements, filling it in and storing them in the database

So assume the relevant part of your view looks like this (default example):

#tasks
  = f.semantic_fields_for :tasks do |task|
    = render 'task_fields', :f => task
  .links
    = link_to_add_association 'add task', f, :tasks

and your nested element looks like

.nested-fields
  = f.input :description
  = f.input :done, :as => :boolean
  = link_to_remove_association "remove task", f 

So normally you give it a class, i normally just test the count of elements on the page.

So if one element is already there, creating a new element, the count should be two. This you could test with

 find("#tasks .nested-fields").count.should == 2

Filling in the newly added nested element, you could use the :last-child css selector

 find("#tasks .nested-fields:last-child input#description").set("something")

How names and id are formed, are close to rails internals, so i try to stay away of those.

nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • Thanks again Nathan, This will undoubtably help me many times in the future – DazBaldwin Apr 23 '14 at 09:19
  • Your answer talks about `:last`, but uses `:last-child`. In my case, `:last` seemed to work while `:last-child` didn't. – Andrew Grimm Feb 29 '16 at 23:40
  • Weird :last-child is the correct css selector, while imho :last does not exist? Which driver are you using? – nathanvda Feb 29 '16 at 23:51
  • @nathanvda I was using Google Chrome. – Andrew Grimm Feb 29 '16 at 23:52
  • Ah - maybe what's valid within a JQuery statement in the JavaScript console is not valid for a `find` call in Capybara. But I'm still confused by you using `:last` in the text, and `:last-child` in the code. – Andrew Grimm Mar 01 '16 at 00:39
  • Yeah _that_ was a typo (which I fixed). Capybara `find` uses css-selectors by default, or xpath. Jquery should also support `:last-child`, but it also supports `:last` (which does not exist in css)([doc](https://api.jquery.com/last-child-selector/)) – nathanvda Mar 01 '16 at 08:27
4

Maybe using Capybara finders all, first and the selector input. Something like this:

visit new_resource_path
click_link "Add a Nested Resource"
first("input[name='nested_resource[name]']").set("Nested Resource")
click_button "submit"

Or

visit new_resource_path
click_link "Add a Nested Resource"
click_link "Add a Nested resource"
all("input[name='nested_resource[name]']").each do |input|
  input.set("Nested Resource")
end
click_button "submit

This is only an approach, I've never worked with cocoon. This is however, a form to test dynamic inputs.

DazBaldwin
  • 4,125
  • 3
  • 39
  • 43
Armando
  • 940
  • 7
  • 16
  • Thanks for this, I'd actually come across the finders in the past but hadn't seen them being used in context. Also, it's worth saying that if using webkit, it may be necessary to add a small `sleep` to allow the JS to load elements before looking for them. – DazBaldwin Apr 21 '14 at 09:55
1

Strange.

i have in the form (haml):

= link_to_add_association f, :staff_phases, class: :button, id: 'add-staff-phase-link' do
  %i.fas.fa-plus

and in my test

click_link 'add-staff-phase-link'
save_and_open_page

the click_link works but i can see no added association. if i, then on the opened page, click the link by mouse, the cocoon-link works and adds a association

chmich
  • 834
  • 9
  • 20
1

It might be common knowledge, but sharing this as it worked for me when dealing with a nested attribute that requires a select instead of a text input. I find all instances of my select fields, then pick the select field I want to updated with my preferred option like below:

page.find_all('select[id^="model_model_nested_attributes_"]')[2].select("preferred_option")

Ariel_RoR
  • 11
  • 1
  • 1
0

A possible alternate that I just used is to dynamically update the label of each added form field (using the technique mentioned in https://github.com/nathanvda/cocoon/issues/374) and now my Cucumber/Capybara tests can easily insert text into the different multiple form fields distinguishing them via the different labels they have.

Full details on what I did in this PR https://github.com/AgileVentures/WebsiteOne/pull/1818

Sam Joseph
  • 4,584
  • 4
  • 31
  • 47