Capybara wait_for_ajax replacement for turbo-stream responses

I’m in need of code like this:

# spec/support/wait_for_ajax.rb
module WaitForAjax
  def wait_for_ajax
    Timeout.timeout(Capybara.default_max_wait_time) do
      loop until finished_all_ajax_requests?
    end
  end

  def finished_all_ajax_requests?
    page.evaluate_script('jQuery.active').zero?
  end
end

but for turbo-stream responses.

Or is there a way to determine if a fetch request is completed?

Does something like this solution work?

@cbandes Thanks but no that solution doesn’t do it.

Did you find a solution to wait for turbo-stream responses?

No, I haven’t found a solution yet.

How do you currently handle it? Or did you pend those specs?

Just doing a sleep 0.5. Granted, it is only in two cases that I needed to do this. Otherwise, a returned stream is modifying the DOM and I’m using proper Capybara detection methods.

I found a solution, which works for me at least.

In that article I mentioned a while back it talks about how wait_for_ajax really isn’t the right solution anyway and that the right approach was to use Capybara’s find which will wait for the elements to come into view. I didn’t really understand how this works at first, but I’ve been playing around with it, and it is starting to make sense to me.

So what I’ve been doing is this - when I want to wait for Turbo to load a new view, I identify an element that only appears on the to-be-loaded view, and I set up a find for that element - something like this

link_to_new_view.click

find('.element_that_only_exists_on_next_view')

expect(thing).to eq(value_that_we_needed_to_wait_for)

The find will wait until the element comes into view, which is pretty much what wait_for_ajax is trying to do anyway, but this is more specific and works really well once you start down this path.

I’m mostly using this with turbo-frames rather than turbo-streams but I think it will work the same way
with anything that changes the dom. You just need to know what you’re going to be looking for.

Right but there are some (albeit rare) edge cases where the DOM doesn’t change after a stream or a fetch(). Even when you’re expecting a DOM change I’ve found that Capybara still can fail intermittently. This can occur even when bumping up the wait time e.g. assert_content "successfully created", wait: 5. Judiciously sprinkling sleep 0.5 or even a sleep 1.0 on my system tests in these cases keeps them consistently green.