1
0
Fork 0
mirror of https://github.com/thoughtbot/capybara-webkit synced 2023-03-27 23:22:28 -04:00

Merge pull request #1033 from twalpole/evaluate_async

Add Capybara Session#evaluate_async_script support
This commit is contained in:
Thomas Walpole 2017-11-01 11:21:35 -07:00 committed by GitHub
commit d63c3c8e3a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 122 additions and 10 deletions

View file

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

View file

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

View file

@ -554,12 +554,11 @@ describe Capybara::Webkit::Driver do
it "evaluates Javascript and returns an object" do it "evaluates Javascript and returns an object" do
result = driver.evaluate_script(%<({ 'one' : 1 })>) result = driver.evaluate_script(%<({ 'one' : 1 })>)
expect(result).to eq 'one' => 1 expect(result).to eq "one" => 1
end end
it "evaluate Javascript and returns an object when the original was readonly" do 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(%<window.getComputedStyle(document.getElementById('greeting'))>)
# result = driver.evaluate_script(%<document.getElementById('greeting')>)
expect(result).to be_a Hash expect(result).to be_a Hash
expect(result["zIndex"]).to eq "auto" expect(result["zIndex"]).to eq "auto"
end end
@ -584,6 +583,27 @@ describe Capybara::Webkit::Driver do
expect(result).to eq [1, 2] expect(result).to eq [1, 2]
end 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 it "executes Javascript" do
driver.execute_script(%<document.getElementById('greeting').innerHTML = 'yo'>) driver.execute_script(%<document.getElementById('greeting').innerHTML = 'yo'>)
expect(driver.find_xpath("//p[contains(., 'yo')]")).not_to be_empty 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 expect(driver.find_xpath("//p[@id='greeting'][contains(., 'new content')]")).not_to be_empty
end 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 it "passes arguments to evaaluated Javascript" do
expect(driver.evaluate_script(%<arguments[0]>, 3)).to eq 3 expect(driver.evaluate_script(%<arguments[0]>, 3)).to eq 3
end end

View file

@ -2,7 +2,8 @@ require "spec_helper"
require "capybara/webkit/server" require "capybara/webkit/server"
describe Capybara::Webkit::Connection do 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 read_io, write_io = IO.pipe
fork_pid = fork do 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_connection = Capybara::Webkit::Connection.new(server: $webkit_server)
$webkit_browser = Capybara::Webkit::Browser.new($webkit_connection) $webkit_browser = Capybara::Webkit::Browser.new($webkit_connection)
if ENV['DEBUG'] if ENV["DEBUG"]
$webkit_browser.enable_logging $webkit_browser.enable_logging
end end
@ -61,6 +61,9 @@ RSpec.configure do |c|
end end
) )
} }
c.filter_run :focus unless ENV["TRAVIS"]
c.run_all_when_everything_filtered = true
end end
def with_env_vars(vars) def with_env_vars(vars)

View file

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

View file

@ -18,8 +18,8 @@ void Evaluate::start() {
QString eval_script = QString("(function(){" QString eval_script = QString("(function(){"
" for(var i=0; i<arguments.length; i++) {" " for(var i=0; i<arguments.length; i++) {"
" arguments[i] = JSON.parse(arguments[i]);" " arguments[i] = JSON.parse(arguments[i]);"
" var elem_id;" " var elem_id = arguments[i]['element-581e-422e-8be1-884c4e116226'];"
" if (elem_id = arguments[i]['element-581e-422e-8be1-884c4e116226']) {" " if (elem_id) {"
" arguments[i] = Capybara.getNode(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(Reset)
CHECK_COMMAND(Node) CHECK_COMMAND(Node)
CHECK_COMMAND(Evaluate) CHECK_COMMAND(Evaluate)
CHECK_COMMAND(EvaluateAsync)
CHECK_COMMAND(Execute) CHECK_COMMAND(Execute)
CHECK_COMMAND(FrameFocus) CHECK_COMMAND(FrameFocus)
CHECK_COMMAND(Header) CHECK_COMMAND(Header)

View file

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