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:
commit
d63c3c8e3a
11 changed files with 122 additions and 10 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
54
src/EvaluateAsync.cpp
Normal 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
14
src/EvaluateAsync.h
Normal 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);
|
||||||
|
};
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
Loading…
Reference in a new issue