Search code examples
ruby-on-railsajaxrspeccapybaracapybara-webkit

How to purposely delay an AJAX response while testing with Capybara?


I have a React component that mimics the "link preview" feature that most modern social media sites have. You type in a link and it fetches the image, title, etc...

enter image description here

I do this by having the React component make an AJAX call back to my server to fetch the URL preview data.

While it's fetching I show an intermediate "loading" state (i.e. some loading icon or spinning wheel)

The relevant React snippet looks like

this.setState({ isLoadingAttachment: true })

return $.ajax({
  type: "GET",
  url: some_url,
  dataType: "json",
  contentType: "application/json",
}).success(function(response){
  // Succesful! Do Success stuff
  component.setState({ isLoadingAttachment: false })
}).error(function(response) {
  // Uh oh! Handle failure stuff
  component.setState({ isLoadingAttachment: false })
});

Note how the isLoadingAttachment state variable is only valid for a brief second while the server is doing the fetching. Both the success and error scenarios immediately disable it.

I'd like to test some functionality during my "loading" state with my Capybara feature specs. I've mocked all the web calls and the data to be returned by the server, but it all happens so quickly that it passes through the "loading" state before I can even run any expect().. statement on it. I also purposely don't call wait_for_ajax so the page will go ahead without waiting for the ajax, but it's still too fast.

Lastly I also tried purposefully delaying the server call by 1.0 second, but that didn't work either. I assume because the whole thing is single threaded somehow?

# `foo` is an arbitrary method called during the server-side execution
allow_any_instance_of(MyController).
  to receive(:foo) { sleep(1.0) }.and_call_original

Any thoughts on how I could do this?

Thanks!


Solution

  • Capybara starts up the app server in a different thread than the tests, however if you're using the default Capybara.server setting you may have issues with your app calling back to itself since it uses webrick by default. Instead you should specify Capybara.server = :puma. Beyond that, mocking responses is generally a bad idea in feature specs (which are generally meant to be end-to-end tests) since it means you're not actually testing your apps code the way it would run in production anymore. A better solution is to use something like puffing-billy - https://github.com/oesmith/puffing-billy - to mock web responses outside of your apps code which would allow you to do something like

    proxy.stub('https://example.com/proc/').and_return(Proc.new { |params, headers, body|
      sleep 2
      { :text => "Your results"}
    })