akephalos-nerian 0.2.4-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 (37) hide show
  1. data/MIT_LICENSE +20 -0
  2. data/README.md +56 -0
  3. data/bin/akephalos +88 -0
  4. data/lib/akephalos.rb +19 -0
  5. data/lib/akephalos/capybara.rb +316 -0
  6. data/lib/akephalos/client.rb +112 -0
  7. data/lib/akephalos/client/cookies.rb +73 -0
  8. data/lib/akephalos/client/filter.rb +120 -0
  9. data/lib/akephalos/configuration.rb +49 -0
  10. data/lib/akephalos/console.rb +32 -0
  11. data/lib/akephalos/cucumber.rb +6 -0
  12. data/lib/akephalos/htmlunit.rb +38 -0
  13. data/lib/akephalos/htmlunit/ext/http_method.rb +30 -0
  14. data/lib/akephalos/node.rb +172 -0
  15. data/lib/akephalos/page.rb +113 -0
  16. data/lib/akephalos/remote_client.rb +84 -0
  17. data/lib/akephalos/server.rb +56 -0
  18. data/lib/akephalos/version.rb +3 -0
  19. data/src/htmlunit/apache-mime4j-0.6.jar +0 -0
  20. data/src/htmlunit/commons-codec-1.4.jar +0 -0
  21. data/src/htmlunit/commons-collections-3.2.1.jar +0 -0
  22. data/src/htmlunit/commons-io-1.4.jar +0 -0
  23. data/src/htmlunit/commons-lang-2.4.jar +0 -0
  24. data/src/htmlunit/commons-logging-1.1.1.jar +0 -0
  25. data/src/htmlunit/cssparser-0.9.5.jar +0 -0
  26. data/src/htmlunit/htmlunit-2.8.jar +0 -0
  27. data/src/htmlunit/htmlunit-core-js-2.8.jar +0 -0
  28. data/src/htmlunit/httpclient-4.0.1.jar +0 -0
  29. data/src/htmlunit/httpcore-4.0.1.jar +0 -0
  30. data/src/htmlunit/httpmime-4.0.1.jar +0 -0
  31. data/src/htmlunit/nekohtml-1.9.14.jar +0 -0
  32. data/src/htmlunit/sac-1.3.jar +0 -0
  33. data/src/htmlunit/serializer-2.7.1.jar +0 -0
  34. data/src/htmlunit/xalan-2.7.1.jar +0 -0
  35. data/src/htmlunit/xercesImpl-2.9.1.jar +0 -0
  36. data/src/htmlunit/xml-apis-1.3.04.jar +0 -0
  37. metadata +150 -0
