caius-celerity 0.0.6.10

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 (59) hide show
  1. data/History.txt +75 -0
  2. data/License.txt +621 -0
  3. data/README.txt +73 -0
  4. data/Rakefile +12 -0
  5. data/lib/celerity/browser.rb +823 -0
  6. data/lib/celerity/clickable_element.rb +69 -0
  7. data/lib/celerity/collections.rb +156 -0
  8. data/lib/celerity/container.rb +788 -0
  9. data/lib/celerity/default_viewer.rb +10 -0
  10. data/lib/celerity/disabled_element.rb +40 -0
  11. data/lib/celerity/element.rb +313 -0
  12. data/lib/celerity/element_collection.rb +107 -0
  13. data/lib/celerity/element_locator.rb +170 -0
  14. data/lib/celerity/elements/button.rb +43 -0
  15. data/lib/celerity/elements/file_field.rb +25 -0
  16. data/lib/celerity/elements/form.rb +23 -0
  17. data/lib/celerity/elements/frame.rb +75 -0
  18. data/lib/celerity/elements/image.rb +76 -0
  19. data/lib/celerity/elements/label.rb +11 -0
  20. data/lib/celerity/elements/link.rb +30 -0
  21. data/lib/celerity/elements/meta.rb +6 -0
  22. data/lib/celerity/elements/non_control_elements.rb +106 -0
  23. data/lib/celerity/elements/option.rb +32 -0
  24. data/lib/celerity/elements/radio_check.rb +115 -0
  25. data/lib/celerity/elements/select_list.rb +121 -0
  26. data/lib/celerity/elements/table.rb +144 -0
  27. data/lib/celerity/elements/table_cell.rb +29 -0
  28. data/lib/celerity/elements/table_elements.rb +42 -0
  29. data/lib/celerity/elements/table_row.rb +48 -0
  30. data/lib/celerity/elements/text_field.rb +169 -0
  31. data/lib/celerity/exception.rb +77 -0
  32. data/lib/celerity/htmlunit/commons-codec-1.3.jar +0 -0
  33. data/lib/celerity/htmlunit/commons-collections-3.2.1.jar +0 -0
  34. data/lib/celerity/htmlunit/commons-httpclient-3.1.jar +0 -0
  35. data/lib/celerity/htmlunit/commons-io-1.4.jar +0 -0
  36. data/lib/celerity/htmlunit/commons-lang-2.4.jar +0 -0
  37. data/lib/celerity/htmlunit/commons-logging-1.1.1.jar +0 -0
  38. data/lib/celerity/htmlunit/cssparser-0.9.5.jar +0 -0
  39. data/lib/celerity/htmlunit/htmlunit-2.6-SNAPSHOT.jar +0 -0
  40. data/lib/celerity/htmlunit/htmlunit-core-js-2.5.jar +0 -0
  41. data/lib/celerity/htmlunit/nekohtml-1.9.13-20090507.082850-2.jar +0 -0
  42. data/lib/celerity/htmlunit/sac-1.3.jar +0 -0
  43. data/lib/celerity/htmlunit/serializer-2.7.1.jar +0 -0
  44. data/lib/celerity/htmlunit/xalan-2.7.1.jar +0 -0
  45. data/lib/celerity/htmlunit/xercesImpl-2.8.1.jar +0 -0
  46. data/lib/celerity/htmlunit/xml-apis-1.3.04.jar +0 -0
  47. data/lib/celerity/htmlunit.rb +61 -0
  48. data/lib/celerity/identifier.rb +11 -0
  49. data/lib/celerity/input_element.rb +25 -0
  50. data/lib/celerity/listener.rb +141 -0
  51. data/lib/celerity/resources/no_viewer.png +0 -0
  52. data/lib/celerity/short_inspect.rb +20 -0
  53. data/lib/celerity/util.rb +91 -0
  54. data/lib/celerity/version.rb +10 -0
  55. data/lib/celerity/watir_compatibility.rb +84 -0
  56. data/lib/celerity.rb +74 -0
  57. data/tasks/jar.rake +57 -0
  58. data/tasks/rdoc.rake +4 -0
  59. metadata +130 -0
