Capybara: Execute asynchronous JavaScript

Updated . Posted . Visible to the public. Repeats.

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.

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.

Tobias Kraze
Last edit
Henning Koch
License
Source code in this card is licensed under the MIT License.
Posted by Tobias Kraze to makandra dev (2019-11-05 11:09)