Add Capybara evaluate_async_script support

This commit is contained in:
Thomas Walpole 2017-10-25 10:48:58 -07:00
parent 5a56c48f21
commit e0e9854145
11 changed files with 122 additions and 10 deletions

View File

@ -134,7 +134,7 @@ module Capybara::Webkit
end
def get_window_handles
JSON.parse(command('GetWindowHandles'))
JSON.parse(command("GetWindowHandles"))
end
def window_handles
@ -144,7 +144,7 @@ module Capybara::Webkit
end
def get_window_handle
command('GetWindowHandle')
command("GetWindowHandle")
end
def window_handle
@ -236,12 +236,17 @@ https://github.com/thoughtbot/capybara-webkit/wiki/Reporting-Crashes
end
def evaluate_script(script, *args)
json = command('Evaluate', script, args.to_json)
json = command("Evaluate", script, args.to_json)
JSON.parse("[#{json}]").first
end
def evaluate_async_script(script, *args)
json = command("EvaluateAsync", script, args.to_json)
JSON.parse("[#{json}]").first
end
def execute_script(script, *args)
command('Execute', script, args.to_json)
command("Execute", script, args.to_json)
end
def render(path, width, height)

View File

@ -91,6 +91,11 @@ module Capybara::Webkit
decode_result(result)
end
def evaluate_async_script(script, *args)
result = @browser.evaluate_async_script(script, *encode_args(args))
decode_result(result)
end
def console_messages
@browser.console_messages
end

View File

@ -554,12 +554,11 @@ describe Capybara::Webkit::Driver do
it "evaluates Javascript and returns an object" do
result = driver.evaluate_script(%<({ 'one' : 1 })>)
expect(result).to eq 'one' => 1
expect(result).to eq "one" => 1
end
it "evaluate Javascript and returns an object when the original was readonly" do
result = driver.evaluate_script(%<window.getComputedStyle(document.getElementById('greeting'))>)
# result = driver.evaluate_script(%<document.getElementById('greeting')>)
expect(result).to be_a Hash
expect(result["zIndex"]).to eq "auto"
end
@ -584,6 +583,27 @@ describe Capybara::Webkit::Driver do
expect(result).to eq [1, 2]
end
it "evaluates asynchronous JS which isn't" do
result = driver.evaluate_async_script("arguments[0](4)")
expect(result).to eq 4
end
it "evaluates asynchronous JS" do
result = driver.evaluate_async_script("setTimeout(function(callback){ callback('jaguar') }, 100, arguments[0])")
expect(result).to eq "jaguar"
end
it "evaluates asynchronous JS and returns an object" do
result = driver.evaluate_async_script(%<setTimeout(function(callback){ callback({ 'one' : 1 }) }, 100, arguments[0])>)
expect(result).to eq "one" => 1
end
it "evaluates asynchronous JS and returns an object when the original was readonly" do
result = driver.evaluate_async_script(%<setTimeout(function(callback){ callback(window.getComputedStyle(document.getElementById('greeting'))) }, 100, arguments[0])>)
expect(result).to be_a Hash
expect(result["zIndex"]).to eq "auto"
end
it "executes Javascript" do
driver.execute_script(%<document.getElementById('greeting').innerHTML = 'yo'>)
expect(driver.find_xpath("//p[contains(., 'yo')]")).not_to be_empty
@ -612,6 +632,12 @@ describe Capybara::Webkit::Driver do
expect(driver.find_xpath("//p[@id='greeting'][contains(., 'new content')]")).not_to be_empty
end
it "passes elements as arguments to asynchronous script" do
greeting = driver.find_xpath("//p[@id='greeting']").first
result = driver.evaluate_async_script(%<arguments[2]([arguments[1], arguments[0]])>, greeting, "a string")
expect(result).to eq ["a string", greeting]
end
it "passes arguments to evaaluated Javascript" do
expect(driver.evaluate_script(%<arguments[0]>, 3)).to eq 3
end

View File

@ -2,7 +2,8 @@ require "spec_helper"
require "capybara/webkit/server"
describe Capybara::Webkit::Connection do
it "ensures the process ends", skip_on_windows: true, skip_on_jruby: true do
it "ensures the process ends when the parent process ends", skip_on_windows: true, skip_on_jruby: true do
sleep 1 # Without this sleep popen3 hangs on OSX when running the tests - not really sure why
read_io, write_io = IO.pipe
fork_pid = fork do

View File

