yellowlab-akephalos 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT_LICENSE +20 -0
- data/README.md +109 -0
- data/bin/akephalos +88 -0
- data/lib/akephalos.rb +19 -0
- data/lib/akephalos/capybara.rb +343 -0
- data/lib/akephalos/client.rb +181 -0
- data/lib/akephalos/client/cookies.rb +73 -0
- data/lib/akephalos/client/filter.rb +120 -0
- data/lib/akephalos/configuration.rb +49 -0
- data/lib/akephalos/console.rb +32 -0
- data/lib/akephalos/cucumber.rb +6 -0
- data/lib/akephalos/htmlunit.rb +36 -0
- data/lib/akephalos/htmlunit/ext/confirm_handler.rb +18 -0
- data/lib/akephalos/htmlunit/ext/http_method.rb +30 -0
- data/lib/akephalos/node.rb +188 -0
- data/lib/akephalos/page.rb +113 -0
- data/lib/akephalos/remote_client.rb +92 -0
- data/lib/akephalos/server.rb +79 -0
- data/lib/akephalos/version.rb +3 -0
- data/src/htmlunit/apache-mime4j-0.6.jar +0 -0
- data/src/htmlunit/commons-codec-1.4.jar +0 -0
- data/src/htmlunit/commons-collections-3.2.1.jar +0 -0
- data/src/htmlunit/commons-io-1.4.jar +0 -0
- data/src/htmlunit/commons-lang-2.4.jar +0 -0
- data/src/htmlunit/commons-logging-1.1.1.jar +0 -0
- data/src/htmlunit/cssparser-0.9.5.jar +0 -0
- data/src/htmlunit/htmlunit-2.8.jar +0 -0
- data/src/htmlunit/htmlunit-core-js-2.8.jar +0 -0
- data/src/htmlunit/httpclient-4.0.1.jar +0 -0
- data/src/htmlunit/httpcore-4.0.1.jar +0 -0
- data/src/htmlunit/httpmime-4.0.1.jar +0 -0
- data/src/htmlunit/nekohtml-1.9.14.jar +0 -0
- data/src/htmlunit/sac-1.3.jar +0 -0
- data/src/htmlunit/serializer-2.7.1.jar +0 -0
- data/src/htmlunit/xalan-2.7.1.jar +0 -0
- data/src/htmlunit/xercesImpl-2.9.1.jar +0 -0
- data/src/htmlunit/xml-apis-1.3.04.jar +0 -0
- metadata +167 -0
data/MIT_LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2010 Bernerd Schaefer
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Akephalos
|
|
2
|
+
Akephalos is a full-stack headless browser for integration testing with
|
|
3
|
+
Capybara. It is built on top of [HtmlUnit](http://htmlunit.sourceforge.net),
|
|
4
|
+
a GUI-less browser for the Java platform, but can be run on both JRuby and
|
|
5
|
+
MRI with no need for JRuby to be installed on the system.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
gem install akephalos
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
Configuring akephalos is as simple as requiring it and setting Capybara's
|
|
14
|
+
javascript driver:
|
|
15
|
+
|
|
16
|
+
require 'akephalos'
|
|
17
|
+
Capybara.javascript_driver = :akephalos
|
|
18
|
+
|
|
19
|
+
## Basic Usage
|
|
20
|
+
|
|
21
|
+
Akephalos provides a driver for Capybara, so using Akephalos is no
|
|
22
|
+
different than using Selenium or Rack::Test. For a full usage guide, check
|
|
23
|
+
out Capybara's DSL [documentation](http://github.com/jnicklas/capybara). It
|
|
24
|
+
makes no assumptions about the testing framework being used, and works with
|
|
25
|
+
RSpec, Cucumber, and Test::Unit.
|
|
26
|
+
|
|
27
|
+
Here's some sample RSpec code:
|
|
28
|
+
|
|
29
|
+
describe "Home Page" do
|
|
30
|
+
before { visit "/" }
|
|
31
|
+
context "searching" do
|
|
32
|
+
before do
|
|
33
|
+
fill_in "Search", :with => "akephalos"
|
|
34
|
+
click_button "Go"
|
|
35
|
+
end
|
|
36
|
+
it "returns results" { page.should have_css("#results") }
|
|
37
|
+
it "includes the search term" { page.should have_content("akephalos") }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
## Configuration
|
|
42
|
+
|
|
43
|
+
There are now a few configuration options available through Capybara's new
|
|
44
|
+
`register_driver` API.
|
|
45
|
+
|
|
46
|
+
### Using a different browser
|
|
47
|
+
|
|
48
|
+
HtmlUnit supports a few browser implementations, and you can choose which
|
|
49
|
+
browser you would like to use through Akephalos. By default, Akephalos uses
|
|
50
|
+
Firefox 3.6.
|
|
51
|
+
|
|
52
|
+
Capybara.register_driver :akephalos do |app|
|
|
53
|
+
# available options:
|
|
54
|
+
# :ie6, :ie7, :ie8, :firefox_3, :firefox_3_6
|
|
55
|
+
Capybara::Driver::Akephalos.new(app, :browser => :ie8)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
### Ignoring javascript errors
|
|
59
|
+
|
|
60
|
+
By default HtmlUnit (and Akephalos) will raise an exception when an error
|
|
61
|
+
is encountered in javascript files. This is generally desireable, except
|
|
62
|
+
that certain libraries aren't supported by HtmlUnit. If possible, it's
|
|
63
|
+
best to keep the default behavior, and use Filters (see below) to mock
|
|
64
|
+
offending libraries. If needed, however, you can configure Akephalos to
|
|
65
|
+
ignore javascript errors.
|
|
66
|
+
|
|
67
|
+
Capybara.register_driver :akephalos do |app|
|
|
68
|
+
Capybara::Driver::Akephalos.new(app, :validate_scripts => false)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
### Setting the HtmlUnit log level
|
|
72
|
+
|
|
73
|
+
By default it uses the 'fatal' level. You can change that like this:
|
|
74
|
+
|
|
75
|
+
Capybara.register_driver :akephalos do |app|
|
|
76
|
+
# available options
|
|
77
|
+
# "trace", "debug", "info", "warn", "error", or "fatal"
|
|
78
|
+
Capybara::Driver::Akephalos.new(app, :htmlunit_log_level => 'fatal')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
### Running Akephalos with Spork
|
|
82
|
+
|
|
83
|
+
Spork.prefork do
|
|
84
|
+
...
|
|
85
|
+
Akephalos::RemoteClient.manager
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
Spork.each_run do
|
|
89
|
+
Thread.current['DRb'] = { 'server' => DRb::DRbServer.new }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
More info at : [sporking-with-akephalos](http://spacevatican.org/2011/7/3/sporking-with-akephalos)
|
|
93
|
+
|
|
94
|
+
## More
|
|
95
|
+
|
|
96
|
+
* [bin/akephalos](http://bernerdschaefer.github.com/akephalos/akephalos-bin.html)
|
|
97
|
+
allows you to start an interactive shell or DRb server, as well as perform
|
|
98
|
+
other maintenance features.
|
|
99
|
+
|
|
100
|
+
* [Filters](http://bernerdschaefer.github.com/akephalos/filters.html) allows
|
|
101
|
+
you to declare mock responses for external resources and services requested
|
|
102
|
+
by the browser.
|
|
103
|
+
|
|
104
|
+
## Resources
|
|
105
|
+
|
|
106
|
+
* [API Documentation](http://bernerdschaefer.github.com/akephalos/api)
|
|
107
|
+
* [Source code](http://github.com/bernerdschaefer/akephalos) and
|
|
108
|
+
[issues](http://github.com/bernerdschaefer/akephalos/issues) are hosted on
|
|
109
|
+
github.
|
data/bin/akephalos
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# vim:set filetype=ruby:
|
|
3
|
+
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "optparse"
|
|
6
|
+
|
|
7
|
+
options = { :interactive => false }
|
|
8
|
+
|
|
9
|
+
parser = OptionParser.new do |opts|
|
|
10
|
+
opts.banner = "Usage: akephalos [--interactive, --use-htmlunit-snapshot] | [--server] <port>"
|
|
11
|
+
opts.on("-s", "--server", "Run in server mode (default)")
|
|
12
|
+
opts.on("-i", "--interactive", "Run in interactive mode") { options[:interactive] = true }
|
|
13
|
+
opts.on("--use-htmlunit-snapshot", "Use the snapshot of htmlunit") { options[:use_htmlunit_snapshot] = true }
|
|
14
|
+
|
|
15
|
+
opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
|
|
16
|
+
end
|
|
17
|
+
parser.parse!
|
|
18
|
+
|
|
19
|
+
root = Pathname(__FILE__).expand_path.dirname.parent
|
|
20
|
+
lib = root + 'lib'
|
|
21
|
+
src = root + 'src'
|
|
22
|
+
|
|
23
|
+
case
|
|
24
|
+
when options[:use_htmlunit_snapshot]
|
|
25
|
+
require "fileutils"
|
|
26
|
+
|
|
27
|
+
FileUtils.mkdir_p("vendor/htmlunit")
|
|
28
|
+
Dir["vendor/htmlunit/*.jar"].each { |jar| File.unlink(jar) }
|
|
29
|
+
|
|
30
|
+
Dir.chdir("vendor") do
|
|
31
|
+
$stdout.print "Downloading latest snapshot... "
|
|
32
|
+
$stdout.flush
|
|
33
|
+
%x[curl -O http://build.canoo.com/htmlunit/artifacts/htmlunit-2.9-SNAPSHOT-with-dependencies.zip &> /dev/null]
|
|
34
|
+
puts "done"
|
|
35
|
+
|
|
36
|
+
$stdout.print "Extracting dependencies... "
|
|
37
|
+
$stdout.flush
|
|
38
|
+
%x[unzip -j -d htmlunit htmlunit-2.9-SNAPSHOT-with-dependencies.zip htmlunit-2.9-SNAPSHOT/lib htmlunit-2.9-SNAPSHOT/lib/* &> /dev/null]
|
|
39
|
+
puts "done"
|
|
40
|
+
|
|
41
|
+
File.unlink "htmlunit-2.9-SNAPSHOT-with-dependencies.zip"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
$stdout.puts "="*40
|
|
45
|
+
$stdout.puts "The latest HtmlUnit snapshot has been extracted to vendor/htmlunit!"
|
|
46
|
+
when options[:interactive]
|
|
47
|
+
$:.unshift('vendor', lib, src)
|
|
48
|
+
require 'rubygems'
|
|
49
|
+
require 'akephalos'
|
|
50
|
+
require 'akephalos/console'
|
|
51
|
+
Akephalos::Console.start
|
|
52
|
+
else
|
|
53
|
+
unless port = ARGV[0]
|
|
54
|
+
puts parser.help
|
|
55
|
+
exit
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if RUBY_PLATFORM == "java"
|
|
59
|
+
$:.unshift("vendor", lib, src)
|
|
60
|
+
require 'akephalos/server'
|
|
61
|
+
Akephalos::Server.start!(port)
|
|
62
|
+
else
|
|
63
|
+
require 'rubygems'
|
|
64
|
+
require 'jruby-jars'
|
|
65
|
+
|
|
66
|
+
jruby = JRubyJars.core_jar_path
|
|
67
|
+
jruby_stdlib = JRubyJars.stdlib_jar_path
|
|
68
|
+
|
|
69
|
+
java_args = [
|
|
70
|
+
"-Xmx512M",
|
|
71
|
+
"-cp", [JRubyJars.core_jar_path, JRubyJars.stdlib_jar_path].join(File::PATH_SEPARATOR),
|
|
72
|
+
"org.jruby.Main"
|
|
73
|
+
]
|
|
74
|
+
ruby_args = [
|
|
75
|
+
"-Ku",
|
|
76
|
+
"-I", ["vendor", lib, src].join(File::PATH_SEPARATOR),
|
|
77
|
+
"-r", "akephalos/server",
|
|
78
|
+
"-e", "Akephalos::Server.start!(#{port.inspect})"
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
# Bundler sets ENV["RUBYOPT"] to automatically load bundler/setup.rb, but
|
|
82
|
+
# since the akephalos server doesn't have any gem dependencies and is
|
|
83
|
+
# always executed with the same context, we clear RUBYOPT before running
|
|
84
|
+
# exec.
|
|
85
|
+
ENV["RUBYOPT"] = ""
|
|
86
|
+
exec("java", *(java_args + ruby_args))
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/akephalos.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# **Akephalos** is a cross-platform Ruby interface for *HtmlUnit*, a headless
|
|
2
|
+
# browser for the Java platform.
|
|
3
|
+
#
|
|
4
|
+
# The only requirement is that a Java runtime is available.
|
|
5
|
+
#
|
|
6
|
+
require 'java' if RUBY_PLATFORM == 'java'
|
|
7
|
+
require 'pathname'
|
|
8
|
+
|
|
9
|
+
module Akephalos
|
|
10
|
+
BIN_DIR = Pathname(__FILE__).expand_path.dirname.parent + 'bin'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
require 'akephalos/client'
|
|
14
|
+
require 'capybara'
|
|
15
|
+
require 'akephalos/capybara'
|
|
16
|
+
|
|
17
|
+
Capybara.register_driver :akephalos do |app|
|
|
18
|
+
Capybara::Driver::Akephalos.new(app)
|
|
19
|
+
end
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# Driver class exposed to Capybara. It implements Capybara's full driver API,
|
|
2
|
+
# and is the entry point for interaction between the test suites and HtmlUnit.
|
|
3
|
+
#
|
|
4
|
+
# This class and +Capybara::Driver::Akephalos::Node+ are written to run on both
|
|
5
|
+
# MRI and JRuby, and is agnostic whether the Akephalos::Client instance is used
|
|
6
|
+
# directly or over DRb.
|
|
7
|
+
class Capybara::Driver::Akephalos < Capybara::Driver::Base
|
|
8
|
+
|
|
9
|
+
# Akephalos-specific implementation for Capybara's Driver::Node class.
|
|
10
|
+
class Node < Capybara::Driver::Node
|
|
11
|
+
|
|
12
|
+
# @api capybara
|
|
13
|
+
# @return [String] the inner text of the node
|
|
14
|
+
def text
|
|
15
|
+
native.text
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @api capybara
|
|
19
|
+
# @param [String] name attribute name
|
|
20
|
+
# @return [String] the attribute value
|
|
21
|
+
def [](name)
|
|
22
|
+
name = name.to_s
|
|
23
|
+
case name
|
|
24
|
+
when 'checked'
|
|
25
|
+
native.checked?
|
|
26
|
+
else
|
|
27
|
+
native[name.to_s]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @api capybara
|
|
32
|
+
# @return [String, Array<String>] the form element's value
|
|
33
|
+
def value
|
|
34
|
+
native.value
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Set the form element's value.
|
|
38
|
+
#
|
|
39
|
+
# @api capybara
|
|
40
|
+
# @param [String] value the form element's new value
|
|
41
|
+
def set(value)
|
|
42
|
+
if tag_name == 'textarea'
|
|
43
|
+
native.value = value.to_s
|
|
44
|
+
elsif tag_name == 'input' and type == 'radio'
|
|
45
|
+
click
|
|
46
|
+
elsif tag_name == 'input' and type == 'checkbox'
|
|
47
|
+
if value != self['checked']
|
|
48
|
+
click
|
|
49
|
+
end
|
|
50
|
+
elsif tag_name == 'input'
|
|
51
|
+
native.value = value.to_s
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @api capybara
|
|
56
|
+
def select_option
|
|
57
|
+
native.click
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Unselect an option from a select box.
|
|
61
|
+
#
|
|
62
|
+
# @api capybara
|
|
63
|
+
def unselect_option
|
|
64
|
+
unless select_node.multiple_select?
|
|
65
|
+
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
native.unselect
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Click the element.
|
|
72
|
+
def click
|
|
73
|
+
native.click
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Drag the element on top of the target element.
|
|
77
|
+
#
|
|
78
|
+
# @api capybara
|
|
79
|
+
# @param [Node] element the target element
|
|
80
|
+
def drag_to(element)
|
|
81
|
+
trigger('mousedown')
|
|
82
|
+
element.trigger('mousemove')
|
|
83
|
+
element.trigger('mouseup')
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @api capybara
|
|
87
|
+
# @return [String] the element's tag name
|
|
88
|
+
def tag_name
|
|
89
|
+
native.tag_name
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @api capybara
|
|
93
|
+
# @return [true, false] the element's visiblity
|
|
94
|
+
def visible?
|
|
95
|
+
native.visible?
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @api capybara
|
|
99
|
+
# @return [true, false] the element's visiblity
|
|
100
|
+
def checked?
|
|
101
|
+
native.checked?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @api capybara
|
|
105
|
+
# @return [true, false] the element's visiblity
|
|
106
|
+
def selected?
|
|
107
|
+
native.selected?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# @api capybara
|
|
111
|
+
# @return [String] the XPath to locate the node
|
|
112
|
+
def path
|
|
113
|
+
native.xpath
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Trigger an event on the element.
|
|
117
|
+
#
|
|
118
|
+
# @api capybara
|
|
119
|
+
# @param [String] event the event to trigger
|
|
120
|
+
def trigger(event)
|
|
121
|
+
native.fire_event(event.to_s)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @api capybara
|
|
125
|
+
# @param [String] selector XPath query
|
|
126
|
+
# @return [Array<Node>] the matched nodes
|
|
127
|
+
def find(selector)
|
|
128
|
+
nodes = []
|
|
129
|
+
native.find(selector).each { |node| nodes << self.class.new(self, node) }
|
|
130
|
+
nodes
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
protected
|
|
134
|
+
|
|
135
|
+
# @return [true, false] whether the node allows multiple-option selection (if the node is a select).
|
|
136
|
+
def multiple_select?
|
|
137
|
+
tag_name == "select" && native.multiple_select?
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
# Return all child nodes which match the selector criteria.
|
|
143
|
+
#
|
|
144
|
+
# @api capybara
|
|
145
|
+
# @return [Array<Node>] the matched nodes
|
|
146
|
+
def all_unfiltered(selector)
|
|
147
|
+
nodes = []
|
|
148
|
+
native.find(selector).each { |node| nodes << self.class.new(driver, node) }
|
|
149
|
+
nodes
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# @return [String] the node's type attribute
|
|
153
|
+
def type
|
|
154
|
+
native[:type]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @return [Node] the select node, if this is an option node
|
|
158
|
+
def select_node
|
|
159
|
+
find('./ancestor::select').first
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
attr_reader :app, :rack_server, :options
|
|
164
|
+
|
|
165
|
+
# Creates a new instance of the Akephalos Driver for Capybara. The driver is
|
|
166
|
+
# registered with Capybara by a name, so that it can be chosen when
|
|
167
|
+
# Capybara's javascript_driver is changed. By default, Akephalos is
|
|
168
|
+
# registered like this:
|
|
169
|
+
#
|
|
170
|
+
# Capybara.register_driver :akephalos do |app|
|
|
171
|
+
# Capybara::Akephalos::Driver.new(
|
|
172
|
+
# app,
|
|
173
|
+
# :browser => :firefox_3_6,
|
|
174
|
+
# :validate_scripts => true
|
|
175
|
+
# )
|
|
176
|
+
# end
|
|
177
|
+
#
|
|
178
|
+
# @param app the Rack application to run
|
|
179
|
+
# @param [Hash] options the Akephalos configuration options
|
|
180
|
+
# @option options [Symbol] :browser (:firefox_3_6) the browser
|
|
181
|
+
# compatibility mode to run in. Available options:
|
|
182
|
+
# :firefox_3_6
|
|
183
|
+
# :firefox_3
|
|
184
|
+
# :ie6
|
|
185
|
+
# :ie7
|
|
186
|
+
# :ie8
|
|
187
|
+
#
|
|
188
|
+
# @option options [true, false] :validate_scripts (true) whether to raise
|
|
189
|
+
# exceptions on script errors
|
|
190
|
+
#
|
|
191
|
+
def initialize(app, options = {})
|
|
192
|
+
@app = app
|
|
193
|
+
@options = options
|
|
194
|
+
@rack_server = Capybara::Server.new(@app)
|
|
195
|
+
@rack_server.boot if Capybara.run_server
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Visit the given path in the browser.
|
|
199
|
+
#
|
|
200
|
+
# @param [String] path relative path to visit
|
|
201
|
+
def visit(path)
|
|
202
|
+
browser.visit(url(path))
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# @return [String] the page's original source
|
|
206
|
+
def source
|
|
207
|
+
page.source
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# @return [String] the page's modified source
|
|
211
|
+
# page.modified_source will return a string with
|
|
212
|
+
# html entities converted into the unicode equivalent
|
|
213
|
+
# but the string will be marked as ASCII-8BIT
|
|
214
|
+
# which causes conversion issues so we force the encoding
|
|
215
|
+
# to UTF-8 (ruby 1.9 only)
|
|
216
|
+
def body
|
|
217
|
+
body_source = page.modified_source
|
|
218
|
+
|
|
219
|
+
if body_source.respond_to?(:force_encoding)
|
|
220
|
+
body_source.force_encoding("UTF-8")
|
|
221
|
+
else
|
|
222
|
+
body_source
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# @return [Hash{String => String}] the page's response headers
|
|
227
|
+
def response_headers
|
|
228
|
+
page.response_headers
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# @return [Integer] the response's status code
|
|
232
|
+
def status_code
|
|
233
|
+
page.status_code
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Execute the given block within the context of a specified frame.
|
|
237
|
+
#
|
|
238
|
+
# @param [String] frame_id the frame's id
|
|
239
|
+
# @raise [Capybara::ElementNotFound] if the frame is not found
|
|
240
|
+
def within_frame(frame_id, &block)
|
|
241
|
+
unless page.within_frame(frame_id, &block)
|
|
242
|
+
raise Capybara::ElementNotFound, "Unable to find frame with id '#{frame_id}'"
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Clear all cookie session data.
|
|
247
|
+
# @deprecated This method is deprecated in Capybara's master branch. Use
|
|
248
|
+
# {#reset!} instead.
|
|
249
|
+
def cleanup!
|
|
250
|
+
reset!
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Clear all cookie session data.
|
|
254
|
+
def reset!
|
|
255
|
+
cookies.clear
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Confirm or cancel the dialog, returning the text of the dialog
|
|
259
|
+
def confirm_dialog(confirm = true, &block)
|
|
260
|
+
browser.confirm_dialog(confirm, &block)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# @return [String] the page's current URL
|
|
264
|
+
def current_url
|
|
265
|
+
page.current_url
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Search for nodes which match the given XPath selector.
|
|
269
|
+
#
|
|
270
|
+
# @param [String] selector XPath query
|
|
271
|
+
# @return [Array<Node>] the matched nodes
|
|
272
|
+
def find(selector)
|
|
273
|
+
nodes = []
|
|
274
|
+
page.find(selector).each { |node| nodes << Node.new(self, node) }
|
|
275
|
+
nodes
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Execute JavaScript against the current page, discarding any return value.
|
|
279
|
+
#
|
|
280
|
+
# @param [String] script the JavaScript to be executed
|
|
281
|
+
# @return [nil]
|
|
282
|
+
def execute_script(script)
|
|
283
|
+
page.execute_script script
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Execute JavaScript against the current page and return the results.
|
|
287
|
+
#
|
|
288
|
+
# @param [String] script the JavaScript to be executed
|
|
289
|
+
# @return the result of the JavaScript
|
|
290
|
+
def evaluate_script(script)
|
|
291
|
+
page.evaluate_script script
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# @return the current page
|
|
295
|
+
def page
|
|
296
|
+
browser.page
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# @return the browser
|
|
300
|
+
def browser
|
|
301
|
+
@browser ||= Akephalos::Client.new(@options)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# @return the session cookies
|
|
305
|
+
def cookies
|
|
306
|
+
browser.cookies
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# @return [String] the current user agent string
|
|
310
|
+
def user_agent
|
|
311
|
+
browser.user_agent
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Set the User-Agent header for this session. If :default is given, the
|
|
315
|
+
# User-Agent header will be reset to the default browser's user agent.
|
|
316
|
+
#
|
|
317
|
+
# @param [:default] user_agent the default user agent
|
|
318
|
+
# @param [String] user_agent the user agent string to use
|
|
319
|
+
def user_agent=(user_agent)
|
|
320
|
+
browser.user_agent = user_agent
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Disable waiting in Capybara, since waiting is handled directly by
|
|
324
|
+
# Akephalos.
|
|
325
|
+
#
|
|
326
|
+
# @return [false]
|
|
327
|
+
def wait
|
|
328
|
+
false
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
private
|
|
332
|
+
|
|
333
|
+
# @param [String] path
|
|
334
|
+
# @return [String] the absolute URL for the given path
|
|
335
|
+
def url(path)
|
|
336
|
+
rack_server.url(path)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
Capybara.register_driver :akephalos do |app|
|
|
342
|
+
Capybara::Driver::Akephalos.new(app)
|
|
343
|
+
end
|