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,347 @@
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
+ #if it is already selected: do nothing
58
+ #if it isn't selected: click on it
59
+ native.click unless selected?
60
+ end
61
+
62
+ # Unselect an option from a select box.
63
+ #
64
+ # @api capybara
65
+ def unselect_option
66
+ unless select_node.multiple_select?
67
+ raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
68
+ end
69
+
70
+ native.unselect
71
+ end
72
+
73
+ # Click the element.
74
+ def click
75
+ native.click
76
+ end
77
+
78
+ # Drag the element on top of the target element.
79
+ #
80
+ # @api capybara
81
+ # @param [Node] element the target element
82
+ def drag_to(element)
83
+ trigger('mousedown')
84
+ element.trigger('mousemove')
85
+ element.trigger('mouseup')
86
+ end
87
+
88
+ # @api capybara
89
+ # @return [String] the element's tag name
90
+ def tag_name
91
+ native.tag_name
92
+ end
93
+
94
+ # @api capybara
95
+ # @return [true, false] the element's visiblity
96
+ def visible?
97
+ native.visible?
98
+ end
99
+
100
+ # @api capybara
101
+ # @return [true, false] the element's visiblity
102
+ def checked?
103
+ native.checked?
104
+ end
105
+
106
+ # @api capybara
107
+ # @return [true, false] the element's visiblity
108
+ def selected?
109
+ native.selected?
110
+ end
111
+
112
+ # @api capybara
113
+ # @return [String] the XPath to locate the node
114
+ def path
115
+ native.xpath
116
+ end
117
+
118
+ # Trigger an event on the element.
119
+ #
120
+ # @api capybara
121
+ # @param [String] event the event to trigger
122
+ def trigger(event)
123
+ native.fire_event(event.to_s)
124
+ end
125
+
126
+ # @api capybara
127
+ # @param [String] selector XPath query
128
+ # @return [Array<Node>] the matched nodes
129
+ def find(selector)
130
+ nodes = []
131
+ native.find(selector).each { |node| nodes << self.class.new(self, node) }
132
+ nodes
133
+ end
134
+
135
+ protected
136
+
137
+ # @return [true, false] whether the node allows multiple-option selection (if the node is a select).
138
+ def multiple_select?
139
+ tag_name == "select" && native.multiple_select?
140
+ end
141
+
142
+ private
143
+
144
+ # Return all child nodes which match the selector criteria.
145
+ #
146
+ # @api capybara
147
+ # @return [Array<Node>] the matched nodes
148
+ def all_unfiltered(selector)
149
+ nodes = []
150
+ native.find(selector).each { |node| nodes << self.class.new(driver, node) }
151
+ nodes
152
+ end
153
+
154
+ # @return [String] the node's type attribute
155
+ def type
156
+ native[:type]
157
+ end
158
+
159
+ # @return [Node] the select node, if this is an option node
160
+ def select_node
161
+ find('./ancestor::select').first
162
+ end
163
+ end
164
+
165
+ attr_reader :app, :rack_server, :options
166
+
167
+ # Creates a new instance of the Akephalos Driver for Capybara. The driver is
168
+ # registered with Capybara by a name, so that it can be chosen when
169
+ # Capybara's javascript_driver is changed. By default, Akephalos is
170
+ # registered like this:
171
+ #
172
+ # Capybara.register_driver :akephalos do |app|
173
+ # Capybara::Akephalos::Driver.new(
174
+ # app,
175
+ # :browser => :firefox_3_6,
176
+ # :validate_scripts => true
177
+ # )
178
+ # end
179
+ #
180
+ # @param app the Rack application to run
181
+ # @param [Hash] options the Akephalos configuration options
182
+ # @option options [Symbol] :browser (:firefox_3_6) the browser
183
+ # compatibility mode to run in. Available options:
184
+ # :firefox_3_6
185
+ # :firefox_3
186
+ # :ie6
187
+ # :ie7
188
+ # :ie8
189
+ #
190
+ # @option options [true, false] :validate_scripts (true) whether to raise
191
+ # exceptions on script errors
192
+ #
193
+ def initialize(app, options = {})
194
+ @app = app
195
+ @options = options
196
+ @rack_server = Capybara::Server.new(@app)
197
+ @rack_server.boot if Capybara.run_server
198
+ end
199
+
200
+ # Visit the given path in the browser.
201
+ #
202
+ # @param [String] path relative path to visit
203
+ def visit(path)
204
+ browser.visit(url(path))
205
+ end
206
+
207
+ # @return [String] the page's original source
208
+ def source
209
+ page.source
210
+ end
211
+
212
+ # @return [String] the page's modified source
213
+ # page.modified_source will return a string with
214
+ # html entities converted into the unicode equivalent
215
+ # but the string will be marked as ASCII-8BIT
216
+ # which causes conversion issues so we force the encoding
217
+ # to UTF-8 (ruby 1.9 only)
218
+ def body
219
+ body_source = page.modified_source
220
+
221
+ if body_source.respond_to?(:force_encoding)
222
+ body_source.force_encoding("UTF-8")
223
+ else
224
+ body_source
225
+ end
226
+ end
227
+
228
+ # @return [Hash{String => String}] the page's response headers
229
+ def response_headers
230
+ page.response_headers
231
+ end
232
+
233
+ # @return [Integer] the response's status code
234
+ def status_code
235
+ page.status_code
236
+ end
237
+
238
+ # Execute the given block within the context of a specified frame.
239
+ #
240
+ # @param [String] frame_id the frame's id or index
241
+ # @raise [Capybara::ElementNotFound] if the frame is not found
242
+ def within_frame(frame_id_or_index, &block)
243
+ result = page.within_frame(frame_id_or_index, &block)
244
+ unless page.within_frame(frame_id_or_index, &block)
245
+ raise Capybara::ElementNotFound, "Unable to find frame with id '#{frame_id_or_index}'"
246
+ end
247
+ end
248
+
249
+ # Clear all cookie session data.
250
+ # @deprecated This method is deprecated in Capybara's master branch. Use
251
+ # {#reset!} instead.
252
+ def cleanup!
253
+ reset!
254
+ end
255
+
256
+ # Reset session
257
+ def reset!
258
+ cookies.clear
259
+ browser.visit('about:blank')
260
+ end
261
+
262
+ # Confirm or cancel the dialog, returning the text of the dialog
263
+ def confirm_dialog(confirm = true, &block)
264
+ browser.confirm_dialog(confirm, &block)
265
+ end
266
+
267
+ # @return [String] the page's current URL
268
+ def current_url
269
+ page.current_url
270
+ end
271
+
272
+ # Search for nodes which match the given XPath selector.
273
+ #
274
+ # @param [String] selector XPath query
275
+ # @return [Array<Node>] the matched nodes
276
+ def find(selector)
277
+ nodes = []
278
+ page.find(selector).each { |node| nodes << Node.new(self, node) }
279
+ nodes
280
+ end
281
+
282
+ # Execute JavaScript against the current page, discarding any return value.
283
+ #
284
+ # @param [String] script the JavaScript to be executed
285
+ # @return [nil]
286
+ def execute_script(script)
287
+ page.execute_script script
288
+ end
289
+
290
+ # Execute JavaScript against the current page and return the results.
291
+ #
292
+ # @param [String] script the JavaScript to be executed
293
+ # @return the result of the JavaScript
294
+ def evaluate_script(script)
295
+ page.evaluate_script script
296
+ end
297
+
298
+ # @return the current page
299
+ def page
300
+ browser.page
301
+ end
302
+
303
+ # @return the browser
304
+ def browser
305
+ @browser ||= Akephalos::Client.new(@options)
306
+ end
307
+
308
+ # @return the session cookies
309
+ def cookies
310
+ browser.cookies
311
+ end
312
+
313
+ # @return [String] the current user agent string
314
+ def user_agent
315
+ browser.user_agent
316
+ end
317
+
318
+ # Set the User-Agent header for this session. If :default is given, the
319
+ # User-Agent header will be reset to the default browser's user agent.
320
+ #
321
+ # @param [:default] user_agent the default user agent
322
+ # @param [String] user_agent the user agent string to use
323
+ def user_agent=(user_agent)
324
+ browser.user_agent = user_agent
325
+ end
326
+
327
+ # Disable waiting in Capybara, since waiting is handled directly by
328
+ # Akephalos.
329
+ #
330
+ # @return [false]
331
+ def wait
332
+ false
333
+ end
334
+
335
+ private
336
+
337
+ # @param [String] path
338
+ # @return [String] the absolute URL for the given path
339
+ def url(path)
340
+ rack_server.url(path)
341
+ end
342
+
343
+ end
344
+
345
+ Capybara.register_driver :akephalos do |app|
346
+ Capybara::Driver::Akephalos.new(app)
347
+ end
@@ -0,0 +1,73 @@
1
+ module Akephalos
2
+ class Client
3
+ # Interface for working with HtmlUnit's CookieManager, providing a basic
4
+ # API for manipulating the cookies in a session.
5
+ class Cookies
6
+ include Enumerable
7
+
8
+ # @param [HtmlUnit::CookieManager] cookie manager
9
+ def initialize(cookie_manager)
10
+ @cookie_manager = cookie_manager
11
+ end
12
+
13
+ # @param [name] the cookie name
14
+ # @return [Cookie] the cookie with the given name
15
+ # @return [nil] when no cookie is found
16
+ def [](name)
17
+ cookie = @cookie_manager.getCookie(name)
18
+ Cookie.new(cookie) if cookie
19
+ end
20
+
21
+ # Clears all cookies for this session.
22
+ def clear
23
+ @cookie_manager.clearCookies
24
+ end
25
+
26
+ # Iterator for all cookies in the current session.
27
+ def each
28
+ @cookie_manager.getCookies.each do |cookie|
29
+ yield Cookie.new(cookie)
30
+ end
31
+ end
32
+
33
+ # Remove the cookie from the session.
34
+ #
35
+ # @param [Cookie] the cookie to remove
36
+ def delete(cookie)
37
+ @cookie_manager.removeCookie(cookie.native)
38
+ end
39
+
40
+ # @return [true, false] whether there are any cookies
41
+ def empty?
42
+ !any?
43
+ end
44
+
45
+ class Cookie
46
+
47
+ attr_reader :domain, :expires, :name, :path, :value
48
+
49
+ # @param [HtmlUnit::Cookie] the cookie
50
+ def initialize(cookie)
51
+ @_cookie = cookie
52
+ @domain = cookie.getDomain
53
+ @expires = cookie.getExpires
54
+ @name = cookie.getName
55
+ @path = cookie.getPath
56
+ @value = cookie.getValue
57
+ @secure = cookie.isSecure
58
+ end
59
+
60
+ def secure?
61
+ !!@secure
62
+ end
63
+
64
+ # @return [HtmlUnit::Cookie] the native cookie object
65
+ # @api private
66
+ def native
67
+ @_cookie
68
+ end
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,120 @@
1
+ module Akephalos
2
+ class Client
3
+
4
+ # Akephalos::Client::Filter extends HtmlUnit's WebConnectionWrapper to
5
+ # enable filtering outgoing requests generated interally by HtmlUnit.
6
+ #
7
+ # When a request comes through, it will be tested against the filters
8
+ # defined in Akephalos.filters and return a mock response if a match is
9
+ # found. If no filters are defined, or no filters match the request, then
10
+ # the response will bubble up to HtmlUnit for the normal request/response
11
+ # cycle.
12
+ class Filter < HtmlUnit::Util::WebConnectionWrapper
13
+ # Filters an outgoing request, and if a match is found, returns the mock
14
+ # response.
15
+ #
16
+ # @param [WebRequest] request the pending HTTP request
17
+ # @return [WebResponse] when the request matches a defined filter
18
+ # @return [nil] when no filters match the request
19
+ def filter(request)
20
+ if filter = find_filter(request)
21
+ start_time = Time.now
22
+ headers = filter[:headers].map do |name, value|
23
+ HtmlUnit::Util::NameValuePair.new(name.to_s, value.to_s)
24
+ end
25
+ response = HtmlUnit::WebResponseData.new(
26
+ filter[:body].to_s.to_java_bytes,
27
+ filter[:status],
28
+ HTTP_STATUS_CODES.fetch(filter[:status], "Unknown"),
29
+ headers
30
+ )
31
+ HtmlUnit::WebResponse.new(response, request, Time.now - start_time)
32
+ end
33
+ end
34
+
35
+ # Searches for a filter which matches the request's HTTP method and url.
36
+ #
37
+ # @param [WebRequest] request the pending HTTP request
38
+ # @return [Hash] when a filter matches the request
39
+ # @return [nil] when no filters match the request
40
+ def find_filter(request)
41
+ Akephalos.filters.find do |filter|
42
+ request.http_method === filter[:method] && request.url.to_s =~ filter[:filter]
43
+ end
44
+ end
45
+
46
+ # This method is called by WebClient when a page is requested, and will
47
+ # return a mock response if the request matches a defined filter or else
48
+ # return the actual response.
49
+ #
50
+ # @api htmlunit
51
+ # @param [WebRequest] request the pending HTTP request
52
+ # @return [WebResponse]
53
+ def getResponse(request)
54
+ filter(request) || super
55
+ end
56
+
57
+ # Map of status codes to their English descriptions.
58
+ HTTP_STATUS_CODES = {
59
+ 100 => "Continue",
60
+ 101 => "Switching Protocols",
61
+ 102 => "Processing",
62
+ 200 => "OK",
63
+ 201 => "Created",
64
+ 202 => "Accepted",
65
+ 203 => "Non-Authoritative Information",
66
+ 204 => "No Content",
67
+ 205 => "Reset Content",
68
+ 206 => "Partial Content",
69
+ 207 => "Multi-Status",
70
+ 300 => "Multiple Choices",
71
+ 301 => "Moved Permanently",
72
+ 302 => "Found",
73
+ 303 => "See Other",
74
+ 304 => "Not Modified",
75
+ 305 => "Use Proxy",
76
+ 306 => "Switch Proxy",
77
+ 307 => "Temporary Redirect",
78
+ 400 => "Bad Request",
79
+ 401 => "Unauthorized",
80
+ 402 => "Payment Required",
81
+ 403 => "Forbidden",
82
+ 404 => "Not Found",
83
+ 405 => "Method Not Allowed",
84
+ 406 => "Not Acceptable",
85
+ 407 => "Proxy Authentication Required",
86
+ 408 => "Request Timeout",
87
+ 409 => "Conflict",
88
+ 410 => "Gone",
89
+ 411 => "Length Required",
90
+ 412 => "Precondition Failed",
91
+ 413 => "Request Entity Too Large",
92
+ 414 => "Request-URI Too Long",
93
+ 415 => "Unsupported Media Type",
94
+ 416 => "Requested Range Not Satisfiable",
95
+ 417 => "Expectation Failed",
96
+ 418 => "I'm a teapot",
97
+ 421 => "There are too many connections from your internet address",
98
+ 422 => "Unprocessable Entity",
99
+ 423 => "Locked",
100
+ 424 => "Failed Dependency",
101
+ 425 => "Unordered Collection",
102
+ 426 => "Upgrade Required",
103
+ 449 => "Retry With",
104
+ 450 => "Blocked by Windows Parental Controls",
105
+ 500 => "Internal Server Error",
106
+ 501 => "Not Implemented",
107
+ 502 => "Bad Gateway",
108
+ 503 => "Service Unavailable",
109
+ 504 => "Gateway Timeout",
110
+ 505 => "HTTP Version Not Supported",
111
+ 506 => "Variant Also Negotiates",
112
+ 507 => "Insufficient Storage",
113
+ 509 => "Bandwidth Limit Exceeded",
114
+ 510 => "Not Extended",
115
+ 530 => "User access denied"
116
+ }.freeze
117
+ end
118
+
119
+ end
120
+ end