@ -13,7 +13,7 @@ $webkit_server = Capybara::Webkit::Server.new
$webkit_connection = Capybara::Webkit::Connection.new(server: $webkit_server)
$webkit_browser = Capybara::Webkit::Browser.new($webkit_connection)
if ENV['DEBUG']
if ENV["DEBUG"]
$webkit_browser.enable_logging
end
@ -61,6 +61,9 @@ RSpec.configure do |c|
end
)
}
c.filter_run :focus unless ENV["TRAVIS"]
c.run_all_when_everything_filtered = true
end
def with_env_vars(vars)

View File

@ -5,6 +5,7 @@
#include "Reset.h"
#include "Node.h"
#include "Evaluate.h"
#include "EvaluateAsync.h"
#include "Execute.h"
#include "FrameFocus.h"
#include "Header.h"

View File

@ -18,8 +18,8 @@ void Evaluate::start() {
QString eval_script = QString("(function(){"
" for(var i=0; i<arguments.length; i++) {"
" arguments[i] = JSON.parse(arguments[i]);"
" var elem_id;"
" if (elem_id = arguments[i]['element-581e-422e-8be1-884c4e116226']) {"
" var elem_id = arguments[i]['element-581e-422e-8be1-884c4e116226'];"
" if (elem_id) {"
" arguments[i] = Capybara.getNode(elem_id);"
" };"
" };"

54
src/EvaluateAsync.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "EvaluateAsync.h"
#include "WebPage.h"
#include "WebPageManager.h"
#include "JsonSerializer.h"
#include <iostream>
EvaluateAsync::EvaluateAsync(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
}
void EvaluateAsync::start() {
QString script = arguments()[0];
QString jsonArgs;
if (arguments().length()>1){
jsonArgs = arguments()[1];
} else {
jsonArgs ="[]";
}
QString eval_script = QString("(function(){"
" for(var i=0; i<arguments.length-1; i++) {"
" arguments[i] = JSON.parse(arguments[i]);"
" var elem_id = arguments[i]['element-581e-422e-8be1-884c4e116226'];"
" if (elem_id) {"
" arguments[i] = Capybara.getNode(elem_id);"
" };"
" };"
" eval(\"%1\");"
" return;"
" }).apply(null, %2.concat(function(res){ "
" res = Capybara.wrapResult(res);"
// This isn't necessary in Qt 5.5 but is in older (at least 5.2 on Travis)
" if (res instanceof Array) {"
" CapybaraAsync['asyncResult(QVariantList)'](res);"
" } else { "
" CapybaraAsync['asyncResult(QVariant)'](res);"
" }"
" }))").arg(script.replace("\"","\\\"").remove("\n"), jsonArgs);
QObject invocation_stub;
invocation_stub.setProperty("allowUnattached", false);
page()->currentFrame()->addToJavaScriptWindowObject("CapybaraInvocation", &invocation_stub);
page()->currentFrame()->addToJavaScriptWindowObject("CapybaraAsync", this);
page()->currentFrame()->evaluateJavaScript(eval_script);
}
void EvaluateAsync::asyncResult(QVariantList result) {
JsonSerializer serializer;
finish(true, serializer.serialize(result));
}
void EvaluateAsync::asyncResult(QVariant result) {
JsonSerializer serializer;
finish(true, serializer.serialize(result));
}

14
src/EvaluateAsync.h Normal file
View File

@ -0,0 +1,14 @@
#include "SocketCommand.h"
#include <QVariantList>
class EvaluateAsync : public SocketCommand {
Q_OBJECT
public:
EvaluateAsync(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
Q_INVOKABLE void asyncResult(QVariant result);
Q_INVOKABLE void asyncResult(QVariantList result);
};

View File

@ -8,6 +8,7 @@ CHECK_COMMAND(FindXpath)
CHECK_COMMAND(Reset)
CHECK_COMMAND(Node)
CHECK_COMMAND(Evaluate)
CHECK_COMMAND(EvaluateAsync)
CHECK_COMMAND(Execute)
CHECK_COMMAND(FrameFocus)
CHECK_COMMAND(Header)

View File

@ -47,6 +47,7 @@ HEADERS = \
Node.h \
JavascriptInvocation.h \
Evaluate.h \
EvaluateAsync.h \
Execute.h \
FrameFocus.h \
Response.h \
@ -132,6 +133,7 @@ SOURCES = \
Node.cpp \
JavascriptInvocation.cpp \
Evaluate.cpp \
EvaluateAsync.cpp \
Execute.cpp \
FrameFocus.cpp \
Response.cpp \