mirror of
https://github.com/thoughtbot/capybara-webkit
synced 2023-03-27 23:22:28 -04:00
Update for Capybara 2.3.0
This adds support for the full Capybara 2.3.0 API. There are two known incompatibilities: * Selenium supports outerWidth and outerHeight, which we cannot, because we dont' have an actual OS window. * Selenium raises errors after interacting with a closed window. We focus the next available window after closing. This commit adds the following: * Implement Driver#close_window * Implement Driver#current_window_handle * Implement Driver#maximize_window * Implement Driver#open_new_window * Implement Driver#no_such_window_error * Implement Driver#resize_window_to * Implement Driver#switch_to_window * Implement Driver#window_size * Implement Driver#go_back * Implement Driver#go_forward * Support change events when clearing a text input * Support setting contentEditable elements * Support window.close() in JavaScript * Don't return text from hidden elements * Skip Capybara specs which use outerWidth, outerHeight * Don't use Qt object ownership to manage windows
This commit is contained in:
parent
729c2cf364
commit
e0172bfcd9
44 changed files with 567 additions and 113 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -24,3 +24,4 @@ webkit_server.pro.user
|
|||
.ruby-version
|
||||
.ruby-gemset
|
||||
.idea
|
||||
.qmake.stash
|
||||
|
|
21
Gemfile.lock
21
Gemfile.lock
|
@ -2,16 +2,17 @@ PATH
|
|||
remote: .
|
||||
specs:
|
||||
capybara-webkit (1.1.1)
|
||||
capybara (>= 2.0.2, < 2.2.0)
|
||||
capybara (>= 2.0.2, < 2.4.0)
|
||||
json
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.3.6)
|
||||
appraisal (0.4.0)
|
||||
bundler
|
||||
rake
|
||||
capybara (2.1.0)
|
||||
capybara (2.3.0)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
|
@ -24,18 +25,15 @@ GEM
|
|||
ffi (1.9.3-java)
|
||||
ffi (1.9.3-x86-mingw32)
|
||||
json (1.8.1)
|
||||
json (1.8.1-java)
|
||||
mime-types (2.0)
|
||||
launchy (2.4.2)
|
||||
addressable (~> 2.3)
|
||||
mime-types (2.3)
|
||||
mini_magick (3.2.1)
|
||||
subexec (~> 0.0.4)
|
||||
mini_portile (0.5.2)
|
||||
mini_portile (0.6.0)
|
||||
multi_json (1.8.4)
|
||||
nokogiri (1.6.0)
|
||||
mini_portile (~> 0.5.0)
|
||||
nokogiri (1.6.0-java)
|
||||
mini_portile (~> 0.5.0)
|
||||
nokogiri (1.6.0-x86-mingw32)
|
||||
mini_portile (~> 0.5.0)
|
||||
nokogiri (1.6.2.1)
|
||||
mini_portile (= 0.6.0)
|
||||
rack (1.5.2)
|
||||
rack-protection (1.3.2)
|
||||
rack
|
||||
|
@ -74,6 +72,7 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
appraisal (~> 0.4.0)
|
||||
capybara-webkit!
|
||||
launchy
|
||||
mini_magick
|
||||
rake
|
||||
rspec (~> 2.14.0)
|
||||
|
|
|
@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|||
|
||||
s.required_ruby_version = ">= 1.9.0"
|
||||
|
||||
s.add_runtime_dependency("capybara", ">= 2.0.2", "< 2.2.0")
|
||||
s.add_runtime_dependency("capybara", ">= 2.0.2", "< 2.4.0")
|
||||
s.add_runtime_dependency("json")
|
||||
|
||||
s.add_development_dependency("rspec", "~> 2.14.0")
|
||||
|
@ -29,5 +29,6 @@ Gem::Specification.new do |s|
|
|||
s.add_development_dependency("rake")
|
||||
s.add_development_dependency("appraisal", "~> 0.4.0")
|
||||
s.add_development_dependency("selenium-webdriver")
|
||||
s.add_development_dependency("launchy")
|
||||
end
|
||||
|
||||
|
|
|
@ -102,6 +102,26 @@ module Capybara::Webkit
|
|||
command("WindowFocus", selector)
|
||||
end
|
||||
|
||||
def window_open
|
||||
command("WindowOpen")
|
||||
end
|
||||
|
||||
def window_close(selector)
|
||||
command("WindowClose", selector)
|
||||
end
|
||||
|
||||
def window_resize(handle, width, height)
|
||||
command("WindowResize", handle, width.to_i, height.to_i)
|
||||
end
|
||||
|
||||
def window_size(handle)
|
||||
JSON.parse(command("WindowSize", handle))
|
||||
end
|
||||
|
||||
def window_maximize(handle)
|
||||
command("WindowMaximize", handle)
|
||||
end
|
||||
|
||||
def get_window_handles
|
||||
JSON.parse(command('GetWindowHandles'))
|
||||
end
|
||||
|
@ -195,14 +215,18 @@ module Capybara::Webkit
|
|||
command("SetProxy")
|
||||
end
|
||||
|
||||
def resize_window(width, height)
|
||||
command("ResizeWindow", width.to_i, height.to_i)
|
||||
end
|
||||
|
||||
def version
|
||||
command("Version")
|
||||
end
|
||||
|
||||
def go_back
|
||||
command("GoBack")
|
||||
end
|
||||
|
||||
def go_forward
|
||||
command("GoForward")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check
|
||||
|
|
|
@ -8,7 +8,7 @@ module Capybara::Webkit
|
|||
SERVER_PATH = File.expand_path("../../../../bin/webkit_server", __FILE__)
|
||||
WEBKIT_SERVER_START_TIMEOUT = 15
|
||||
|
||||
attr_reader :port
|
||||
attr_reader :port, :pid
|
||||
|
||||
def initialize(options = {})
|
||||
@socket = nil
|
||||
|
|
|
@ -89,7 +89,15 @@ module Capybara::Webkit
|
|||
end
|
||||
|
||||
def resize_window(width, height)
|
||||
browser.resize_window(width, height)
|
||||
resize_window_to(current_window_handle, width, height)
|
||||
end
|
||||
|
||||
def resize_window_to(handle, width, height)
|
||||
browser.window_resize(handle, width, height)
|
||||
end
|
||||
|
||||
def window_size(handle)
|
||||
browser.window_size(handle)
|
||||
end
|
||||
|
||||
def within_frame(selector)
|
||||
|
@ -102,8 +110,8 @@ module Capybara::Webkit
|
|||
end
|
||||
|
||||
def within_window(selector)
|
||||
current_window = window_handle
|
||||
browser.window_focus(selector)
|
||||
current_window = current_window_handle
|
||||
switch_to_window(selector)
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
|
@ -111,14 +119,30 @@ module Capybara::Webkit
|
|||
end
|
||||
end
|
||||
|
||||
def switch_to_window(selector)
|
||||
browser.window_focus(selector)
|
||||
end
|
||||
|
||||
def window_handles
|
||||
browser.get_window_handles
|
||||
end
|
||||
|
||||
def window_handle
|
||||
def current_window_handle
|
||||
browser.get_window_handle
|
||||
end
|
||||
|
||||
def open_new_window
|
||||
browser.window_open
|
||||
end
|
||||
|
||||
def close_window(selector)
|
||||
browser.window_close(selector)
|
||||
end
|
||||
|
||||
def maximize_window(selector)
|
||||
browser.window_maximize(selector)
|
||||
end
|
||||
|
||||
def accept_js_confirms!
|
||||
browser.accept_js_confirms
|
||||
end
|
||||
|
@ -143,6 +167,14 @@ module Capybara::Webkit
|
|||
end
|
||||
end
|
||||
|
||||
def go_back
|
||||
browser.go_back
|
||||
end
|
||||
|
||||
def go_forward
|
||||
browser.go_forward
|
||||
end
|
||||
|
||||
def wait?
|
||||
true
|
||||
end
|
||||
|
@ -174,6 +206,10 @@ module Capybara::Webkit
|
|||
[Capybara::Webkit::ClickFailed]
|
||||
end
|
||||
|
||||
def no_such_window_error
|
||||
Capybara::Webkit::NoSuchWindowError
|
||||
end
|
||||
|
||||
def version
|
||||
[
|
||||
"Capybara: #{Capybara::VERSION}",
|
||||
|
|
|
@ -14,6 +14,9 @@ module Capybara::Webkit
|
|||
class TimeoutError < Timeout::Error
|
||||
end
|
||||
|
||||
class NoSuchWindowError < StandardError
|
||||
end
|
||||
|
||||
class JsonError
|
||||
def initialize(response)
|
||||
error = JSON.parse response
|
||||
|
|
|
@ -45,4 +45,26 @@ describe Capybara::Webkit::Driver, "#resize_window(width, height)" do
|
|||
driver.visit("#{AppRunner.app_host}/")
|
||||
driver.html.should include(DEFAULT_DIMENTIONS)
|
||||
end
|
||||
|
||||
it "resizes windows by handle" do
|
||||
driver.visit("#{AppRunner.app_host}/")
|
||||
driver.open_new_window
|
||||
driver.visit("#{AppRunner.app_host}/")
|
||||
|
||||
driver.resize_window_to(driver.window_handles.first, 800, 600)
|
||||
driver.resize_window_to(driver.window_handles.last, 400, 300)
|
||||
|
||||
driver.window_size(driver.window_handles.first).should eq [800, 600]
|
||||
driver.window_size(driver.window_handles.last).should eq [400, 300]
|
||||
end
|
||||
|
||||
it "maximizes a window" do
|
||||
driver.visit("#{AppRunner.app_host}/")
|
||||
driver.resize_window(400, 300)
|
||||
driver.maximize_window(driver.current_window_handle)
|
||||
width, height = *driver.window_size(driver.current_window_handle)
|
||||
|
||||
width.should be > 400
|
||||
height.should be > 300
|
||||
end
|
||||
end
|
||||
|
|
|
@ -341,6 +341,9 @@ describe Capybara::Webkit::Driver do
|
|||
<div id="hidden-text">
|
||||
Some of this text is <em style="display:none">hidden!</em>
|
||||
</div>
|
||||
<div id="hidden-ancestor" style="display: none">
|
||||
<div>Hello</div>
|
||||
</div>
|
||||
<input type="text" disabled="disabled"/>
|
||||
<input id="checktest" type="checkbox" checked="checked"/>
|
||||
<script type="text/javascript">
|
||||
|
@ -353,6 +356,12 @@ describe Capybara::Webkit::Driver do
|
|||
|
||||
before { visit("/") }
|
||||
|
||||
it "doesn't return text if the ancestor is hidden" do
|
||||
visit("/")
|
||||
|
||||
driver.find_css("#hidden-ancestor div").first.text.should eq ''
|
||||
end
|
||||
|
||||
it "handles anchor tags" do
|
||||
visit("#test")
|
||||
driver.find_xpath("//*[contains(., 'hello')]").should_not be_empty
|
||||
|
@ -1081,7 +1090,7 @@ describe Capybara::Webkit::Driver do
|
|||
<input class="watch" type="password"/>
|
||||
<input class="watch" type="search"/>
|
||||
<input class="watch" type="tel"/>
|
||||
<input class="watch" type="text"/>
|
||||
<input class="watch" type="text" value="original"/>
|
||||
<input class="watch" type="url"/>
|
||||
<textarea class="watch"></textarea>
|
||||
<input class="watch" type="checkbox"/>
|
||||
|
@ -1117,7 +1126,7 @@ describe Capybara::Webkit::Driver do
|
|||
|
||||
before { visit("/") }
|
||||
|
||||
let(:newtext) { 'newvalue' }
|
||||
let(:newtext) { '12345' }
|
||||
|
||||
let(:keyevents) do
|
||||
(%w{focus} +
|
||||
|
@ -1125,13 +1134,22 @@ describe Capybara::Webkit::Driver do
|
|||
).flatten
|
||||
end
|
||||
|
||||
let(:textevents) { keyevents + %w(change blur) }
|
||||
|
||||
%w(email number password search tel text url).each do | field_type |
|
||||
it "triggers text input events on inputs of type #{field_type}" do
|
||||
driver.find_xpath("//input[@type='#{field_type}']").first.set(newtext)
|
||||
driver.find_xpath("//li").map(&:visible_text).should eq keyevents
|
||||
driver.find_xpath("//body").first.click
|
||||
driver.find_xpath("//li").map(&:visible_text).should eq textevents
|
||||
end
|
||||
end
|
||||
|
||||
it "triggers events for cleared inputs" do
|
||||
driver.find_xpath("//input[@type='text']").first.set('')
|
||||
driver.find_xpath("//body").first.click
|
||||
driver.find_xpath("//li").map(&:visible_text).should include('change')
|
||||
end
|
||||
|
||||
it "triggers textarea input events" do
|
||||
driver.find_xpath("//textarea").first.set(newtext)
|
||||
driver.find_xpath("//li").map(&:visible_text).should eq keyevents
|
||||
|
@ -1925,6 +1943,42 @@ describe Capybara::Webkit::Driver do
|
|||
end
|
||||
end
|
||||
|
||||
it "can switch to another window" do
|
||||
visit("/new_window")
|
||||
driver.switch_to_window(driver.window_handles.last)
|
||||
driver.find_xpath("//p").first.visible_text.should eq "finished"
|
||||
end
|
||||
|
||||
it "knows the current window handle" do
|
||||
visit("/new_window")
|
||||
driver.within_window(driver.window_handles.last) do
|
||||
driver.current_window_handle.should eq driver.window_handles.last
|
||||
end
|
||||
end
|
||||
|
||||
it "can close the current window" do
|
||||
visit("/new_window")
|
||||
original_handle = driver.current_window_handle
|
||||
driver.switch_to_window(driver.window_handles.last)
|
||||
driver.close_window(driver.current_window_handle)
|
||||
|
||||
driver.current_window_handle.should eq(original_handle)
|
||||
end
|
||||
|
||||
it "can close an unfocused window" do
|
||||
visit("/new_window")
|
||||
driver.close_window(driver.window_handles.last)
|
||||
driver.window_handles.size.should eq(1)
|
||||
end
|
||||
|
||||
it "can close the last window" do
|
||||
visit("/new_window")
|
||||
handles = driver.window_handles
|
||||
handles.each { |handle| driver.close_window(handle) }
|
||||
driver.html.should be_empty
|
||||
handles.should_not include(driver.current_window_handle)
|
||||
end
|
||||
|
||||
it "waits for the new window to load" do
|
||||
visit("/new_window?sleep=1")
|
||||
driver.within_window(driver.window_handles.last) do
|
||||
|
@ -1969,7 +2023,7 @@ describe Capybara::Webkit::Driver do
|
|||
|
||||
it "raises an error if the window is not found" do
|
||||
expect { driver.within_window('myWindowDoesNotExist') }.
|
||||
to raise_error(Capybara::Webkit::InvalidResponseError)
|
||||
to raise_error(Capybara::Webkit::NoSuchWindowError)
|
||||
end
|
||||
|
||||
it "has a number of window handles equal to the number of open windows" do
|
||||
|
@ -1978,12 +2032,35 @@ describe Capybara::Webkit::Driver do
|
|||
driver.window_handles.size.should eq 2
|
||||
end
|
||||
|
||||
it "removes windows when closed via JavaScript" do
|
||||
visit("/new_window")
|
||||
driver.execute_script('console.log(window.document.title); window.close()')
|
||||
sleep 2
|
||||
driver.window_handles.size.should eq 1
|
||||
end
|
||||
|
||||
it "closes new windows on reset" do
|
||||
visit("/new_window")
|
||||
last_handle = driver.window_handles.last
|
||||
driver.reset!
|
||||
driver.window_handles.should_not include(last_handle)
|
||||
end
|
||||
|
||||
it "leaves the old window focused when opening a new window" do
|
||||
visit("/new_window")
|
||||
current_window = driver.current_window_handle
|
||||
driver.open_new_window
|
||||
|
||||
driver.current_window_handle.should eq current_window
|
||||
driver.window_handles.size.should eq 3
|
||||
end
|
||||
|
||||
it "opens blank windows" do
|
||||
visit("/new_window")
|
||||
driver.open_new_window
|
||||
driver.switch_to_window(driver.window_handles.last)
|
||||
driver.html.should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it "preserves cookies across windows" do
|
||||
|
@ -2386,6 +2463,34 @@ describe Capybara::Webkit::Driver do
|
|||
end
|
||||
end
|
||||
|
||||
context "history" do
|
||||
let(:driver) do
|
||||
driver_for_app do
|
||||
get "/:param" do |param|
|
||||
<<-HTML
|
||||
<html>
|
||||
<body>
|
||||
<p>#{param}</p>
|
||||
<a href="/navigated">Navigate</a>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "can navigate in history" do
|
||||
visit("/first")
|
||||
driver.find_xpath("//p").first.text.should eq('first')
|
||||
driver.find_xpath("//a").first.click
|
||||
driver.find_xpath("//p").first.text.should eq('navigated')
|
||||
driver.go_back
|
||||
driver.find_xpath("//p").first.text.should eq('first')
|
||||
driver.go_forward
|
||||
driver.find_xpath("//p").first.text.should eq('navigated')
|
||||
end
|
||||
end
|
||||
|
||||
def driver_url(driver, path)
|
||||
URI.parse(driver.current_url).merge(path).to_s
|
||||
end
|
||||
|
|
|
@ -10,6 +10,8 @@ describe Capybara::Webkit, 'compatibility with selenium' do
|
|||
<label for="one">One</label><input type="text" name="one" id="one" />
|
||||
<label for="two">Two</label><input type="text" name="two" id="two" />
|
||||
<label for="three">Three</label><input type="text" name="three" id="three" readonly="readonly" />
|
||||
<label for="textarea">Textarea</label>
|
||||
<textarea name="textarea" id="textarea"></textarea>
|
||||
<input type="submit" value="Submit" id="submit" />
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
|
@ -35,6 +37,7 @@ describe Capybara::Webkit, 'compatibility with selenium' do
|
|||
fill_in "One", :with => "a new value"
|
||||
fill_in "Two", :with => "other value"
|
||||
fill_in "Three", :with => "readonly value"
|
||||
fill_in "Textarea", :with => "last value"
|
||||
click_button "Submit"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,8 +10,8 @@ $LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
|
|||
Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) }
|
||||
|
||||
require 'capybara/webkit'
|
||||
connection = Capybara::Webkit::Connection.new(:socket_class => TCPSocket)
|
||||
$webkit_browser = Capybara::Webkit::Browser.new(connection)
|
||||
$webkit_connection = Capybara::Webkit::Connection.new(:socket_class => TCPSocket)
|
||||
$webkit_browser = Capybara::Webkit::Browser.new($webkit_connection)
|
||||
|
||||
if ENV['DEBUG']
|
||||
$webkit_browser.enable_logging
|
||||
|
@ -24,9 +24,27 @@ Capybara.register_driver :reusable_webkit do |app|
|
|||
end
|
||||
|
||||
RSpec.configure do |c|
|
||||
Capybara::SpecHelper.configure(c)
|
||||
|
||||
c.filter_run_excluding :skip_on_windows => !(RbConfig::CONFIG['host_os'] =~ /mingw32/).nil?
|
||||
c.filter_run_excluding :skip_on_jruby => !defined?(::JRUBY_VERSION).nil?
|
||||
Capybara::SpecHelper.configure(c)
|
||||
|
||||
# We can't support outerWidth and outerHeight without a visible window.
|
||||
# We focus the next window instead of failing when closing windows.
|
||||
c.filter_run_excluding :full_description =>
|
||||
/Capybara::Session webkit Capybara::Window #(size|resize_to|maximize|close.*no_such_window_error)/
|
||||
|
||||
# Capybara's integration tests expect "capybara/" in the default path
|
||||
c.around :requires => :screenshot do |example|
|
||||
old_path = Capybara.save_and_open_page_path
|
||||
Capybara.save_and_open_page_path = File.join(PROJECT_ROOT, 'tmp', 'capybara')
|
||||
|
||||
begin
|
||||
example.run
|
||||
ensure
|
||||
Capybara.save_and_open_page_path = old_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def with_env_vars(vars)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "CurrentUrl.h"
|
||||
#include "SetTimeout.h"
|
||||
#include "GetTimeout.h"
|
||||
#include "ResizeWindow.h"
|
||||
#include "WindowResize.h"
|
||||
#include "IgnoreSslErrors.h"
|
||||
#include "SetSkipImageLoading.h"
|
||||
#include "WindowFocus.h"
|
||||
|
@ -40,6 +40,12 @@
|
|||
#include "Version.h"
|
||||
#include "Title.h"
|
||||
#include "FindCss.h"
|
||||
#include "WindowClose.h"
|
||||
#include "WindowOpen.h"
|
||||
#include "WindowSize.h"
|
||||
#include "WindowMaximize.h"
|
||||
#include "GoBack.h"
|
||||
#include "GoForward.h"
|
||||
|
||||
CommandFactory::CommandFactory(WebPageManager *manager, QObject *parent) : QObject(parent) {
|
||||
m_manager = manager;
|
||||
|
|
12
src/GoBack.cpp
Normal file
12
src/GoBack.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "GoBack.h"
|
||||
#include "SocketCommand.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
|
||||
GoBack::GoBack(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void GoBack::start() {
|
||||
page()->triggerAction(QWebPage::Back);
|
||||
finish(true);
|
||||
}
|
10
src/GoBack.h
Normal file
10
src/GoBack.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "SocketCommand.h"
|
||||
|
||||
class GoBack : public SocketCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GoBack(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
virtual void start();
|
||||
};
|
||||
|
12
src/GoForward.cpp
Normal file
12
src/GoForward.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "GoForward.h"
|
||||
#include "SocketCommand.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
|
||||
GoForward::GoForward(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void GoForward::start() {
|
||||
page()->triggerAction(QWebPage::Forward);
|
||||
finish(true);
|
||||
}
|
10
src/GoForward.h
Normal file
10
src/GoForward.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "SocketCommand.h"
|
||||
|
||||
class GoForward : public SocketCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GoForward(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
virtual void start();
|
||||
};
|
||||
|
|
@ -6,8 +6,6 @@ Reset::Reset(WebPageManager *manager, QStringList &arguments, QObject *parent) :
|
|||
}
|
||||
|
||||
void Reset::start() {
|
||||
page()->triggerAction(QWebPage::Stop);
|
||||
|
||||
manager()->reset();
|
||||
|
||||
finish(true);
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#include "ResizeWindow.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
|
||||
ResizeWindow::ResizeWindow(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void ResizeWindow::start() {
|
||||
int width = arguments()[0].toInt();
|
||||
int height = arguments()[1].toInt();
|
||||
|
||||
QSize size(width, height);
|
||||
page()->setViewportSize(size);
|
||||
|
||||
finish(true);
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#include "SocketCommand.h"
|
||||
|
||||
class ResizeWindow : public SocketCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ResizeWindow(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
virtual void start();
|
||||
};
|
||||
|
|
@ -19,3 +19,9 @@ WebPageManager *SocketCommand::manager() const {
|
|||
return m_manager;
|
||||
}
|
||||
|
||||
QString SocketCommand::toString() const {
|
||||
QString result;
|
||||
QTextStream(&result) << metaObject()->className() << QString("(") << m_arguments.join(", ") << QString(")");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ class SocketCommand : public Command {
|
|||
|
||||
public:
|
||||
SocketCommand(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
virtual QString toString() const;
|
||||
|
||||
protected:
|
||||
WebPage *page() const;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <QWebSettings>
|
||||
#include <QUuid>
|
||||
#include <QApplication>
|
||||
#include <QWebView>
|
||||
#include <QMainWindow>
|
||||
|
||||
WebPage::WebPage(WebPageManager *manager, QObject *parent) : QWebPage(parent) {
|
||||
m_loading = false;
|
||||
|
@ -33,14 +35,23 @@ WebPage::WebPage(WebPageManager *manager, QObject *parent) : QWebPage(parent) {
|
|||
this, SLOT(frameCreated(QWebFrame *)));
|
||||
connect(this, SIGNAL(unsupportedContent(QNetworkReply*)),
|
||||
this, SLOT(handleUnsupportedContent(QNetworkReply*)));
|
||||
resetWindowSize();
|
||||
connect(this, SIGNAL(windowCloseRequested()), this, SLOT(remove()));
|
||||
|
||||
settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
|
||||
settings()->setAttribute(QWebSettings::JavascriptCanCloseWindows, true);
|
||||
settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
|
||||
|
||||
createWindow();
|
||||
}
|
||||
|
||||
void WebPage::resetWindowSize() {
|
||||
this->setViewportSize(QSize(1680, 1050));
|
||||
this->settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
|
||||
void WebPage::createWindow() {
|
||||
QSize size(1680, 1050);
|
||||
setViewportSize(size);
|
||||
}
|
||||
|
||||
void WebPage::resize(int width, int height) {
|
||||
QSize size(width, height);
|
||||
setViewportSize(size);
|
||||
}
|
||||
|
||||
void WebPage::resetLocalStorage() {
|
||||
|
@ -334,7 +345,7 @@ bool WebPage::supportsExtension(Extension extension) const {
|
|||
|
||||
QWebPage *WebPage::createWindow(WebWindowType type) {
|
||||
Q_UNUSED(type);
|
||||
return m_manager->createPage(this);
|
||||
return m_manager->createPage();
|
||||
}
|
||||
|
||||
QString WebPage::uuid() {
|
||||
|
@ -361,6 +372,10 @@ void WebPage::setFocus() {
|
|||
m_manager->setCurrentPage(this);
|
||||
}
|
||||
|
||||
void WebPage::remove() {
|
||||
m_manager->removePage(this);
|
||||
}
|
||||
|
||||
void WebPage::setConfirmAction(QString action) {
|
||||
m_confirm = (action == "Yes");
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
class WebPageManager;
|
||||
class InvocationResult;
|
||||
class NetworkReplyProxy;
|
||||
class QWebView;
|
||||
|
||||
class WebPage : public QWebPage {
|
||||
Q_OBJECT
|
||||
|
@ -33,7 +34,7 @@ class WebPage : public QWebPage {
|
|||
QVariantList alertMessages();
|
||||
QVariantList confirmMessages();
|
||||
QVariantList promptMessages();
|
||||
void resetWindowSize();
|
||||
void createWindow();
|
||||
void resetLocalStorage();
|
||||
QWebPage *createWindow(WebWindowType type);
|
||||
QString uuid();
|
||||
|
@ -46,6 +47,7 @@ class WebPage : public QWebPage {
|
|||
QString contentType();
|
||||
void mouseEvent(QEvent::Type type, const QPoint &position, Qt::MouseButton button);
|
||||
bool clickTest(QWebElement element, int absoluteX, int absoluteY);
|
||||
void resize(int, int);
|
||||
|
||||
public slots:
|
||||
bool shouldInterruptJavaScript();
|
||||
|
@ -57,6 +59,7 @@ class WebPage : public QWebPage {
|
|||
void handleSslErrorsForReply(QNetworkReply *reply, const QList<QSslError> &);
|
||||
void handleUnsupportedContent(QNetworkReply *reply);
|
||||
void replyFinished(QUrl &, QNetworkReply *);
|
||||
void remove();
|
||||
|
||||
signals:
|
||||
void pageFinished(bool);
|
||||
|
|
|
@ -12,7 +12,7 @@ WebPageManager::WebPageManager(QObject *parent) : QObject(parent) {
|
|||
m_timeout = -1;
|
||||
m_networkAccessManager = new NetworkAccessManager(this);
|
||||
m_networkAccessManager->setCookieJar(m_cookieJar);
|
||||
createPage(this)->setFocus();
|
||||
createPage()->setFocus();
|
||||
}
|
||||
|
||||
NetworkAccessManager *WebPageManager::networkAccessManager() {
|
||||
|
@ -35,8 +35,8 @@ WebPage *WebPageManager::currentPage() const {
|
|||
return m_currentPage;
|
||||
}
|
||||
|
||||
WebPage *WebPageManager::createPage(QObject *parent) {
|
||||
WebPage *page = new WebPage(this, parent);
|
||||
WebPage *WebPageManager::createPage() {
|
||||
WebPage *page = new WebPage(this);
|
||||
connect(page, SIGNAL(loadStarted()),
|
||||
this, SLOT(emitLoadStarted()));
|
||||
connect(page, SIGNAL(pageFinished(bool)),
|
||||
|
@ -47,6 +47,15 @@ WebPage *WebPageManager::createPage(QObject *parent) {
|
|||
return page;
|
||||
}
|
||||
|
||||
void WebPageManager::removePage(WebPage *page) {
|
||||
m_pages.removeOne(page);
|
||||
page->deleteLater();
|
||||
if (m_pages.isEmpty())
|
||||
createPage()->setFocus();
|
||||
else if (page == m_currentPage)
|
||||
m_pages.first()->setFocus();
|
||||
}
|
||||
|
||||
void WebPageManager::emitLoadStarted() {
|
||||
if (m_started.empty()) {
|
||||
logger() << "Load started";
|
||||
|
@ -110,10 +119,12 @@ void WebPageManager::reset() {
|
|||
m_timeout = -1;
|
||||
m_cookieJar->clearCookies();
|
||||
m_networkAccessManager->reset();
|
||||
m_pages.first()->resetLocalStorage();
|
||||
m_pages.first()->deleteLater();
|
||||
m_pages.clear();
|
||||
createPage(this)->setFocus();
|
||||
m_currentPage->resetLocalStorage();
|
||||
while (!m_pages.isEmpty()) {
|
||||
WebPage *page = m_pages.takeFirst();
|
||||
delete page;
|
||||
}
|
||||
createPage()->setFocus();
|
||||
}
|
||||
|
||||
NetworkCookieJar *WebPageManager::cookieJar() {
|
||||
|
|
|
@ -20,7 +20,8 @@ class WebPageManager : public QObject {
|
|||
QList<WebPage *> pages() const;
|
||||
void setCurrentPage(WebPage *);
|
||||
WebPage *currentPage() const;
|
||||
WebPage *createPage(QObject *parent);
|
||||
WebPage *createPage();
|
||||
void removePage(WebPage *);
|
||||
void setIgnoreSslErrors(bool);
|
||||
bool ignoreSslErrors();
|
||||
void setTimeout(int);
|
||||
|
|
10
src/WindowClose.cpp
Normal file
10
src/WindowClose.cpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "WindowClose.h"
|
||||
#include "WebPage.h"
|
||||
|
||||
WindowClose::WindowClose(WebPageManager *manager, QStringList &arguments, QObject *parent) : WindowCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void WindowClose::windowFound(WebPage *page) {
|
||||
page->remove();
|
||||
finish(true);
|
||||
}
|
12
src/WindowClose.h
Normal file
12
src/WindowClose.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "WindowCommand.h"
|
||||
|
||||
class WindowClose : public WindowCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowClose(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
|
||||
protected:
|
||||
virtual void windowFound(WebPage *);
|
||||
};
|
||||
|
27
src/WindowCommand.cpp
Normal file
27
src/WindowCommand.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include "WindowCommand.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
#include "ErrorMessage.h"
|
||||
|
||||
WindowCommand::WindowCommand(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void WindowCommand::start() {
|
||||
findWindow(arguments()[0]);
|
||||
}
|
||||
|
||||
void WindowCommand::findWindow(QString selector) {
|
||||
foreach(WebPage *page, manager()->pages()) {
|
||||
if (page->matchesWindowSelector(selector)) {
|
||||
windowFound(page);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
windowNotFound();
|
||||
}
|
||||
|
||||
void WindowCommand::windowNotFound() {
|
||||
finish(false,
|
||||
new ErrorMessage("NoSuchWindowError", "Unable to locate window."));
|
||||
}
|
21
src/WindowCommand.h
Normal file
21
src/WindowCommand.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef WINDOW_COMMAND_H
|
||||
#define WINDOW_COMMAND_H
|
||||
|
||||
#include "SocketCommand.h"
|
||||
|
||||
class WindowCommand : public SocketCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowCommand(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
virtual void start();
|
||||
|
||||
protected:
|
||||
virtual void windowFound(WebPage *) = 0;
|
||||
|
||||
private:
|
||||
void findWindow(QString);
|
||||
void windowNotFound();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,33 +1,10 @@
|
|||
#include "WindowFocus.h"
|
||||
#include "SocketCommand.h"
|
||||
#include "WebPage.h"
|
||||
#include "CommandFactory.h"
|
||||
#include "WebPageManager.h"
|
||||
#include "ErrorMessage.h"
|
||||
|
||||
WindowFocus::WindowFocus(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
|
||||
WindowFocus::WindowFocus(WebPageManager *manager, QStringList &arguments, QObject *parent) : WindowCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void WindowFocus::start() {
|
||||
focusWindow(arguments()[0]);
|
||||
}
|
||||
|
||||
void WindowFocus::windowNotFound() {
|
||||
finish(false, new ErrorMessage("Unable to locate window."));
|
||||
}
|
||||
|
||||
void WindowFocus::success(WebPage *page) {
|
||||
void WindowFocus::windowFound(WebPage *page) {
|
||||
page->setFocus();
|
||||
finish(true);
|
||||
}
|
||||
|
||||
void WindowFocus::focusWindow(QString selector) {
|
||||
foreach(WebPage *page, manager()->pages()) {
|
||||
if (page->matchesWindowSelector(selector)) {
|
||||
success(page);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
windowNotFound();
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
#include "SocketCommand.h"
|
||||
#include "WindowCommand.h"
|
||||
|
||||
class WindowFocus : public SocketCommand {
|
||||
class WindowFocus : public WindowCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowFocus(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
virtual void start();
|
||||
|
||||
private:
|
||||
void success(WebPage *);
|
||||
void windowNotFound();
|
||||
void focusWindow(QString);
|
||||
protected:
|
||||
virtual void windowFound(WebPage *);
|
||||
};
|
||||
|
||||
|
|
13
src/WindowMaximize.cpp
Normal file
13
src/WindowMaximize.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "WindowMaximize.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
|
||||
WindowMaximize::WindowMaximize(WebPageManager *manager, QStringList &arguments, QObject *parent) : WindowCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void WindowMaximize::windowFound(WebPage *page) {
|
||||
QDesktopWidget *desktop = QApplication::desktop();
|
||||
QRect area = desktop->availableGeometry();
|
||||
page->resize(area.width(), area.height());
|
||||
finish(true);
|
||||
}
|
12
src/WindowMaximize.h
Normal file
12
src/WindowMaximize.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "WindowCommand.h"
|
||||
|
||||
class WindowMaximize : public WindowCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowMaximize(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
|
||||
protected:
|
||||
virtual void windowFound(WebPage *);
|
||||
};
|
||||
|
12
src/WindowOpen.cpp
Normal file
12
src/WindowOpen.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "WindowOpen.h"
|
||||
#include "SocketCommand.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
|
||||
WindowOpen::WindowOpen(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void WindowOpen::start() {
|
||||
manager()->createPage();
|
||||
finish(true);
|
||||
}
|
10
src/WindowOpen.h
Normal file
10
src/WindowOpen.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "SocketCommand.h"
|
||||
|
||||
class WindowOpen : public SocketCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowOpen(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
virtual void start();
|
||||
};
|
||||
|
16
src/WindowResize.cpp
Normal file
16
src/WindowResize.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "WindowResize.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
|
||||
WindowResize::WindowResize(WebPageManager *manager, QStringList &arguments, QObject *parent) : WindowCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void WindowResize::windowFound(WebPage *page) {
|
||||
int width = arguments()[1].toInt();
|
||||
int height = arguments()[2].toInt();
|
||||
|
||||
page->resize(width, height);
|
||||
|
||||
finish(true);
|
||||
}
|
||||
|
12
src/WindowResize.h
Normal file
12
src/WindowResize.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "WindowCommand.h"
|
||||
|
||||
class WindowResize : public WindowCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowResize(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
|
||||
protected:
|
||||
virtual void windowFound(WebPage *);
|
||||
};
|
||||
|
17
src/WindowSize.cpp
Normal file
17
src/WindowSize.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include "WindowSize.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
#include "JsonSerializer.h"
|
||||
|
||||
WindowSize::WindowSize(WebPageManager *manager, QStringList &arguments, QObject *parent) : WindowCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
||||
void WindowSize::windowFound(WebPage *page) {
|
||||
QSize size = page->viewportSize();
|
||||
QVariantList elements;
|
||||
elements << size.width();
|
||||
elements << size.height();
|
||||
JsonSerializer serializer;
|
||||
QByteArray json = serializer.serialize(elements);
|
||||
finish(true, json);
|
||||
}
|
12
src/WindowSize.h
Normal file
12
src/WindowSize.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "WindowCommand.h"
|
||||
|
||||
class WindowSize : public WindowCommand {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowSize(WebPageManager *, QStringList &arguments, QObject *parent = 0);
|
||||
|
||||
protected:
|
||||
virtual void windowFound(WebPage *);
|
||||
};
|
||||
|
|
@ -66,7 +66,9 @@ Capybara = {
|
|||
text: function (index) {
|
||||
var node = this.getNode(index);
|
||||
var type = (node.type || node.tagName).toLowerCase();
|
||||
if (type == "textarea") {
|
||||
if (!this.isNodeVisible(node)) {
|
||||
return '';
|
||||
} else if (type == "textarea") {
|
||||
return node.innerHTML;
|
||||
} else {
|
||||
return node.innerText || node.textContent;
|
||||
|
@ -286,20 +288,34 @@ Capybara = {
|
|||
CapybaraInvocation.keypress(value[strindex]);
|
||||
}
|
||||
|
||||
if (value == '')
|
||||
this.trigger(index, "change");
|
||||
} else if (type === "checkbox" || type === "radio") {
|
||||
if (node.checked != (value === "true")) {
|
||||
this.leftClick(index);
|
||||
}
|
||||
|
||||
} else if (type === "file") {
|
||||
this.attachedFiles = Array.prototype.slice.call(arguments, 1);
|
||||
this.leftClick(index);
|
||||
|
||||
} else if (this.isContentEditable(node)) {
|
||||
var content = document.createTextNode(value);
|
||||
node.innerHTML = '';
|
||||
node.appendChild(content);
|
||||
} else {
|
||||
node.value = value;
|
||||
}
|
||||
},
|
||||
|
||||
isContentEditable: function(node) {
|
||||
if (node.contentEditable == 'true') {
|
||||
return true;
|
||||
} else if (node.contentEditable == 'false') {
|
||||
return false;
|
||||
} else if (node.contentEditable == 'inherit') {
|
||||
return this.isContentEditable(node.parentNode);
|
||||
}
|
||||
},
|
||||
|
||||
focus: function(index) {
|
||||
this.getNode(index).focus();
|
||||
},
|
||||
|
|
|
@ -21,7 +21,7 @@ CHECK_COMMAND(GetCookies)
|
|||
CHECK_COMMAND(SetProxy)
|
||||
CHECK_COMMAND(ConsoleMessages)
|
||||
CHECK_COMMAND(CurrentUrl)
|
||||
CHECK_COMMAND(ResizeWindow)
|
||||
CHECK_COMMAND(WindowResize)
|
||||
CHECK_COMMAND(IgnoreSslErrors)
|
||||
CHECK_COMMAND(SetSkipImageLoading)
|
||||
CHECK_COMMAND(WindowFocus)
|
||||
|
@ -42,3 +42,9 @@ CHECK_COMMAND(SetUrlBlacklist)
|
|||
CHECK_COMMAND(Title)
|
||||
CHECK_COMMAND(Version)
|
||||
CHECK_COMMAND(FindCss)
|
||||
CHECK_COMMAND(WindowClose)
|
||||
CHECK_COMMAND(WindowOpen)
|
||||
CHECK_COMMAND(WindowSize)
|
||||
CHECK_COMMAND(WindowMaximize)
|
||||
CHECK_COMMAND(GoBack)
|
||||
CHECK_COMMAND(GoForward)
|
||||
|
|
|
@ -7,6 +7,13 @@ PRECOMPILED_DIR = $${BUILD_DIR}
|
|||
OBJECTS_DIR = $${BUILD_DIR}
|
||||
MOC_DIR = $${BUILD_DIR}
|
||||
HEADERS = \
|
||||
GoForward.h \
|
||||
GoBack.h \
|
||||
WindowMaximize.h \
|
||||
WindowSize.h \
|
||||
WindowCommand.h \
|
||||
WindowOpen.h \
|
||||
WindowClose.h \
|
||||
Version.h \
|
||||
EnableLogging.h \
|
||||
Authenticate.h \
|
||||
|
@ -18,7 +25,7 @@ HEADERS = \
|
|||
JavascriptConfirmMessages.h \
|
||||
JavascriptPromptMessages.h \
|
||||
IgnoreSslErrors.h \
|
||||
ResizeWindow.h \
|
||||
WindowResize.h \
|
||||
CurrentUrl.h \
|
||||
ConsoleMessages.h \
|
||||
WebPage.h \
|
||||
|
@ -71,6 +78,13 @@ HEADERS = \
|
|||
IgnoreDebugOutput.h
|
||||
|
||||
SOURCES = \
|
||||
GoForward.cpp \
|
||||
GoBack.cpp \
|
||||
WindowMaximize.cpp \
|
||||
WindowSize.cpp \
|
||||
WindowCommand.cpp \
|
||||
WindowOpen.cpp \
|
||||
WindowClose.cpp \
|
||||
Version.cpp \
|
||||
EnableLogging.cpp \
|
||||
Authenticate.cpp \
|
||||
|
@ -82,7 +96,7 @@ SOURCES = \
|
|||
JavascriptConfirmMessages.cpp \
|
||||
JavascriptPromptMessages.cpp \
|
||||
IgnoreSslErrors.cpp \
|
||||
ResizeWindow.cpp \
|
||||
WindowResize.cpp \
|
||||
CurrentUrl.cpp \
|
||||
ConsoleMessages.cpp \
|
||||
main.cpp \
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "NAME.h"
|
||||
#include "SocketCommand.h"
|
||||
#include "WebPage.h"
|
||||
#include "WebPageManager.h"
|
||||
|
||||
NAME::NAME(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#include "Command.h"
|
||||
|
||||
class WebPage;
|
||||
#include "SocketCommand.h"
|
||||
|
||||
class NAME : public SocketCommand {
|
||||
Q_OBJECT
|
||||
|
|
Loading…
Reference in a new issue