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.