@@ -0,0 +1,823 @@
1
+ module Celerity
2
+ class Browser
3
+ include Container
4
+
5
+ attr_accessor :page, :object, :charset
6
+ attr_reader :webclient, :viewer, :options
7
+
8
+ #
9
+ # Initialize a browser and go to the given URL
10
+ #
11
+ # @param [String] uri The URL to go to.
12
+ # @return [Celerity::Browser] instance.
13
+ #
14
+
15
+ def self.start(uri)
16
+ browser = new
17
+ browser.goto(uri)
18
+ browser
19
+ end
20
+
21
+ #
22
+ # Not implemented. Use ClickableElement#click_and_attach instead.
23
+ #
24
+
25
+ def self.attach(*args)
26
+ raise NotImplementedError, "use ClickableElement#click_and_attach instead"
27
+ end
28
+
29
+ #
30
+ # Creates a browser object.
31
+ #
32
+ # @see Celerity::Container for an introduction to the main API.
33
+ #
34
+ # @option opts :log_level [Symbol] (:warning) @see log_level=
35
+ # @option opts :browser [:firefox, :internet_explorer] (:internet_explorer) Set the BrowserVersion used by HtmlUnit. Defaults to Internet Explorer.
36
+ # @option opts :css [Boolean] (false) Enable CSS. Disabled by default.
37
+ # @option opts :secure_ssl [Boolean] (true) Disable secure SSL. Enabled by default.
38
+ # @option opts :resynchronize [Boolean] (false) Use HtmlUnit::NicelyResynchronizingAjaxController to resynchronize Ajax calls.
39
+ # @option opts :javascript_exceptions [Boolean] (false) Raise exceptions on script errors. Disabled by default.
40
+ # @option opts :status_code_exceptions [Boolean] (false) Raise exceptions on failing status codes (404 etc.). Disabled by default.
41
+ # @option opts :render [:html, :xml] (:html) What DOM representation to send to connected viewers.
42
+ # @option opts :charset [String] ("UTF-8") Specify the charset that webclient will use for requests, and those where texts are getting gibberished, like Browser#html.
43
+ # @option opts :proxy [String] (nil) Proxy server to use, in address:port format.
44
+ # @option opts :user_agent [String] Override the User-Agent set by the :browser option
45
+ #
46
+ # @return [Celerity::Browser] An instance of the browser.
47
+ #
48
+ # @api public
49
+ #
50
+
51
+ def initialize(opts = {})
52
+ unless opts.is_a?(Hash)
53
+ raise TypeError, "wrong argument type #{opts.class}, expected Hash"
54
+ end
55
+
56
+ unless (render_types = [:html, :xml, nil]).include?(opts[:render])
57
+ raise ArgumentError, "expected one of #{render_types.inspect} for key :render"
58
+ end
59
+
60
+ @options = opts.dup # for ClickableElement#click_and_attach
61
+
62
+ @render_type = opts.delete(:render) || :html
63
+ @charset = opts.delete(:charset) || "UTF-8"
64
+ self.log_level = opts.delete(:log_level) || :warning
65
+
66
+ @last_url, @page = nil
67
+ @error_checkers = []
68
+ @browser = self # for Container#browser
69
+
70
+ setup_webclient(opts)
71
+
72
+ raise ArgumentError, "unknown option #{opts.inspect}" unless opts.empty?
73
+ find_viewer
74
+ end
75
+
76
+ def inspect
77
+ short_inspect :exclude => %w[@webclient @browser @object @options]
78
+ end
79
+
80
+ #
81
+ # Goto the given URL
82
+ #
83
+ # @param [String] uri The url.
84
+ # @return [String] The url.
85
+ #
86
+
87
+ def goto(uri)
88
+ uri = "http://#{uri}" unless uri =~ %r{://}
89
+
90
+ request = HtmlUnit::WebRequestSettings.new(::Java::JavaNet::URL.new(uri))
91
+ request.setCharset(@charset)
92
+
93
+ rescue_status_code_exception do
94
+ self.page = @webclient.getPage(request)
95
+ end
96
+
97
+ url()
98
+ end
99
+
100
+ #
101
+ # Set the credentials used for basic HTTP authentication. (Celerity only)
102
+ #
103
+ # Example:
104
+ # browser.credentials = "username:password"
105
+ #
106
+ # @param [String] A string with username / password, separated by a colon
107
+ #
108
+
109
+ def credentials=(string)
110
+ user, pass = string.split(":")
111
+ dcp = HtmlUnit::DefaultCredentialsProvider.new
112
+ dcp.addCredentials(user, pass)
113
+ @webclient.setCredentialsProvider(dcp)
114
+ end
115
+
116
+ #
117
+ # Unsets the current page / closes all windows
118
+ #
119
+
120
+ def close
121
+ @page = nil
122
+ @webclient.closeAllWindows
123
+ end
124
+
125
+ #
126
+ # @return [String] the URL of the current page
127
+ #
128
+
129
+ def url
130
+ assert_exists
131
+ @page.getWebResponse.getRequestUrl.toString
132
+ end
133
+
134
+ #
135
+ # @return [String] the title of the current page
136
+ #
137
+
138
+ def title
139
+ @page ? @page.getTitleText : ''
140
+ end
141
+
142
+ #
143
+ # @return [String] the value of window.status
144
+ #
145
+
146
+ def status
147
+ execute_script "window.status" # avoid the listener overhead
148
+ end
149
+
150
+ #
151
+ # @return [String] the HTML content of the current page
152
+ #
153
+
154
+ def html
155
+ @page ? @page.getWebResponse.getContentAsString(@charset) : ''
156
+ end
157
+
158
+ #
159
+ # @return [String] the XML representation of the DOM
160
+ #
161
+
162
+ def xml
163
+ return '' unless @page
164
+ return @page.asXml if @page.respond_to?(:asXml)
165
+ return text # fallback to text (for exampel for "plain/text" pages)
166
+ end
167
+
168
+ #
169
+ # @return [String] a text representation of the current page
170
+ #
171
+
172
+ def text
173
+ return '' unless @page
174
+
175
+ if @page.respond_to?("getContent")
176
+ string = @page.getContent.strip
177
+ elsif @page.documentElement
178
+ string = @page.documentElement.asText.strip
179
+ else
180
+ string = ''
181
+ end
182
+
183
+ # Celerity::Util.normalize_text(string)
184
+ string
185
+ end
186
+
187
+ #
188
+ # @return [Hash] response headers as a hash
189
+ #
190
+
191
+ def response_headers
192
+ return {} unless @page
193
+
194
+ Hash[*@page.getWebResponse.getResponseHeaders.map { |obj| [obj.name, obj.value] }.flatten]
195
+ end
196
+
197
+ #
198
+ # @return [Fixnum] status code of the last request
199
+ #
200
+
201
+ def status_code
202
+ @page.getWebResponse.getStatusCode
203
+ end
204
+
205
+ #
206
+ # @return [String] content-type as in 'text/html'
207
+ #
208
+
209
+ def content_type
210
+ return '' unless @page
211
+
212
+ @page.getWebResponse.getContentType
213
+ end
214
+
215
+ #
216
+ # @return [IO, nil] page contents as an IO, returns nil if no page is loaded.
217
+ #
218
+
219
+ def io
220
+ return nil unless @page
221
+
222
+ @page.getWebResponse.getContentAsStream.to_io
223
+ end
224
+
225
+ #
226
+ # Check if the current page contains the given text.
227
+ #
228
+ # @param [String, Regexp] expected_text The text to look for.
229
+ # @return [Numeric, nil] The index of the matched text, or nil if it isn't found.
230
+ # @raise [TypeError]
231
+ #
232
+
233
+ def contains_text(expected_text)
234
+ return nil unless exist?
235
+ super
236
+ end
237
+
238
+ #
239
+ # Get the first element found matching the given XPath.
240
+ #
241
+ # @param [String] xpath
242
+ # @return [Celerity::Element] An element subclass (or Element if none is found)
243
+ #
244
+
245
+ def element_by_xpath(xpath)
246
+ assert_exists
247
+ obj = @page.getFirstByXPath(xpath)
248
+ element_from_dom_node(obj)
249
+ end
250
+
251
+ #
252
+ # Get all the elements matching the given XPath.
253
+ #
254
+ # @param [String] xpath
255
+ # @return [Array<Celerity::Element>] array of elements
256
+ #
257
+
258
+ def elements_by_xpath(xpath)
259
+ assert_exists
260
+ objects = @page.getByXPath(xpath)
261
+ # should use an ElementCollection here?
262
+ objects.map { |o| element_from_dom_node(o) }.compact
263
+ end
264
+
265
+ #
266
+ # @return [HtmlUnit::HtmlHtml] the underlying HtmlUnit document.
267
+ #
268
+
269
+ def document
270
+ @object
271
+ end
272
+
273
+ #
274
+ # Goto the last url - HtmlUnit doesn't have a 'back' functionality, so we only have 1 history item :)
275
+ # @return [String, nil] The url of the resulting page, or nil if none was stored.
276
+ #
277
+
278
+ def back
279
+ # TODO: this is naive, need capability from HtmlUnit
280
+ goto(@last_url) if @last_url
281
+ end
282
+
283
+ #
284
+ # Wait for javascript jobs to finish
285
+ #
286
+
287
+ def wait
288
+ assert_exists
289
+ @webclient.waitForBackgroundJavaScript(10000);
290
+ end
291
+
292
+ #
293
+ # Refresh the current page
294
+ #
295
+
296
+ def refresh
297
+ assert_exists
298
+ self.page = @page.refresh
299
+ end
300
+
301
+ #
302
+ # Clears all cookies. (Celerity only)
303
+ #
304
+
305
+ def clear_cookies
306
+ @webclient.getCookieManager.clearCookies
307
+ end
308
+
309
+ #
310
+ # Clears the cache of "compiled JavaScript files and parsed CSS snippets"
311
+ #
312
+
313
+ def clear_cache
314
+ @webclient.cache.clear
315
+ end
316
+
317
+ #
318
+ # Get the cookies for this session. (Celerity only)
319
+ #
320
+ # @return [Hash<domain, Hash<name, value>>]
321
+ #
322
+
323
+ def cookies
324
+ result = Hash.new { |hash, key| hash[key] = {} }
325
+
326
+ cookies = @webclient.getCookieManager.getCookies
327
+ cookies.each do |cookie|
328
+ result[cookie.getDomain][cookie.getName] = cookie.getValue
329
+ end
330
+
331
+ result
332
+ end
333
+
334
+ #
335
+ # Add a cookie with the given parameters (Celerity only)
336
+ #
337
+ # @param [String] domain
338
+ # @param [String] name
339
+ # @param [String] value
340
+ #
341
+ # @option opts :path [String] ("/") A path
342
+ # @option opts :max_age [Fixnum] (??) A max age
343
+ # @option opts :secure [Boolean] (false)
344
+ #
345
+
346
+ def add_cookie(domain, name, value, opts = {})
347
+ path = opts.delete(:path) || "/"
348
+ max_age = opts.delete(:max_age) || (Time.now + 60*60*24) # not sure if this is correct
349
+ secure = opts.delete(:secure) || false
350
+
351
+ raise "unknown option: #{opts.inspect}" unless opts.empty?
352
+
353
+ cookie = Cookie.new(domain, name, value, path, max_age, secure)
354
+ @webclient.getCookieManager.addCookie(cookie)
355
+ end
356
+
357
+ #
358
+ # Remove the cookie with the given domain and name (Celerity only)
359
+ #
360
+ # @param [String] domain
361
+ # @param [String] name
362
+ #
363
+
364
+ def remove_cookie(domain, name)
365
+ cm = @webclient.getCookieManager
366
+ cookie = cm.getCookies.find { |c| c.getDomain == domain && c.getName == name }
367
+
368
+ if cookie.nil?
369
+ raise "no cookie with domain #{domain.inspect} and name #{name.inspect}"
370
+ end
371
+
372
+ cm.removeCookie(cookie)
373
+ end
374
+
375
+ #
376
+ # Execute the given JavaScript on the current page.
377
+ # @return [Object] The resulting Object
378
+ #
379
+
380
+ def execute_script(source)
381
+ assert_exists
382
+ @page.executeJavaScript(source.to_s).getJavaScriptResult
383
+ end
384
+
385
+ # experimental - should be removed?
386
+ def send_keys(keys)
387
+ keys = keys.gsub(/\s*/, '').scan(/((?:\{[A-Z]+?\})|.)/u).flatten
388
+ keys.each do |key|
389
+ element = @page.getFocusedElement
390
+ case key
391
+ when "{TAB}"
392
+ @page.tabToNextElement
393
+ when /\w/
394
+ element.type(key)
395
+ else
396
+ raise NotImplementedError
397
+ end
398
+ end
399
+ end
400
+
401
+ #
402
+ # Wait until the given block evaluates to true (Celerity only)
403
+ #
404
+ # @param [Fixnum] timeout Number of seconds to wait before timing out (default: 30).
405
+ # @yieldparam [Celerity::Browser] browser The browser instance.
406
+ # @see Celerity::Browser#resynchronized
407
+ #
408
+
409
+ def wait_until(timeout = 30, &block)
410
+ Timeout.timeout(timeout) do
411
+ until yield(self)
412
+ refresh_page_from_window
413
+ sleep 0.1
414
+ end
415
+ end
416
+ end
417
+
418
+ #
419
+ # Wait while the given block evaluates to true (Celerity only)
420
+ #
421
+ # @param [Fixnum] timeout Number of seconds to wait before timing out (default: 30).
422
+ # @yieldparam [Celerity::Browser] browser The browser instance.
423
+ # @see Celerity::Browser#resynchronized
424
+ #
425
+
426
+ def wait_while(timeout = 30, &block)
427
+ Timeout.timeout(timeout) do
428
+ while yield(self)
429
+ refresh_page_from_window
430
+ sleep 0.1
431
+ end
432
+ end
433
+ end
434
+
435
+ #
436
+ # Allows you to temporarily switch to HtmlUnit's NicelyResynchronizingAjaxController
437
+ # to resynchronize ajax calls.
438
+ #
439
+ # @browser.resynchronized do |b|
440
+ # b.link(:id, 'trigger_ajax_call').click
441
+ # end
442
+ #
443
+ # @yieldparam [Celerity::Browser] browser The current browser object.
444
+ # @see Celerity::Browser#new for how to configure the browser to always use this.
445
+ #
446
+
447
+ def resynchronized(&block)
448
+ old_controller = @webclient.ajaxController
449
+ @webclient.setAjaxController(::HtmlUnit::NicelyResynchronizingAjaxController.new)
450
+ yield self
451
+ @webclient.setAjaxController(old_controller)
452
+ end
453
+
454
+ #
455
+ # Allows you to temporarliy switch to HtmlUnit's default AjaxController, so
456
+ # ajax calls are performed asynchronously. This is useful if you have created
457
+ # the Browser with :resynchronize => true, but want to switch it off temporarily.
458
+ #
459
+ # @yieldparam [Celerity::Browser] browser The current browser object.
460
+ # @see Celerity::Browser#new
461
+ #
462
+
463
+ def asynchronized(&block)
464
+ old_controller = @webclient.ajaxController
465
+ @webclient.setAjaxController(::HtmlUnit::AjaxController.new)
466
+ yield self
467
+ @webclient.setAjaxController(old_controller)
468
+ end
469
+
470
+ #
471
+ # Start or stop HtmlUnit's DebuggingWebConnection. (Celerity only)
472
+ # The output will go to /tmp/«name»
473
+ #
474
+ # @param [Boolean] bool start or stop
475
+ # @param [String] name required if bool is true
476
+ #
477
+
478
+ def debug_web_connection(bool, name = nil)
479
+ if bool
480
+ raise "no name given" unless name
481
+ @old_webconnection = @webclient.getWebConnection
482
+ dwc = HtmlUnit::Util::DebuggingWebConnection.new(@old_webconnection, name)
483
+ @webclient.setWebConnection(dwc)
484
+ $stderr.puts "debug-webconnection on"
485
+ else
486
+ @webclient.setWebConnection(@old_webconnection) if @old_webconnection
487
+ $stderr.puts "debug-webconnection off"
488
+ end
489
+ end
490
+
491
+ #
492
+ # Add a listener block for one of the available types. (Celerity only)
493
+ # Types map to HtmlUnit interfaces like this:
494
+ #
495
+ # :status => StatusHandler
496
+ # :alert => AlertHandler ( window.alert() )
497
+ # :web_window_event => WebWindowListener
498
+ # :html_parser => HTMLParserListener
499
+ # :incorrectness => IncorrectnessListener
500
+ # :confirm => ConfirmHandler ( window.confirm() )
501
+ # :prompt => PromptHandler ( window.prompt() )
502
+ #
503
+ # Examples:
504
+ #
505
+ # browser.add_listener(:status) { |page, message| ... }
506
+ # browser.add_listener(:alert) { |page, message| ... }
507
+ # browser.add_listener(:web_window_event) { |web_window_event| ... }
508
+ # browser.add_listener(:html_parser) { |message, url, line, column, key| ... }
509
+ # browser.add_listener(:incorrectness) { |message, origin| ... }
510
+ # browser.add_listener(:confirm) { |page, message| ...; true }
511
+ # browser.add_listener(:prompt) { |page, message| ... }
512
+ #
513
+ #
514
+ # @param [Symbol] type One of the above symbols.
515
+ # @param [Proc] block A block to be executed for events of this type.
516
+ #
517
+
518
+ def add_listener(type, &block)
519
+ listener.add_listener(type, &block)
520
+ end
521
+
522
+ #
523
+ # Removes a listener block for one the available types. (Celerity only)
524
+ # See add_listener for the available types.
525
+ #
526
+ # @param [Symbol] type One of the available symbols.
527
+ # @param [Proc] block The block to remove from being executed for events of this type.
528
+ #
529
+
530
+ def remove_listener(type, &block)
531
+ listener.remove_listener(type, block)
532
+ end
533
+
534
+ #
535
+ # Specify a boolean value to click either 'OK' or 'Cancel' in any confirm
536
+ # dialogs that might show up during the duration of the given block.
537
+ #
538
+ # (Celerity only)
539
+ #
540
+ # @param [Boolean] bool true to click 'OK', false to click 'cancel'
541
+ # @param [Proc] block A block that will trigger the confirm() call(s).
542
+ #
543
+
544
+ def confirm(bool, &block)
545
+ blk = lambda { bool }
546
+
547
+ listener.add_listener(:confirm, &blk)
548
+ yield
549
+ listener.remove_listener(:confirm, blk)
550
+ end
551
+
552
+ #
553
+ # Add a 'checker' proc that will be run on every page load
554
+ #
555
+ # @param [Proc] checker The proc to be run (can also be given as a block)
556
+ # @yieldparam [Celerity::Browser] browser The current browser object.
557
+ # @raise [ArgumentError] if no Proc or block was given.
558
+ #
559
+
560
+ def add_checker(checker = nil, &block)
561
+ if block_given?
562
+ @error_checkers << block
563
+ elsif Proc === checker
564
+ @error_checkers << checker
565
+ else
566
+ raise ArgumentError, "argument must be a Proc or block"
567
+ end
568
+ end
569
+
570
+ #
571
+ # Remove the given checker from the list of checkers
572
+ # @param [Proc] checker The Proc to disable.
573
+ #
574
+
575
+ def disable_checker(checker)
576
+ @error_checkers.delete(checker)
577
+ end
578
+
579
+ #
580
+ # :finest, :finer, :fine, :config, :info, :warning, :severe, or :off, :all
581
+ #
582
+ # @return [Symbol] the current log level
583
+ #
584
+
585
+ def log_level
586
+ Celerity::Util.logger_for('com.gargoylesoftware.htmlunit').level.to_s.downcase.to_sym
587
+ end
588
+
589
+ #
590
+ # Set Java log level (default is :warning, can be any of :all, :finest, :finer, :fine, :config, :info, :warning, :severe, :off)
591
+ #
592
+ # @param [Symbol] level The new log level.
593
+ #
594
+
595
+ def log_level=(level)
596
+ log_level = java.util.logging.Level.const_get(level.to_s.upcase)
597
+
598
+ [ 'com.gargoylesoftware.htmlunit',
599
+ 'com.gargoylesoftware.htmlunit.html',
600
+ 'com.gargoylesoftware.htmlunit.javascript',
601
+ 'org.apache.commons.httpclient'
602
+ ].each { |package| Celerity::Util.logger_for(package).level = log_level }
603
+
604
+ level
605
+ end
606
+
607
+ #
608
+ # Checks if we have a page currently loaded.
609
+ # @return [true, false]
610
+ #
611
+
612
+ def exist?
613
+ !!@page
614
+ end
615
+ alias_method :exists?, :exist?
616
+
617
+ #
618
+ # Turn on/off javascript exceptions
619
+ #
620
+ # @param [Bool]
621
+ #
622
+
623
+ def javascript_exceptions=(bool)
624
+ @webclient.throwExceptionOnScriptError = bool
625
+ end
626
+
627
+ def javascript_exceptions
628
+ @webclient.throwExceptionOnScriptError
629
+ end
630
+
631
+ #
632
+ # Turn on/off status code exceptions
633
+ #
634
+ # @param [Bool]
635
+ #
636
+
637
+ def status_code_exceptions=(bool)
638
+ @webclient.throwExceptionOnFailingStatusCode = bool
639
+ end
640
+
641
+ def status_code_exceptions
642
+ @webclient.throwExceptionOnFailingStatusCode
643
+ end
644
+
645
+ #
646
+ # Turn on/off CSS loading
647
+ #
648
+ # @param [Bool]
649
+ #
650
+
651
+ def css=(bool)
652
+ @webclient.cssEnabled = bool
653
+ end
654
+
655
+ def css
656
+ @webclient.cssEnabled
657
+ end
658
+
659
+ #
660
+ # Turn on/off secure SSL
661
+ #
662
+ # @param [Bool]
663
+ #
664
+
665
+ def secure_ssl=(bool)
666
+ @webclient.useInsecureSSL = !bool
667
+ end
668
+
669
+ def secure_ssl
670
+ !@webclient.useInsecureSSL
671
+ end
672
+
673
+ #
674
+ # Sets the current page object for the browser
675
+ #
676
+ # @param [HtmlUnit::HtmlPage] value The page to set.
677
+ # @api private
678
+ #
679
+
680
+ def page=(value)
681
+ @last_url = url() if exist?
682
+ @page = value
683
+
684
+ if @page.respond_to?("getDocumentElement")
685
+ @object = @page.getDocumentElement
686
+ elsif @page.is_a? HtmlUnit::UnexpectedPage
687
+ raise UnexpectedPageException, @page.getWebResponse.getContentType
688
+ end
689
+
690
+ render unless @viewer == DefaultViewer
691
+ run_error_checks
692
+
693
+ value
694
+ end
695
+
696
+ #
697
+ # Check that we have a @page object.
698
+ #
699
+ # @raise [Celerity::Exception::UnknownObjectException] if no page is loaded.
700
+ # @api private
701
+ #
702
+
703
+ def assert_exists
704
+ raise UnknownObjectException, "no page loaded" unless exist?
705
+ end
706
+
707
+ #
708
+ # Returns the element that currently has the focus (Celerity only)
709
+ #
710
+
711
+ def focused_element
712
+ element_from_dom_node(page.getFocusedElement())
713
+ end
714
+
715
+ private
716
+
717
+ #
718
+ # Runs the all the checker procs added by +add_checker+
719
+ #
720
+ # @see add_checker
721
+ # @api private
722
+ #
723
+
724
+ def run_error_checks
725
+ @error_checkers.each { |e| e[self] }
726
+ end
727
+
728
+ #
729
+ # Configure the webclient according to the options given to #new.
730
+ # @see initialize
731
+ #
732
+
733
+ def setup_webclient(opts)
734
+ browser = (opts.delete(:browser) || :firefox).to_sym
735
+
736
+ case browser
737
+ when :firefox, :ff
738
+ browser_version = ::HtmlUnit::BrowserVersion::FIREFOX_2
739
+ when :internet_explorer, :ie
740
+ browser_version = ::HtmlUnit::BrowserVersion::INTERNET_EXPLORER_7
741
+ else
742
+ raise ArgumentError, "unknown browser: #{browser.inspect}"
743
+ end
744
+
745
+ if ua = opts.delete(:user_agent)
746
+ browser_version.setUserAgent(ua)
747
+ end
748
+
749
+ if proxy = opts.delete(:proxy)
750
+ phost, pport = proxy.split(":")
751
+ @webclient = ::HtmlUnit::WebClient.new(browser_version, phost, pport.to_i)
752
+ else
753
+ @webclient = ::HtmlUnit::WebClient.new(browser_version)
754
+ end
755
+
756
+ self.javascript_exceptions = false unless opts.delete(:javascript_exceptions)
757
+ self.status_code_exceptions = false unless opts.delete(:status_code_exceptions)
758
+ self.css = false unless opts.delete(:css)
759
+ self.secure_ssl = opts.delete(:secure_ssl) == false
760
+ @webclient.setAjaxController(::HtmlUnit::NicelyResynchronizingAjaxController.new) if opts.delete(:resynchronize)
761
+ end
762
+
763
+ #
764
+ # This *should* be unneccessary, but sometimes the page we get from the
765
+ # window is different (ie. a different object) from our current @page
766
+ # (Used by #wait_while and #wait_until)
767
+ #
768
+
769
+ def refresh_page_from_window
770
+ new_page = @page.getEnclosingWindow.getEnclosedPage
771
+
772
+ if new_page && (new_page != @page)
773
+ self.page = new_page
774
+ else
775
+ Log.debug "unneccessary refresh"
776
+ end
777
+ end
778
+
779
+ #
780
+ # Render the current page on the viewer.
781
+ # @api private
782
+ #
783
+
784
+ def render
785
+ @viewer.render_html(self.send(@render_type), url)
786
+ rescue DRb::DRbConnError, Errno::ECONNREFUSED => e
787
+ @viewer = DefaultViewer
788
+ end
789
+
790
+ #
791
+ # Check if we have a viewer available on druby://127.0.0.1:6429
792
+ # @api private
793
+ #
794
+
795
+ def find_viewer
796
+ # needed to avoid DRb raising and rescuing lots exceptions
797
+ DRb.start_service unless DRb.primary_server
798
+
799
+ viewer = DRbObject.new_with_uri("druby://127.0.0.1:6429")
800
+ if viewer.respond_to?(:render_html)
801
+ @viewer = viewer
802
+ else
803
+ @viewer = DefaultViewer
804
+ end
805
+ rescue DRb::DRbConnError, Errno::ECONNREFUSED
806
+ @viewer = DefaultViewer
807
+ end
808
+
809
+ #
810
+ # Convert the given HtmlUnit object to a Celerity object
811
+ #
812
+
813
+ def element_from_dom_node(obj)
814
+ element_class = Celerity::Util.htmlunit2celerity(obj.class) || Element
815
+ element_class.new(self, :object, obj)
816
+ end
817
+
818
+ def listener
819
+ @listener ||= Celerity::Listener.new(@webclient)
820
+ end
821
+
822
+ end # Browser
823
+ end # Celerity