@@ -0,0 +1,172 @@
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
+ def text
23
+ @_node.asText
24
+ end
25
+
26
+ # Return the value of the node's attribute.
27
+ #
28
+ # @param [String] name attribute on node
29
+ # @return [String] the value of the named attribute
30
+ # @return [nil] when the node does not have the named attribute
31
+ def [](name)
32
+ @_node.hasAttribute(name.to_s) ? @_node.getAttribute(name.to_s) : nil
33
+ end
34
+
35
+ # Return the value of a form element. If the element is a select box and
36
+ # has "multiple" declared as an attribute, then all selected options will
37
+ # be returned as an array.
38
+ #
39
+ # @return [String, Array<String>] the node's value
40
+ def value
41
+ case tag_name
42
+ when "select"
43
+ if self[:multiple]
44
+ selected_options.map { |option| option.value }
45
+ else
46
+ selected_option = @_node.selected_options.first
47
+ selected_option ? Node.new(selected_option).value : nil
48
+ end
49
+ when "option"
50
+ self[:value] || text
51
+ when "textarea"
52
+ @_node.getText
53
+ else
54
+ self[:value]
55
+ end
56
+ end
57
+
58
+ # Set the value of the form input.
59
+ #
60
+ # @param [String] value
61
+ def value=(value)
62
+ case tag_name
63
+ when "textarea"
64
+ @_node.setText("")
65
+ type(value)
66
+ when "input"
67
+ if file_input?
68
+ @_node.setValueAttribute(value)
69
+ else
70
+ @_node.setValueAttribute("")
71
+ type(value)
72
+ end
73
+ end
74
+ end
75
+
76
+ # Types each character into a text or input field.
77
+ #
78
+ # @param [String] value the string to type
79
+ def type(value)
80
+ value.each_char do |c|
81
+ @_node.type(c)
82
+ end
83
+ end
84
+
85
+ # @return [true, false] whether the node allows multiple-option selection (if the node is a select).
86
+ def multiple_select?
87
+ !self[:multiple].nil?
88
+ end
89
+
90
+ # @return [true, false] whether the node is a file input
91
+ def file_input?
92
+ tag_name == "input" && @_node.getAttribute("type") == "file"
93
+ end
94
+
95
+
96
+ # Unselect an option.
97
+ #
98
+ # @return [true, false] whether the unselection was successful
99
+ def unselect
100
+ @_node.setSelected(false)
101
+ end
102
+
103
+ # Return the option elements for a select box.
104
+ #
105
+ # @return [Array<Node>] the options
106
+ def options
107
+ @_node.getOptions.map { |node| Node.new(node) }
108
+ end
109
+
110
+ # Return the selected option elements for a select box.
111
+ #
112
+ # @return [Array<Node>] the selected options
113
+ def selected_options
114
+ @_node.getSelectedOptions.map { |node| Node.new(node) }
115
+ end
116
+
117
+ # Fire a JavaScript event on the current node. Note that you should not
118
+ # prefix event names with "on", so:
119
+ #
120
+ # link.fire_event('mousedown')
121
+ #
122
+ # @param [String] JavaScript event name
123
+ def fire_event(name)
124
+ @_node.fireEvent(name)
125
+ end
126
+
127
+ # @return [String] the node's tag name
128
+ def tag_name
129
+ @_node.getNodeName
130
+ end
131
+
132
+ # @return [true, false] whether the node is visible to the user accounting
133
+ # for CSS.
134
+ def visible?
135
+ @_node.isDisplayed
136
+ end
137
+
138
+ # @return [true, false] whether the node is selected to the user accounting
139
+ # for CSS.
140
+ def selected?
141
+ if @_node.respond_to?(:isSelected)
142
+ @_node.isSelected
143
+ else
144
+ !! self[:selected]
145
+ end
146
+ end
147
+
148
+ # Click the node and then wait for any triggered JavaScript callbacks to
149
+ # fire.
150
+ def click
151
+ @_node.click
152
+ @_node.getPage.getEnclosingWindow.getJobManager.waitForJobs(1000)
153
+ @_node.getPage.getEnclosingWindow.getJobManager.waitForJobsStartingBefore(1000)
154
+ end
155
+
156
+ # Search for child nodes which match the given XPath selector.
157
+ #
158
+ # @param [String] selector an XPath selector
159
+ # @return [Array<Node>] the matched nodes
160
+ def find(selector)
161
+ nodes = @_node.getByXPath(selector).map { |node| Node.new(node) }
162
+ @nodes << nodes
163
+ nodes
164
+ end
165
+
166
+ # @return [String] the XPath expression for this node
167
+ def xpath
168
+ @_node.getCanonicalXPath
169
+ end
170
+ end
171
+
172
+ end
@@ -0,0 +1,113 @@
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.getRequestSettings.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] id the frame's id
103
+ # @return [HtmlUnit::HtmlPage] the specified frame
104
+ # @return [nil] if no frame is found
105
+ def find_frame(id)
106
+ frame = @_page.getFrames.find do |frame|
107
+ frame.getFrameElement.getAttribute("id") == id
108
+ end
109
+ frame.getEnclosedPage if frame
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,84 @@
1
+ require 'socket'
2
+ require 'drb/drb'
3
+
4
+ # We need to define our own NativeException class for the cases when a native
5
+ # exception is raised by the JRuby DRb server.
6
+ class NativeException < StandardError; end
7
+
8
+ module Akephalos
9
+
10
+ # The +RemoteClient+ class provides an interface to an +Akephalos::Client+
11
+ # isntance on a remote DRb server.
12
+ #
13
+ # == Usage
14
+ # client = Akephalos::RemoteClient.new
15
+ # client.visit "http://www.oinopa.com"
16
+ # client.page.source # => "<!DOCTYPE html PUBLIC..."
17
+ class RemoteClient
18
+ # Start a remote akephalos server and return the remote Akephalos::Client
19
+ # instance.
20
+ #
21
+ # @return [DRbObject] the remote client instance
22
+ def self.new
23
+ server_port = start!
24
+
25
+ DRb.start_service("druby://127.0.0.1:#{find_available_port}")
26
+ client = DRbObject.new_with_uri("druby://127.0.0.1:#{server_port}")
27
+
28
+ # We want to share our local configuration with the remote server
29
+ # process, so we share an undumped version of our configuration. This
30
+ # lets us continue to make changes locally and have them reflected in the
31
+ # remote process.
32
+ client.configuration = Akephalos.configuration.extend(DRbUndumped)
33
+
34
+ client
35
+ end
36
+
37
+ # Start a remote server process and return when it is available for use.
38
+ def self.start!
39
+ port = find_available_port
40
+
41
+ remote_client = IO.popen("#{Akephalos::BIN_DIR + 'akephalos'} #{port}")
42
+
43
+ # Set up a monitor thread to detect if the forked server exits
44
+ # prematurely.
45
+ server_monitor = Thread.new { Thread.current[:exited] = Process.wait(remote_client.pid) }
46
+
47
+ # Wait for the server to be accessible on the socket we specified.
48
+ until responsive?(port)
49
+ exit!(1) if server_monitor[:exited]
50
+ sleep 0.5
51
+ end
52
+ server_monitor.kill
53
+
54
+ # Ensure that the remote server shuts down gracefully when we are
55
+ # finished.
56
+ at_exit { Process.kill(:INT, remote_client.pid) }
57
+
58
+ port
59
+ end
60
+
61
+ private
62
+
63
+ # @api private
64
+ # @param [Integer] port the port to check for responsiveness
65
+ # @return [true, false] whether the port is responsive
66
+ def self.responsive?(port)
67
+ socket = TCPSocket.open('127.0.0.1', port)
68
+ true
69
+ rescue Errno::ECONNREFUSED
70
+ false
71
+ ensure
72
+ socket.close if socket
73
+ end
74
+
75
+ # @api private
76
+ # @return [Integer] the next available port
77
+ def self.find_available_port
78
+ server = TCPServer.new('127.0.0.1', 0)
79
+ server.addr[1]
80
+ ensure
81
+ server.close if server
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,56 @@
1
+ require "pathname"
2
+ require "drb/drb"
3
+ require "akephalos/client"
4
+
5
+ # In ruby-1.8.7 and later, the message for a NameError exception is lazily
6
+ # evaluated. There are, however, different implementations of this between ruby
7
+ # and jruby, so we realize these messages when sending over DRb.
8
+ class NameError::Message
9
+ # @note This method is called by DRb before sending the error to the remote
10
+ # connection.
11
+ # @return [String] the inner message.
12
+ def _dump
13
+ to_s
14
+ end
15
+ end
16
+
17
+ [
18
+ Akephalos::Page,
19
+ Akephalos::Node,
20
+ Akephalos::Client::Cookies,
21
+ Akephalos::Client::Cookies::Cookie
22
+ ].each { |klass| klass.send(:include, DRbUndumped) }
23
+
24
+ module Akephalos
25
+
26
+ # Akephalos::Server is used by `akephalos --server` to start a DRb server
27
+ # serving an instance of Akephalos::Client.
28
+ class Server
29
+ # Start DRb service for an Akephalos::Client.
30
+ #
31
+ # @param [String] port attach server to
32
+ def self.start!(port)
33
+ abort_on_parent_exit!
34
+ client = Client.new
35
+ DRb.start_service("druby://127.0.0.1:#{port}", client)
36
+ DRb.thread.join
37
+ end
38
+
39
+ private
40
+
41
+ # Exit if STDIN is no longer readable, which corresponds to the process
42
+ # which started the server exiting prematurely.
43
+ #
44
+ # @api private
45
+ def self.abort_on_parent_exit!
46
+ Thread.new do
47
+ begin
48
+ STDIN.read
49
+ rescue IOError
50
+ exit
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,3 @@
1
+ module Akephalos #:nodoc
2
+ VERSION = "0.2.4"
3
+ end
Binary file
Binary file
Binary file
Binary file