From e0e9854145e7a1defbe54ed771c5f17418b6802f Mon Sep 17 00:00:00 2001 From: Thomas Walpole Date: Wed, 25 Oct 2017 10:48:58 -0700 Subject: [PATCH] Add Capybara evaluate_async_script support --- lib/capybara/webkit/browser.rb | 13 +++++--- lib/capybara/webkit/driver.rb | 5 ++++ spec/driver_spec.rb | 30 +++++++++++++++++-- spec/server_spec.rb | 3 +- spec/spec_helper.rb | 5 +++- src/CommandFactory.cpp | 1 + src/Evaluate.cpp | 4 +-- src/EvaluateAsync.cpp | 54 ++++++++++++++++++++++++++++++++++ src/EvaluateAsync.h | 14 +++++++++ src/find_command.h | 1 + src/webkit_server.pro | 2 ++ 11 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 src/EvaluateAsync.cpp create mode 100644 src/EvaluateAsync.h diff --git a/lib/capybara/webkit/browser.rb b/lib/capybara/webkit/browser.rb index 8aac793..6a8c426 100644 --- a/lib/capybara/webkit/browser.rb +++ b/lib/capybara/webkit/browser.rb @@ -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) diff --git a/lib/capybara/webkit/driver.rb b/lib/capybara/webkit/driver.rb index a659489..951cc4a 100644 --- a/lib/capybara/webkit/driver.rb +++ b/lib/capybara/webkit/driver.rb @@ -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 diff --git a/spec/driver_spec.rb b/spec/driver_spec.rb index f6b1326..1f93038 100644 --- a/spec/driver_spec.rb +++ b/spec/driver_spec.rb @@ -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(%) - # result = driver.evaluate_script(%) 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(%) + 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(%) + expect(result).to be_a Hash + expect(result["zIndex"]).to eq "auto" + end + it "executes Javascript" do driver.execute_script(%) 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(%, greeting, "a string") + expect(result).to eq ["a string", greeting] + end + it "passes arguments to evaaluated Javascript" do expect(driver.evaluate_script(%, 3)).to eq 3 end diff --git a/spec/server_spec.rb b/spec/server_spec.rb index 9b208b1..9d203a4 100644 --- a/spec/server_spec.rb +++ b/spec/server_spec.rb @@ -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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4ae1332..8b3a3d2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -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) diff --git a/src/CommandFactory.cpp b/src/CommandFactory.cpp index 546630a..26ce2f4 100644 --- a/src/CommandFactory.cpp +++ b/src/CommandFactory.cpp @@ -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" diff --git a/src/Evaluate.cpp b/src/Evaluate.cpp index 61bcd94..9ee72fe 100644 --- a/src/Evaluate.cpp +++ b/src/Evaluate.cpp @@ -18,8 +18,8 @@ void Evaluate::start() { QString eval_script = QString("(function(){" " for(var i=0; i + +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; icurrentFrame()->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)); +} + + diff --git a/src/EvaluateAsync.h b/src/EvaluateAsync.h new file mode 100644 index 0000000..9433054 --- /dev/null +++ b/src/EvaluateAsync.h @@ -0,0 +1,14 @@ +#include "SocketCommand.h" + +#include + +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); +}; + diff --git a/src/find_command.h b/src/find_command.h index 72e04e3..559e977 100644 --- a/src/find_command.h +++ b/src/find_command.h @@ -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) diff --git a/src/webkit_server.pro b/src/webkit_server.pro index bd0787b..7bb7b0c 100644 --- a/src/webkit_server.pro +++ b/src/webkit_server.pro @@ -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 \