webpilot 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +6 -0
- data/Rakefile +7 -0
- data/lib/webpilot.rb +133 -0
- data/spec/basic_spec.rb +19 -0
- data/spec/browsers_spec.rb +62 -0
- data/spec/spec_helper.rb +5 -0
- metadata +57 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/Rakefile
ADDED
data/lib/webpilot.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'headless'
|
3
|
+
require 'log4r'
|
4
|
+
require 'selenium-webdriver'
|
5
|
+
|
6
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
class WebPilot
|
9
|
+
include Log4r
|
10
|
+
attr_reader :driver, :logger
|
11
|
+
|
12
|
+
extend Forwardable
|
13
|
+
def_delegators :@driver, :close, :current_url, :execute_script, :navigate,
|
14
|
+
:page_source, :quit, :switch_to, :window_handle, :window_handles
|
15
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
16
|
+
|
17
|
+
def initialize(options={})
|
18
|
+
@browser = options[:browser] || :firefox
|
19
|
+
@is_headless = options[:is_headless]
|
20
|
+
@pause_time = options[:pause_time] || 0.3
|
21
|
+
@screenshot_dir = options[:screenshot_dir]
|
22
|
+
@timeout = options[:timeout] || 8
|
23
|
+
|
24
|
+
case
|
25
|
+
when options[:logger].nil?
|
26
|
+
@logger = Logger.new 'debug_log'
|
27
|
+
null_outputter = IOOutputter.new 'null', File.open('/dev/null', 'w')
|
28
|
+
when options[:logger].is_a?(Logger)
|
29
|
+
@logger = options[:logger]
|
30
|
+
when options[:logger] == 'STDOUT'
|
31
|
+
@logger = Logger.new 'debug_log'
|
32
|
+
@logger.outputters = Outputter.stdout
|
33
|
+
@logger.level = DEBUG
|
34
|
+
when options[:logger] == 'STDERR'
|
35
|
+
@logger = Logger.new 'debug_log'
|
36
|
+
@logger.outputters = Outputter.stderr
|
37
|
+
@logger.level = DEBUG
|
38
|
+
end
|
39
|
+
|
40
|
+
if @is_headless
|
41
|
+
@headless = Headless.new
|
42
|
+
@headless.start
|
43
|
+
end
|
44
|
+
|
45
|
+
@driver = Selenium::WebDriver.for @browser
|
46
|
+
end
|
47
|
+
|
48
|
+
# Close all windows that have a current url of "about:blank". Must follow this with a call to
|
49
|
+
# `#switch_to`, so that you know what window you're on.
|
50
|
+
def close_blank_windows
|
51
|
+
@driver.window_handles.each do |handle|
|
52
|
+
@driver.switch_to.window(handle)
|
53
|
+
@driver.close if @driver.current_url == 'about:blank'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Enlargens the text of an element, using `method` and `locator`, by changing the `font-size`
|
58
|
+
# in the style to be `3em`. It uses the following Javascript:
|
59
|
+
#
|
60
|
+
# hlt = function(c) { c.style.fontSize='3em'; }; return hlt(arguments[0]);
|
61
|
+
def enlargen(method, locator)
|
62
|
+
@logger.debug " enlargen: Waiting up to #{@timeout} seconds to find_element(#{method}, #{locator})..."
|
63
|
+
wait = Selenium::WebDriver::Wait.new(:timeout => @timeout)
|
64
|
+
wait.until { find_element(method, locator) }
|
65
|
+
element = find_element(method, locator)
|
66
|
+
execute_script("hlt = function(c) { c.style.fontSize='3em'; }; return hlt(arguments[0]);", element)
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_element(method, selector, options={})
|
70
|
+
retries = 4
|
71
|
+
sleep 0.1 # based on http://groups.google.com/group/ruby-capybara/browse_thread/thread/5e182835a8293def fixes "NS_ERROR_ILLEGAL_VALUE"
|
72
|
+
begin
|
73
|
+
@driver.find_element(method, selector)
|
74
|
+
rescue Selenium::WebDriver::Error::NoSuchElementError, Selenium::WebDriver::Error::TimeOutError => e
|
75
|
+
return nil if options[:no_raise]
|
76
|
+
raise e
|
77
|
+
rescue Selenium::WebDriver::Error::InvalidSelectorError => e
|
78
|
+
raise e if retries == 0
|
79
|
+
@logger.info "Caught a Selenium::WebDriver::Error::InvalidSelectorError: #{e}"
|
80
|
+
@logger.info "Retrying..."
|
81
|
+
pause 2
|
82
|
+
retries -= 1
|
83
|
+
retry
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def highlight(method, locator, ancestors=0)
|
88
|
+
wait = Selenium::WebDriver::Wait.new(:timeout => @timeout)
|
89
|
+
wait.until { find_element(method, locator) }
|
90
|
+
element = find_element(method, locator)
|
91
|
+
execute_script("hlt = function(c) { c.style.border='solid 1px rgb(255, 16, 16)'; }; return hlt(arguments[0]);", element)
|
92
|
+
parents = ""
|
93
|
+
red = 255
|
94
|
+
|
95
|
+
ancestors.times do
|
96
|
+
parents << ".parentNode"
|
97
|
+
red -= (12*8 / ancestors)
|
98
|
+
execute_script("hlt = function(c) { c#{parents}.style.border='solid 1px rgb(#{red}, 0, 0)'; }; return hlt(arguments[0]);", element)
|
99
|
+
end
|
100
|
+
pause
|
101
|
+
end
|
102
|
+
|
103
|
+
def pause(time = nil)
|
104
|
+
@logger.debug " breathing..."
|
105
|
+
sleep (time || @pause_time)
|
106
|
+
end
|
107
|
+
|
108
|
+
def quit
|
109
|
+
@driver.quit
|
110
|
+
@headless.destroy if @is_headless
|
111
|
+
end
|
112
|
+
|
113
|
+
# Deselect all `<option>s` within a `<select>`, suppressing any `UnsupportedOperationError`
|
114
|
+
# that Selenium may throw
|
115
|
+
def safe_deselect_all(el)
|
116
|
+
el.deselect_all
|
117
|
+
rescue Selenium::WebDriver::Error::UnsupportedOperationError
|
118
|
+
end
|
119
|
+
|
120
|
+
# Select a frame by its `id`
|
121
|
+
def select_frame(id)
|
122
|
+
@driver.switch_to().frame(id)
|
123
|
+
pause
|
124
|
+
end
|
125
|
+
|
126
|
+
# Create and execute a `Selenium::WebDriver::Wait` for finding an element by `method` and `selector`
|
127
|
+
def wait_for(method, locator)
|
128
|
+
@logger.debug " wait_for: Waiting up to #{@timeout} seconds to find_element(#{method}, #{locator})..."
|
129
|
+
wait = Selenium::WebDriver::Wait.new(:timeout => @timeout)
|
130
|
+
sleep 0.1 # based on http://groups.google.com/group/ruby-capybara/browse_thread/thread/5e182835a8293def fixes "NS_ERROR_ILLEGAL_VALUE"
|
131
|
+
wait.until { driver.find_element(method, locator) }
|
132
|
+
end
|
133
|
+
end
|
data/spec/basic_spec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
|
2
|
+
|
3
|
+
describe "WebPilot" do
|
4
|
+
before(:each) do
|
5
|
+
@driver = WebPilot.new(:is_headless => true)
|
6
|
+
end
|
7
|
+
|
8
|
+
after(:each) do
|
9
|
+
@driver.quit
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should do some basics" do
|
13
|
+
@driver.navigate.to "http://www.google.com"
|
14
|
+
@driver.find_element(:css, '#gbqfq').send_keys('mwrc ruby')
|
15
|
+
@driver.find_element(:css, '#gbqfb').click
|
16
|
+
@driver.wait_for(:xpath, "//ol[@id='rso']/li//a")
|
17
|
+
@driver.find_element(:xpath, "//ol[@id='rso']/li//a").click
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
|
2
|
+
|
3
|
+
describe "WebPilot" do
|
4
|
+
context "default" do
|
5
|
+
before(:each) do
|
6
|
+
@driver = WebPilot.new(:is_headless => true)
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
@driver.quit
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should launch firefox by default" do
|
14
|
+
@driver.navigate.to "http://www.google.com"
|
15
|
+
ps_firefox = `ps -ef | grep "[f]irefox"`
|
16
|
+
ps_firefox['foreground'].should_not == nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "firefox" do
|
21
|
+
before(:each) do
|
22
|
+
@driver = WebPilot.new(:browser => :firefox, :is_headless => true)
|
23
|
+
end
|
24
|
+
|
25
|
+
after(:each) do
|
26
|
+
@driver.quit
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should launch firefox when specified" do
|
30
|
+
@driver.navigate.to "http://www.google.com"
|
31
|
+
ps_firefox = `ps -ef | grep "[f]irefox"`
|
32
|
+
ps_firefox['foreground'].should_not == nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "chrome" do
|
37
|
+
before(:each) do
|
38
|
+
begin
|
39
|
+
@driver = WebPilot.new(:browser => :chrome, :is_headless => true)
|
40
|
+
rescue Selenium::WebDriver::Error::WebDriverError => e
|
41
|
+
@driver = nil
|
42
|
+
@pending = true
|
43
|
+
@exception = e
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
after(:each) do
|
48
|
+
@driver.quit unless @driver.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should launch chrome when specified" do
|
52
|
+
if @driver.nil? and @pending
|
53
|
+
pending(@exception)
|
54
|
+
else
|
55
|
+
@driver.navigate.to "http://www.google.com"
|
56
|
+
sleep 5
|
57
|
+
ps_chrome = `ps -ef | grep "[c]hrom"`
|
58
|
+
ps_chrome['foreground'].should_not == nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: webpilot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sam Rawlins
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-26 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: WebPilot is a wrapper for Selenium::WebDriver that makes the library
|
15
|
+
more ruby-esque. Rather than inherit from Selenium::WebDriver, an instance of WebPilot
|
16
|
+
has a Selenium::WebDriver as an attribute. It serves other functions rather than
|
17
|
+
just extending Selenium::WebDriver, so it also wraps a logger, saves screenshots,
|
18
|
+
etc.
|
19
|
+
email:
|
20
|
+
- katt-core@listserv.arizona.edu
|
21
|
+
executables: []
|
22
|
+
extensions: []
|
23
|
+
extra_rdoc_files: []
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- Gemfile
|
27
|
+
- Rakefile
|
28
|
+
- lib/webpilot.rb
|
29
|
+
- spec/basic_spec.rb
|
30
|
+
- spec/browsers_spec.rb
|
31
|
+
- spec/spec_helper.rb
|
32
|
+
homepage:
|
33
|
+
licenses: []
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubyforge_project:
|
52
|
+
rubygems_version: 1.8.17
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: A facade for Selenium::WebDriver to make the library more ruby-esque.
|
56
|
+
test_files: []
|
57
|
+
has_rdoc:
|