akephalos2 2.0.7-java

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.
Files changed (38) hide show
  1. data/MIT_LICENSE +20 -0
  2. data/README.md +330 -0
  3. data/bin/akephalos +102 -0
  4. data/lib/akephalos/capybara.rb +347 -0
  5. data/lib/akephalos/client/cookies.rb +73 -0
  6. data/lib/akephalos/client/filter.rb +120 -0
  7. data/lib/akephalos/client.rb +192 -0
  8. data/lib/akephalos/configuration.rb +49 -0
  9. data/lib/akephalos/console.rb +32 -0
  10. data/lib/akephalos/cucumber.rb +6 -0
  11. data/lib/akephalos/htmlunit/ext/confirm_handler.rb +18 -0
  12. data/lib/akephalos/htmlunit/ext/http_method.rb +30 -0
  13. data/lib/akephalos/htmlunit.rb +31 -0
  14. data/lib/akephalos/node.rb +192 -0
  15. data/lib/akephalos/page.rb +118 -0
  16. data/lib/akephalos/remote_client.rb +93 -0
  17. data/lib/akephalos/server.rb +79 -0
  18. data/lib/akephalos/version.rb +3 -0
  19. data/lib/akephalos.rb +19 -0
  20. data/vendor/html-unit/apache-mime4j-0.6.jar +0 -0
  21. data/vendor/html-unit/commons-codec-1.4.jar +0 -0
  22. data/vendor/html-unit/commons-collections-3.2.1.jar +0 -0
  23. data/vendor/html-unit/commons-io-2.0.1.jar +0 -0
  24. data/vendor/html-unit/commons-lang3-3.0.1.jar +0 -0
  25. data/vendor/html-unit/commons-logging-1.1.1.jar +0 -0
  26. data/vendor/html-unit/cssparser-0.9.6-20110829.205617-3.jar +0 -0
  27. data/vendor/html-unit/htmlunit-2.10-SNAPSHOT.jar +0 -0
  28. data/vendor/html-unit/htmlunit-core-js-2.9.jar +0 -0
  29. data/vendor/html-unit/httpclient-4.1.2.jar +0 -0
  30. data/vendor/html-unit/httpcore-4.1.2.jar +0 -0
  31. data/vendor/html-unit/httpmime-4.1.2.jar +0 -0
  32. data/vendor/html-unit/nekohtml-1.9.15.jar +0 -0
  33. data/vendor/html-unit/sac-1.3.jar +0 -0
  34. data/vendor/html-unit/serializer-2.7.1.jar +0 -0
  35. data/vendor/html-unit/xalan-2.7.1.jar +0 -0
  36. data/vendor/html-unit/xercesImpl-2.9.1.jar +0 -0
  37. data/vendor/html-unit/xml-apis-1.3.04.jar +0 -0
  38. metadata +127 -0
