akephalos2 2.0.7-java

Sign up to get free protection for your applications and to get access to all the features.
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