Hi Jonathan - TLDR; the answer to all synchronization type issues is set an expectation for what on the page indicates it's ready for the next step
In more detail I'll explain why each of the things you tried didn't make any difference
- find("#{dropdown_id}").find(:option, nature).select_option instead of using the select matcher
This approach always confuses me, and if you can explain why you thought it would make a difference maybe I can use that to improve the documentation. If a higher level Capybara method is succeeding (the method call isn't erroring) then breaking the exact same behavior down into more basic things isn't going to change anything. That's how the higher level methods are implemented so why would you expect doing this to change anything?
- using expect statements to make sure the elements are present before interacting with them
Good thought but the elements are already there, otherwise the initial methods would have failed when trying to select
- increasing the Capybara default max wait time
This is the maximum wait time -- unless something was timing out then it's not going to make any difference allowing to wait longer because it's already finding everything it was asked to find
- using a
wait_for_ajax helper as implemented
here
Just no no no no no no - This is *never the right answer (* 99.99999% of the time)
- moving each select + attach_file within a using_wait_time block
This is just the same as increasing Capybara default max wait time - just locally - it increase before the block is run and resets it after
- checking that the dropdown was actually populated with options before selecting one; which it is.
Already known since the `select` call isn't failing
-----------------------------------
What you need to do between each of these file uploads is look for whatever on the page indicates the previous submission has completed. That could be a flash message, it could be a counter of how many files are already uploaded shown on the page, it could be a specific number of elements with a class that indicates the files are uploaded, etc
select nature1, from: dropdown_name1
attach_file(input_id1, test_file_path, visible: false)
expect(page).to have_text('File uploaded') # look for flash message that indicates the upload succeeded
expect(page).not_to have_text('File uploaded') # wait for the message to go away (so it's not still there after the next step
select nature2, from: dropdown_name2
attach_file(input_id2, test_file_path, visible: false)
...
Or if the page happened to render already uploaded files in divs with the class 'uploaded_file'
expect(page).not_to have_css('.uploaded_file')
select nature1, from: dropdown_name1
attach_file(input_id1, test_file_path, visible: false)
expect(page).to have_css('.uploaded_file', count: 1)
select nature2, from: dropdown_name2
attach_file(input_id2, test_file_path, visible: false)
expect(page).to have_css('.uploaded_file', count: 2)
...
It's all about figuring out what on/in the page indicates it's ready for the users next step