Read more

Capybara: Execute asynchronous JavaScript

Tobias Kraze
November 05, 2019Software engineer at makandra GmbH

Capybara provides execute_script and evaluate_script to execute JavaScript code in a Selenium-controlled browser. This however is not a good solution for asynchronous JavaScript.

Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show archive.org snapshot

Enter evaluate_async_script, which allows you to execute some asynchronous code and wait until it finishes. There is a timeout of a couple of seconds, so it will not wait forever.

Use it like this:

page.evaluate_async_script(<<~JS)
  let [done] = arguments
  doSomethingAsynchronous().then(() => {
    done() // call this to indicate we're done
  })
JS

You can return results to Ruby by passing them to the done callback:

result = page.evaluate_async_script(<<~JS)
  let [done] = arguments
  doSomethingAsynchronous().then(() => {
    done("some result")
  })
JS

Finally, you can pass additional object from Ruby to Javascript:

result = page.evaluate_async_script(<<~JS, arg1, arg2)
  let [arg1, arg2, done] = arguments
  doSomethingAsynchronous().then(() => {
    done("some result")
  })
JS

Returning a promise

Warning

The following is not documented anywhere, it may be incorrect.

In newer Capybara versions you may also wrap a promise inside an IIFE and use evaluate_script:

result = page.evaluate_script(<<~JS)
  (function() {
    return doSomethingAsynchronous()
  })()
JS

Of course, you may also add an async-modifier to this function declaration to enable the usage of await. Please check, if this works for you. If not, use evaluate_async_script and chain your calls.

Posted by Tobias Kraze to makandra dev (2019-11-05 12:09)