@@ -0,0 +1,192 @@
1
+ require 'akephalos/configuration'
2
+
3
+ if RUBY_PLATFORM != "java"
4
+ require 'akephalos/remote_client'
5
+ Akephalos::Client = Akephalos::RemoteClient
6
+ else
7
+ require 'akephalos/htmlunit'
8
+ require 'akephalos/htmlunit/ext/http_method'
9
+ require 'akephalos/htmlunit/ext/confirm_handler'
10
+
11
+ require 'akephalos/page'
12
+ require 'akephalos/node'
13
+
14
+ require 'akephalos/client/cookies'
15
+ require 'akephalos/client/filter'
16
+
17
+ module Akephalos
18
+
19
+ # Akephalos::Client wraps HtmlUnit's WebClient class. It is the main entry
20
+ # point for all interaction with the browser, exposing its current page and
21
+ # allowing navigation.
22
+ class Client
23
+
24
+ # @return [Akephalos::Page] the current page
25
+ attr_reader :page
26
+
27
+ # @return [HtmlUnit::BrowserVersion] the configured browser version
28
+ attr_reader :browser_version
29
+
30
+ # @return [true/false] whether to raise errors on javascript failures
31
+ attr_reader :validate_scripts
32
+
33
+ # @return [true/false] whether to ignore insecure ssl certificates
34
+ attr_reader :use_insecure_ssl
35
+
36
+ # @return ["trace" / "debug" / "info" / "warn" / "error" or "fatal"] which points the htmlunit log level
37
+ attr_reader :htmlunit_log_level
38
+
39
+ # The default configuration options for a new Client.
40
+ DEFAULT_OPTIONS = {
41
+ :browser => :firefox_3_6,
42
+ :validate_scripts => true,
43
+ :use_insecure_ssl => false,
44
+ :htmlunit_log_level => 'fatal'
45
+ }
46
+
47
+ # Map of browser version symbols to their HtmlUnit::BrowserVersion
48
+ # instances.
49
+ BROWSER_VERSIONS = {
50
+ :ie6 => HtmlUnit::BrowserVersion::INTERNET_EXPLORER_6,
51
+ :ie7 => HtmlUnit::BrowserVersion::INTERNET_EXPLORER_7,
52
+ :ie8 => HtmlUnit::BrowserVersion::INTERNET_EXPLORER_8,
53
+ :firefox_3_6 => HtmlUnit::BrowserVersion::FIREFOX_3_6
54
+ }
55
+
56
+ # @param [Hash] options the configuration options for this client
57
+ #
58
+ # @option options [Symbol] :browser (:firefox_3_6) the browser version (
59
+ # see BROWSER_VERSIONS)
60
+ #
61
+ # @option options [true, false] :validate_scripts (true) whether to raise
62
+ # errors on javascript errors
63
+ def initialize(options = {})
64
+ process_options!(options)
65
+
66
+ @_client = java.util.concurrent.FutureTask.new do
67
+
68
+ if @http_proxy.nil? or @http_proxy_port.nil?
69
+ client = HtmlUnit::WebClient.new(browser_version)
70
+ else
71
+ client = HtmlUnit::WebClient.new(browser_version, @http_proxy, @http_proxy_port)
72
+ end
73
+
74
+ client.setThrowExceptionOnFailingStatusCode(false)
75
+ client.setAjaxController(HtmlUnit::NicelyResynchronizingAjaxController.new)
76
+ client.setCssErrorHandler(HtmlUnit::SilentCssErrorHandler.new)
77
+ client.setThrowExceptionOnScriptError(validate_scripts)
78
+ client.setUseInsecureSSL(use_insecure_ssl)
79
+ client.setRefreshHandler(HtmlUnit::WaitingRefreshHandler.new)
80
+
81
+ Filter.new(client)
82
+ client
83
+ end
84
+ Thread.new { @_client.run }
85
+ end
86
+
87
+ # Visit the requested URL and return the page.
88
+ #
89
+ # @param [String] url the URL to load
90
+ # @return [Page] the loaded page
91
+ def visit(url)
92
+ begin
93
+ client.getPage(url)
94
+ rescue Exception => e
95
+ raise e unless e.message == 'java.lang.NullPointerException: null'
96
+ end
97
+ page
98
+ end
99
+
100
+ # @return [Cookies] the cookies for this session
101
+ def cookies
102
+ @cookies ||= Cookies.new(client.getCookieManager)
103
+ end
104
+
105
+ # @return [String] the current user agent string
106
+ def user_agent
107
+ @user_agent || client.getBrowserVersion.getUserAgent
108
+ end
109
+
110
+ # Set the User-Agent header for this session. If :default is given, the
111
+ # User-Agent header will be reset to the default browser's user agent.
112
+ #
113
+ # @param [:default] user_agent the default user agent
114
+ # @param [String] user_agent the user agent string to use
115
+ def user_agent=(user_agent)
116
+ if user_agent == :default
117
+ @user_agent = nil
118
+ client.removeRequestHeader("User-Agent")
119
+ else
120
+ @user_agent = user_agent
121
+ client.addRequestHeader("User-Agent", user_agent)
122
+ end
123
+ end
124
+
125
+ # @return [Page] the current page
126
+ def page
127
+ self.page = client.getCurrentWindow.getTopWindow.getEnclosedPage
128
+ @page
129
+ end
130
+
131
+ # Update the current page.
132
+ #
133
+ # @param [HtmlUnit::HtmlPage] _page the new page
134
+ # @return [Page] the new page
135
+ def page=(_page)
136
+ if @page != _page
137
+ @page = Page.new(_page)
138
+ end
139
+ @page
140
+ end
141
+
142
+ # @return [true, false] whether javascript errors will raise exceptions
143
+ def validate_scripts?
144
+ !!validate_scripts
145
+ end
146
+
147
+ # @return [true, false] whether to ignore insecure ssl certificates
148
+ def use_insecure_ssl?
149
+ !!use_insecure_ssl
150
+ end
151
+
152
+ # Merges the DEFAULT_OPTIONS with those provided to initialize the Client
153
+ # state, namely, its browser version, whether it should
154
+ # validate scripts, and htmlunit log level.
155
+ #
156
+ # @param [Hash] options the options to process
157
+ def process_options!(options)
158
+ options = DEFAULT_OPTIONS.merge(options)
159
+
160
+ @browser_version = BROWSER_VERSIONS.fetch(options.delete(:browser))
161
+ @validate_scripts = options.delete(:validate_scripts)
162
+ @use_insecure_ssl = options.delete(:use_insecure_ssl)
163
+ @htmlunit_log_level = options.delete(:htmlunit_log_level)
164
+ @http_proxy = options.delete(:http_proxy)
165
+ @http_proxy_port = options.delete(:http_proxy_port)
166
+
167
+ java.lang.System.setProperty("org.apache.commons.logging.simplelog.defaultlog", @htmlunit_log_level)
168
+ end
169
+
170
+ # Confirm or cancel the dialog, returning the text of the dialog
171
+ def confirm_dialog(confirm = true, &block)
172
+ handler = HtmlUnit::ConfirmHandler.new
173
+ handler.handleConfirmValue = confirm
174
+ client.setConfirmHandler(handler)
175
+ yield if block_given?
176
+ return handler.text
177
+ end
178
+
179
+ private
180
+
181
+ # Call the future set up in #initialize and return the WebCLient
182
+ # instance.
183
+ #
184
+ # @return [HtmlUnit::WebClient] the WebClient instance
185
+ def client
186
+ @client ||= @_client.get.tap do |client|
187
+ client.getCurrentWindow.getHistory.ignoreNewPages_.set(true)
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,49 @@
1
+ module Akephalos
2
+
3
+ @configuration = {}
4
+
5
+ class << self
6
+ # @return [Hash] the configuration
7
+ attr_accessor :configuration
8
+ end
9
+
10
+ module Filters
11
+ # @return [Array] all defined filters
12
+ def filters
13
+ configuration[:filters] ||= []
14
+ end
15
+
16
+ # Defines a new filter to be tested by Akephalos::Filter when executing
17
+ # page requests. An HTTP method and a regex or string to match against the
18
+ # URL are required for defining a filter.
19
+ #
20
+ # You can additionally pass the following options to define how the
21
+ # filtered request should respond:
22
+ #
23
+ # :status (defaults to 200)
24
+ # :body (defaults to "")
25
+ # :headers (defaults to {})
26
+ #
27
+ # If we define a filter with no additional options, then, we will get an
28
+ # empty HTML response:
29
+ #
30
+ # Akephalos.filter :post, "http://example.com"
31
+ # Akephalos.filter :any, %r{http://.*\.com}
32
+ #
33
+ # If you instead, say, wanted to simulate a failure in an external system,
34
+ # you could do this:
35
+ #
36
+ # Akephalos.filter :post, "http://example.com",
37
+ # :status => 500, :body => "Something went wrong"
38
+ #
39
+ # @param [Symbol] method the HTTP method to match
40
+ # @param [RegExp, String] regex URL matcher
41
+ # @param [Hash] options response values
42
+ def filter(method, regex, options = {})
43
+ regex = Regexp.new(Regexp.escape(regex)) if regex.is_a?(String)
44
+ filters << {:method => method, :filter => regex, :status => 200, :body => "", :headers => {}}.merge!(options)
45
+ end
46
+ end
47
+
48
+ extend Filters
49
+ end
@@ -0,0 +1,32 @@
1
+ # Begin a new Capybara session, by default connecting to localhost on port
2
+ # 3000.
3
+ def session
4
+ Capybara.app_host ||= "http://localhost:3000"
5
+ @session ||= Capybara::Session.new(:akephalos)
6
+ end
7
+ alias page session
8
+
9
+ module Akephalos
10
+ # Simple class for starting an IRB session.
11
+ class Console
12
+
13
+ # Start an IRB session. Tries to load irb/completion, and also loads a
14
+ # .irbrc file if it exists.
15
+ def self.start
16
+ require 'irb'
17
+
18
+ begin
19
+ require 'irb/completion'
20
+ rescue Exception
21
+ # No readline available, proceed anyway.
22
+ end
23
+
24
+ if ::File.exists? ".irbrc"
25
+ ENV['IRBRC'] = ".irbrc"
26
+ end
27
+
28
+ IRB.start
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ require 'capybara/cucumber'
2
+
3
+ Before('@akephalos') do
4
+ Capybara.current_driver = :akephalos
5
+ end
6
+
@@ -0,0 +1,18 @@
1
+ # Reopen com.gargoylesoftware.htmlunit.ConfirmHandler to provide an interface to
2
+ # confirm a dialog and capture its message
3
+ module HtmlUnit
4
+ module ConfirmHandler
5
+
6
+ # Boolean - true for ok, false for cancel
7
+ attr_accessor :handleConfirmValue
8
+
9
+ # last confirmation's message
10
+ attr_reader :text
11
+
12
+ # handleConfirm will be called by htmlunit on a confirm, so store the message.
13
+ def handleConfirm(page, message)
14
+ @text = message
15
+ return handleConfirmValue.nil? ? true : handleConfirmValue
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ module HtmlUnit
2
+ # Reopen HtmlUnit's HttpMethod class to add convenience methods.
3
+ class HttpMethod
4
+
5
+ # Loosely compare HttpMethod with another object, accepting either an
6
+ # HttpMethod instance or a symbol describing the method. Note that :any is a
7
+ # special symbol which will always return true.
8
+ #
9
+ # @param [HttpMethod] other an HtmlUnit HttpMethod object
10
+ # @param [Symbol] other a symbolized representation of an http method
11
+ # @return [true/false]
12
+ def ===(other)
13
+ case other
14
+ when HttpMethod
15
+ super
16
+ when :any
17
+ true
18
+ when :get
19
+ self == self.class::GET
20
+ when :post
21
+ self == self.class::POST
22
+ when :put
23
+ self == self.class::PUT
24
+ when :delete
25
+ self == self.class::DELETE
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ require "pathname"
2
+ require "java"
3
+
4
+ Dir[File.dirname(__FILE__) + "/../.." + "/vendor/html-unit/*.jar"].each {|file| require file }
5
+
6
+ java.lang.System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog")
7
+ java.lang.System.setProperty("org.apache.commons.logging.simplelog.defaultlog", "fatal")
8
+ java.lang.System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true")
9
+
10
+ # Container module for com.gargoylesoftware.htmlunit namespace.
11
+ module HtmlUnit
12
+ java_import "com.gargoylesoftware.htmlunit.BrowserVersion"
13
+ java_import "com.gargoylesoftware.htmlunit.History"
14
+ java_import "com.gargoylesoftware.htmlunit.HttpMethod"
15
+ java_import 'com.gargoylesoftware.htmlunit.ConfirmHandler'
16
+ java_import "com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController"
17
+ java_import "com.gargoylesoftware.htmlunit.SilentCssErrorHandler"
18
+ java_import "com.gargoylesoftware.htmlunit.WebClient"
19
+ java_import "com.gargoylesoftware.htmlunit.WebResponseData"
20
+ java_import "com.gargoylesoftware.htmlunit.WebResponse"
21
+ java_import "com.gargoylesoftware.htmlunit.WaitingRefreshHandler"
22
+
23
+ # Container module for com.gargoylesoftware.htmlunit.util namespace.
24
+ module Util
25
+ java_import "com.gargoylesoftware.htmlunit.util.NameValuePair"
26
+ java_import "com.gargoylesoftware.htmlunit.util.WebConnectionWrapper"
27
+ end
28
+
29
+ # Disable history tracking
30
+ History.field_reader :ignoreNewPages_
31
+ end
@@ -0,0 +1,192 @@
1
+ module Akephalos
2
+
3
+ # Akephalos::Node wraps HtmlUnit's DOMNode class, providing a simple API for
4
+ # interacting with an element on the page.
5
+ class Node
6
+ # @param [HtmlUnit::DOMNode] node
7
+ def initialize(node)
8
+ @nodes = []
9
+ @_node = node
10
+ end
11
+
12
+ # @return [true, false] whether the element is checked
13
+ def checked?
14
+ if @_node.respond_to?(:isChecked)
15
+ @_node.isChecked
16
+ else
17
+ !! self[:checked]
18
+ end
19
+ end
20
+
21
+ # @return [String] inner text of the node
22
+ # Returns a textual representation of this element that represents what would
23
+ # be visible to the user if this page was shown in a web browser.
24
+ # For example, a single-selection select element would return the currently
25
+ # selected value as text.
26
+ # Note: This will cleanup/reduce whitespace
27
+ def text
28
+ @_node.asText
29
+ end
30
+
31
+ # Returns the raw text content of this node and its descendants...
32
+ def text_content
33
+ @_node.getTextContent
34
+ end
35
+
36
+ # Returns a string representation of the XML document from this element and
37
+ # all it's children (recursively). The charset used is the current page encoding.
38
+ def xml
39
+ @_node.asXml
40
+ end
41
+
42
+ # Return the value of the node's attribute.
43
+ #
44
+ # @param [String] name attribute on node
45
+ # @return [String] the value of the named attribute
46
+ # @return [nil] when the node does not have the named attribute
47
+ def [](name)
48
+ @_node.hasAttribute(name.to_s) ? @_node.getAttribute(name.to_s) : nil
49
+ end
50
+
51
+ # Return the value of a form element. If the element is a select box and
52
+ # has "multiple" declared as an attribute, then all selected options will
53
+ # be returned as an array.
54
+ #
55
+ # @return [String, Array<String>] the node's value
56
+ def value
57
+ case tag_name
58
+ when "select"
59
+ if self[:multiple]
60
+ selected_options.map { |option| option.value }
61
+ else
62
+ selected_option = @_node.selected_options.first
63
+ selected_option ? Node.new(selected_option).value : nil
64
+ end
65
+ when "option"
66
+ self[:value] || text
67
+ when "textarea"
68
+ @_node.getText
69
+ else
70
+ self[:value]
71
+ end
72
+ end
73
+
74
+ # Set the value of the form input.
75
+ #
76
+ # @param [String] value
77
+ def value=(value)
78
+ case tag_name
79
+ when "textarea"
80
+ @_node.setText("")
81
+ type(value)
82
+ when "input"
83
+ if file_input?
84
+ @_node.setValueAttribute(value)
85
+ else
86
+ @_node.setValueAttribute("")
87
+ type(value)
88
+ end
89
+ end
90
+ end
91
+
92
+ # Types each character into a text or input field.
93
+ #
94
+ # @param [String] value the string to type
95
+ def type(value)
96
+ value.each_char do |c|
97
+ @_node.type(c)
98
+ end
99
+ end
100
+
101
+ # @return [true, false] whether the node allows multiple-option selection (if the node is a select).
102
+ def multiple_select?
103
+ !self[:multiple].nil?
104
+ end
105
+
106
+ # @return [true, false] whether the node is a file input
107
+ def file_input?
108
+ tag_name == "input" && @_node.getAttribute("type") == "file"
109
+ end
110
+
111
+
112
+ # Unselect an option.
113
+ #
114
+ # @return [true, false] whether the unselection was successful
115
+ def unselect
116
+ @_node.setSelected(false)
117
+ end
118
+
119
+ # Return the option elements for a select box.
120
+ #
121
+ # @return [Array<Node>] the options
122
+ def options
123
+ @_node.getOptions.map { |node| Node.new(node) }
124
+ end
125
+
126
+ # Return the selected option elements for a select box.
127
+ #
128
+ # @return [Array<Node>] the selected options
129
+ def selected_options
130
+ @_node.getSelectedOptions.map { |node| Node.new(node) }
131
+ end
132
+
133
+ # Fire a JavaScript event on the current node. Note that you should not
134
+ # prefix event names with "on", so:
135
+ #
136
+ # link.fire_event('mousedown')
137
+ #
138
+ # @param [String] JavaScript event name
139
+ def fire_event(name)
140
+ @_node.fireEvent(name)
141
+ end
142
+
143
+ # @return [String] the node's tag name
144
+ def tag_name
145
+ @_node.getNodeName
146
+ end
147
+
148
+ # @return [true, false] whether the node is visible to the user accounting
149
+ # for CSS.
150
+ def visible?
151
+ @_node.isDisplayed
152
+ end
153
+
154
+ # @return [true, false] whether the node is selected to the user accounting
155
+ # for CSS.
156
+ def selected?
157
+ if @_node.respond_to?(:isSelected)
158
+ @_node.isSelected
159
+ else
160
+ !! self[:selected]
161
+ end
162
+ end
163
+
164
+ # Click the node and then wait for any triggered JavaScript callbacks to
165
+ # fire.
166
+ def click
167
+ begin
168
+ @_node.click
169
+ @_node.getPage.getEnclosingWindow.getJobManager.waitForJobs(1000)
170
+ @_node.getPage.getEnclosingWindow.getJobManager.waitForJobsStartingBefore(1000)
171
+ rescue Exception => e
172
+ raise e unless e.message == 'java.lang.NullPointerException: null'
173
+ end
174
+ end
175
+
176
+ # Search for child nodes which match the given XPath selector.
177
+ #
178
+ # @param [String] selector an XPath selector
179
+ # @return [Array<Node>] the matched nodes
180
+ def find(selector)
181
+ nodes = @_node.getByXPath(selector).map { |node| Node.new(node) }
182
+ @nodes << nodes
183
+ nodes
184
+ end
185
+
186
+ # @return [String] the XPath expression for this node
187
+ def xpath
188
+ @_node.getCanonicalXPath
189
+ end
190
+ end
191
+
192
+ end
@@ -0,0 +1,118 @@
1
+ module Akephalos
2
+
3
+ # Akephalos::Page wraps HtmlUnit's HtmlPage class, exposing an API for
4
+ # interacting with a page in the browser.
5
+ class Page
6
+ # @param [HtmlUnit::HtmlPage] page
7
+ def initialize(page)
8
+ @nodes = []
9
+ @_page = page
10
+ end
11
+
12
+ # Search for nodes which match the given XPath selector.
13
+ #
14
+ # @param [String] selector an XPath selector
15
+ # @return [Array<Node>] the matched nodes
16
+ def find(selector)
17
+ nodes = current_frame.getByXPath(selector).map { |node| Node.new(node) }
18
+ @nodes << nodes
19
+ nodes
20
+ end
21
+
22
+ # Return the page's source, including any JavaScript-triggered DOM changes.
23
+ #
24
+ # @return [String] the page's modified source
25
+ def modified_source
26
+ current_frame.asXml
27
+ end
28
+
29
+ # Return the page's source as returned by the web server.
30
+ #
31
+ # @return [String] the page's original source
32
+ def source
33
+ current_frame.getWebResponse.getContentAsString
34
+ end
35
+
36
+ # @return [Hash{String => String}] the page's response headers
37
+ def response_headers
38
+ headers = current_frame.getWebResponse.getResponseHeaders.map do |header|
39
+ [header.getName, header.getValue]
40
+ end
41
+ Hash[*headers.flatten]
42
+ end
43
+
44
+ # @return [Integer] the response's status code
45
+ def status_code
46
+ current_frame.getWebResponse.getStatusCode
47
+ end
48
+
49
+ # Execute the given block in the context of the frame specified.
50
+ #
51
+ # @param [String] frame_id the frame's id
52
+ # @return [true] if the frame is found
53
+ # @return [nil] if the frame is not found
54
+ def within_frame(frame_id)
55
+ return unless @current_frame = find_frame(frame_id)
56
+ yield
57
+ true
58
+ ensure
59
+ @current_frame = nil
60
+ end
61
+
62
+ # @return [String] the current page's URL.
63
+ def current_url
64
+ current_frame.getWebResponse.getWebRequest.getUrl.toString
65
+ end
66
+
67
+ # Execute JavaScript against the current page, discarding any return value.
68
+ #
69
+ # @param [String] script the JavaScript to be executed
70
+ # @return [nil]
71
+ def execute_script(script)
72
+ current_frame.executeJavaScript(script)
73
+ nil
74
+ end
75
+
76
+ # Execute JavaScript against the current page and return the results.
77
+ #
78
+ # @param [String] script the JavaScript to be executed
79
+ # @return the result of the JavaScript
80
+ def evaluate_script(script)
81
+ current_frame.executeJavaScript(script).getJavaScriptResult
82
+ end
83
+
84
+ # Compare this page with an HtmlUnit page.
85
+ #
86
+ # @param [HtmlUnit::HtmlPage] other an HtmlUnit page
87
+ # @return [true, false]
88
+ def ==(other)
89
+ @_page == other
90
+ end
91
+
92
+ private
93
+
94
+ # Return the current frame. Usually just @_page, except when inside of the
95
+ # within_frame block.
96
+ #
97
+ # @return [HtmlUnit::HtmlPage] the current frame
98
+ def current_frame
99
+ @current_frame || @_page
100
+ end
101
+
102
+ # @param [String/Integer] id the frame's id or index
103
+ # @return [HtmlUnit::HtmlPage] the specified frame
104
+ # @return [nil] if no frame is found
105
+ def find_frame(id_or_index)
106
+ if id_or_index.is_a? Fixnum
107
+ frame = @_page.getFrames.get(id_or_index) rescue nil
108
+ else
109
+ frame = @_page.getFrames.find do |frame|
110
+ frame.getFrameElement.getAttribute("id") == id_or_index
111
+ end
112
+ end
113
+ frame.getEnclosedPage if frame
114
+ end
115
+
116
+ end
117
+
118
+ end