celerity 0.0.6 → 0.0.7

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 (75) hide show
  1. data/History.txt +36 -0
  2. data/Manifest.txt +82 -0
  3. data/README.rdoc +78 -0
  4. data/Rakefile +25 -10
  5. data/celerity.gemspec +40 -0
  6. data/lib/celerity.rb +36 -20
  7. data/lib/celerity/browser.rb +396 -189
  8. data/lib/celerity/clickable_element.rb +25 -5
  9. data/lib/celerity/collections.rb +2 -2
  10. data/lib/celerity/container.rb +74 -61
  11. data/lib/celerity/default_viewer.rb +8 -4
  12. data/lib/celerity/disabled_element.rb +5 -5
  13. data/lib/celerity/element.rb +57 -35
  14. data/lib/celerity/element_collection.rb +22 -21
  15. data/lib/celerity/element_locator.rb +25 -18
  16. data/lib/celerity/elements/button.rb +13 -11
  17. data/lib/celerity/elements/file_field.rb +8 -4
  18. data/lib/celerity/elements/form.rb +7 -5
  19. data/lib/celerity/elements/frame.rb +6 -4
  20. data/lib/celerity/elements/image.rb +4 -4
  21. data/lib/celerity/elements/label.rb +1 -1
  22. data/lib/celerity/elements/link.rb +5 -5
  23. data/lib/celerity/elements/meta.rb +2 -1
  24. data/lib/celerity/elements/non_control_elements.rb +3 -3
  25. data/lib/celerity/elements/option.rb +7 -7
  26. data/lib/celerity/elements/radio_check.rb +18 -18
  27. data/lib/celerity/elements/select_list.rb +55 -25
  28. data/lib/celerity/elements/table.rb +21 -18
  29. data/lib/celerity/elements/table_cell.rb +1 -1
  30. data/lib/celerity/elements/table_elements.rb +1 -1
  31. data/lib/celerity/elements/table_row.rb +5 -5
  32. data/lib/celerity/elements/text_field.rb +33 -28
  33. data/lib/celerity/exception.rb +11 -5
  34. data/lib/celerity/htmlunit.rb +24 -8
  35. data/lib/celerity/htmlunit/commons-codec-1.4.jar +0 -0
  36. data/lib/celerity/htmlunit/htmlunit-2.6.jar +0 -0
  37. data/lib/celerity/htmlunit/htmlunit-core-js-2.6.jar +0 -0
  38. data/lib/celerity/htmlunit/nekohtml-1.9.13.jar +0 -0
  39. data/lib/celerity/htmlunit/{xercesImpl-2.8.1.jar → xercesImpl-2.9.1.jar} +0 -0
  40. data/lib/celerity/ignoring_web_connection.rb +15 -0
  41. data/lib/celerity/input_element.rb +1 -1
  42. data/lib/celerity/listener.rb +23 -17
  43. data/lib/celerity/short_inspect.rb +20 -0
  44. data/lib/celerity/util.rb +5 -2
  45. data/lib/celerity/version.rb +3 -10
  46. data/lib/celerity/viewer_connection.rb +89 -0
  47. data/lib/celerity/watir_compatibility.rb +2 -5
  48. data/lib/celerity/xpath_support.rb +48 -0
  49. data/spec/browser_authentication_spec.rb +16 -0
  50. data/spec/browser_spec.rb +300 -0
  51. data/spec/clickable_element_spec.rb +39 -0
  52. data/spec/default_viewer_spec.rb +23 -0
  53. data/spec/element_spec.rb +51 -0
  54. data/spec/filefield_spec.rb +18 -0
  55. data/spec/htmlunit_spec.rb +56 -0
  56. data/spec/index_offset_spec.rb +24 -0
  57. data/spec/listener_spec.rb +142 -0
  58. data/spec/spec_helper.rb +8 -0
  59. data/tasks/benchmark.rake +4 -0
  60. data/tasks/deployment.rake +43 -0
  61. data/tasks/environment.rake +7 -0
  62. data/tasks/fix.rake +25 -0
  63. data/tasks/jar.rake +4 -6
  64. data/tasks/rspec.rake +43 -0
  65. data/tasks/simple_ci.rake +94 -0
  66. data/tasks/snapshot.rake +22 -0
  67. data/tasks/website.rake +17 -0
  68. data/tasks/yard.rake +9 -0
  69. metadata +59 -26
  70. data/README.txt +0 -69
  71. data/lib/celerity/extra/method_generator.rb +0 -170
  72. data/lib/celerity/htmlunit/commons-codec-1.3.jar +0 -0
  73. data/lib/celerity/htmlunit/htmlunit-2.5-SNAPSHOT.jar +0 -0
  74. data/lib/celerity/htmlunit/htmlunit-core-js-2.5-SNAPSHOT.jar +0 -0
  75. data/lib/celerity/htmlunit/nekohtml-1.9.12-20090308.130127-11.jar +0 -0
data/History.txt CHANGED
@@ -1,3 +1,39 @@
1
+ == 0.0.7 2009-09-04
2
+ * :firefox (Firefox 2) is now the default browser, :firefox3 support added.
3
+ * Avoid huge Java backtraces on FailingHttpStatusCodeException
4
+ * Browser#log_level= sets the log level for more HtmlUnit packages
5
+ * Default log level is now :off
6
+ * ClickableElement#click_and_attach inherits options from parent browser
7
+ * Allow searching by XPath in frames.
8
+ * Fix bug with scripts in body onload.
9
+ * Nicer API for Browser#debug_web_connection
10
+ * Fix bug in Browser#element_by_xpath(s) and Element#method_missing
11
+ * Fix bug when selecting empty SelectList options
12
+ * Fix issue when using multiple attributes to locate elements on a page with non-unique IDs.
13
+ * Nicer #inspect methods on some objects
14
+ * Improved IPC with viewers
15
+ * Methods added:
16
+ - Browser#clear_cache
17
+ - Browser#confirm
18
+ - Browser#css=
19
+ - Browser#ignore_pattern=
20
+ - Browser#javascript_excepetion=
21
+ - Browser#secure_ssl=
22
+ - Browser#status
23
+ - Browser#status_code
24
+ - Browser#status_code_exceptions=
25
+ - Celerity.index_offset=
26
+ - ClickableElement#download
27
+ - Element#fire_event
28
+ - Element#javascript_object
29
+ * New constructor options:
30
+ - :javascript_enabled => true, false
31
+ - :viewer => true, false, String
32
+ - :refresh_handler => :immediate, :waiting, :threaded
33
+ * Features removed:
34
+ - Celerity::MethodGenerator
35
+ * Most of the spec suite moved to the WatirSpec project
36
+
1
37
  == 0.0.6 2009-03-19
2
38
  * Support for meta, strong, dl, dt, dd, and em HTML elements.
3
39
  * Update to HtmlUnit 2.5-SNAPSHOT.
data/Manifest.txt ADDED
@@ -0,0 +1,82 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ celerity.gemspec
7
+ lib/celerity.rb
8
+ lib/celerity/browser.rb
9
+ lib/celerity/clickable_element.rb
10
+ lib/celerity/collections.rb
11
+ lib/celerity/container.rb
12
+ lib/celerity/default_viewer.rb
13
+ lib/celerity/disabled_element.rb
14
+ lib/celerity/element.rb
15
+ lib/celerity/element_collection.rb
16
+ lib/celerity/element_locator.rb
17
+ lib/celerity/elements/button.rb
18
+ lib/celerity/elements/file_field.rb
19
+ lib/celerity/elements/form.rb
20
+ lib/celerity/elements/frame.rb
21
+ lib/celerity/elements/image.rb
22
+ lib/celerity/elements/label.rb
23
+ lib/celerity/elements/link.rb
24
+ lib/celerity/elements/meta.rb
25
+ lib/celerity/elements/non_control_elements.rb
26
+ lib/celerity/elements/option.rb
27
+ lib/celerity/elements/radio_check.rb
28
+ lib/celerity/elements/select_list.rb
29
+ lib/celerity/elements/table.rb
30
+ lib/celerity/elements/table_cell.rb
31
+ lib/celerity/elements/table_elements.rb
32
+ lib/celerity/elements/table_row.rb
33
+ lib/celerity/elements/text_field.rb
34
+ lib/celerity/exception.rb
35
+ lib/celerity/htmlunit.rb
36
+ lib/celerity/htmlunit/commons-codec-1.4.jar
37
+ lib/celerity/htmlunit/commons-collections-3.2.1.jar
38
+ lib/celerity/htmlunit/commons-httpclient-3.1.jar
39
+ lib/celerity/htmlunit/commons-io-1.4.jar
40
+ lib/celerity/htmlunit/commons-lang-2.4.jar
41
+ lib/celerity/htmlunit/commons-logging-1.1.1.jar
42
+ lib/celerity/htmlunit/cssparser-0.9.5.jar
43
+ lib/celerity/htmlunit/htmlunit-2.6.jar
44
+ lib/celerity/htmlunit/htmlunit-core-js-2.6.jar
45
+ lib/celerity/htmlunit/nekohtml-1.9.13.jar
46
+ lib/celerity/htmlunit/sac-1.3.jar
47
+ lib/celerity/htmlunit/serializer-2.7.1.jar
48
+ lib/celerity/htmlunit/xalan-2.7.1.jar
49
+ lib/celerity/htmlunit/xercesImpl-2.9.1.jar
50
+ lib/celerity/htmlunit/xml-apis-1.3.04.jar
51
+ lib/celerity/identifier.rb
52
+ lib/celerity/ignoring_web_connection.rb
53
+ lib/celerity/input_element.rb
54
+ lib/celerity/listener.rb
55
+ lib/celerity/resources/no_viewer.png
56
+ lib/celerity/short_inspect.rb
57
+ lib/celerity/util.rb
58
+ lib/celerity/version.rb
59
+ lib/celerity/viewer_connection.rb
60
+ lib/celerity/watir_compatibility.rb
61
+ lib/celerity/xpath_support.rb
62
+ spec/browser_authentication_spec.rb
63
+ spec/browser_spec.rb
64
+ spec/clickable_element_spec.rb
65
+ spec/default_viewer_spec.rb
66
+ spec/element_spec.rb
67
+ spec/filefield_spec.rb
68
+ spec/htmlunit_spec.rb
69
+ spec/index_offset_spec.rb
70
+ spec/listener_spec.rb
71
+ spec/spec_helper.rb
72
+ tasks/benchmark.rake
73
+ tasks/deployment.rake
74
+ tasks/environment.rake
75
+ tasks/fix.rake
76
+ tasks/jar.rake
77
+ tasks/rdoc.rake
78
+ tasks/rspec.rake
79
+ tasks/simple_ci.rake
80
+ tasks/snapshot.rake
81
+ tasks/website.rake
82
+ tasks/yard.rake
data/README.rdoc ADDED
@@ -0,0 +1,78 @@
1
+ = Celerity
2
+
3
+ * http://celerity.rubyforge.org/
4
+
5
+ == Description
6
+
7
+ Celerity is a JRuby library for easy and fast functional test automation for web applications.
8
+
9
+ It is a JRuby wrapper around HtmlUnit – a headless Java browser with
10
+ JavaScript support. It provides a simple API for programmatic navigation through
11
+ web applications. Celerity aims at being API compatible with Watir.
12
+
13
+ == Features
14
+
15
+ * *Fast*: No time-consuming GUI rendering or unessential downloads
16
+ * *Scalable*: Java threads lets you run tests in parallel
17
+ * *Easy to use*: Simple API
18
+ * *Portable*: Cross-platform thanks to the JVM
19
+ * *Unintrusive*: No browser window interrupting your workflow (runs in background)
20
+
21
+ == Requirements
22
+
23
+ * JRuby 1.2.0 or higher
24
+ * Java 6
25
+
26
+ == Install
27
+
28
+ jruby -S gem install celerity
29
+
30
+ or from GitHub (updated frequently)
31
+
32
+ jruby -S gem install jarib-celerity
33
+
34
+
35
+ == Example
36
+
37
+ require "rubygems"
38
+ require "celerity"
39
+
40
+ browser = Celerity::Browser.new
41
+ browser.goto('http://www.google.com')
42
+ browser.text_field(:name, 'q').value = 'Celerity'
43
+ browser.button(:name, 'btnG').click
44
+
45
+ puts "yay" if browser.text.include? 'celerity.rubyforge.org'
46
+
47
+ == Source
48
+
49
+ The source code is available on [GitHub](http://github.com/jarib/celerity/tree/master).
50
+
51
+
52
+ == Wiki & Bug Tracker
53
+
54
+ * [Wiki](http://github.com/jarib/celerity/wikis)
55
+ * [Bug Tracker](http://github.com/jarib/celerity/issues)
56
+
57
+ == Related projects
58
+
59
+ * [WatirSpec](http://github.com/jarib/watirspec/tree/master)
60
+ * [Celerity Viewers](http://github.com/jarib/celerity-viewers)
61
+
62
+ == License
63
+
64
+ Celerity - JRuby wrapper for HtmlUnit
65
+ Copyright (c) 2008-2009 FINN.no AS
66
+
67
+ This program is free software: you can redistribute it and/or modify
68
+ it under the terms of the GNU General Public License as published by
69
+ the Free Software Foundation, either version 3 of the License, or
70
+ (at your option) any later version.
71
+
72
+ This program is distributed in the hope that it will be useful,
73
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
74
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
75
+ GNU General Public License for more details.
76
+
77
+ You should have received a copy of the GNU General Public License
78
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
data/Rakefile CHANGED
@@ -1,12 +1,27 @@
1
- $:.unshift("#{File.dirname(__FILE__)}/lib")
2
-
3
- if File.exist?('config') # are we in a git clone
4
- require 'config/requirements'
5
- require 'config/hoe' # setup Hoe + all gem configuration
6
- Dir['tasks/**/*.rake'].each { |rake| load rake }
7
- else # in gem dir
8
- load 'tasks/jar.rake'
9
- load 'tasks/rdoc.rake'
10
- end
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.3.0'
3
+ require 'hoe'
4
+ %w[fileutils rubigen].each { |f| require f }
5
+
6
+ require "lib/celerity/version"
11
7
 
8
+ Hoe.plugin :newgem # newgem 1.5.2+
9
+ Hoe.plugin :website
12
10
 
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ Hoe.spec 'celerity' do
14
+ author << "Jari Bakken" << "T. Alexander Lystad" << "Knut Johannes Dahle"
15
+ email << "jari.bakken@finn.no"
16
+ extra_dev_deps << ['sinatra', '>= 0.9.4']
17
+ version = Celerity::VERSION
18
+ end
19
+
20
+ Dir['tasks/**/*.rake'].each do |rake|
21
+ begin
22
+ load rake
23
+ rescue LoadError
24
+ end
25
+ end
26
+ # load 'tasks/jar.rake'
27
+ # load 'tasks/rdoc.rake'
data/celerity.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{celerity}
5
+ s.version = "0.0.7"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Jari Bakken", "T. Alexander Lystad", "Knut Johannes Dahle"]
9
+ s.date = %q{2009-09-04}
10
+ s.description = %q{Celerity is a JRuby library for easy and fast functional test automation for web applications.
11
+
12
+ It is a JRuby wrapper around HtmlUnit – a headless Java browser with
13
+ JavaScript support. It provides a simple API for programmatic navigation through
14
+ web applications. Celerity aims at being API compatible with Watir.}
15
+ s.email = ["jari.bakken@finn.no"]
16
+ s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt"]
17
+ s.files = ["History.txt", "License.txt", "Manifest.txt", "README.rdoc", "Rakefile", "celerity.gemspec", "lib/celerity.rb", "lib/celerity/browser.rb", "lib/celerity/clickable_element.rb", "lib/celerity/collections.rb", "lib/celerity/container.rb", "lib/celerity/default_viewer.rb", "lib/celerity/disabled_element.rb", "lib/celerity/element.rb", "lib/celerity/element_collection.rb", "lib/celerity/element_locator.rb", "lib/celerity/elements/button.rb", "lib/celerity/elements/file_field.rb", "lib/celerity/elements/form.rb", "lib/celerity/elements/frame.rb", "lib/celerity/elements/image.rb", "lib/celerity/elements/label.rb", "lib/celerity/elements/link.rb", "lib/celerity/elements/meta.rb", "lib/celerity/elements/non_control_elements.rb", "lib/celerity/elements/option.rb", "lib/celerity/elements/radio_check.rb", "lib/celerity/elements/select_list.rb", "lib/celerity/elements/table.rb", "lib/celerity/elements/table_cell.rb", "lib/celerity/elements/table_elements.rb", "lib/celerity/elements/table_row.rb", "lib/celerity/elements/text_field.rb", "lib/celerity/exception.rb", "lib/celerity/htmlunit.rb", "lib/celerity/htmlunit/commons-codec-1.4.jar", "lib/celerity/htmlunit/commons-collections-3.2.1.jar", "lib/celerity/htmlunit/commons-httpclient-3.1.jar", "lib/celerity/htmlunit/commons-io-1.4.jar", "lib/celerity/htmlunit/commons-lang-2.4.jar", "lib/celerity/htmlunit/commons-logging-1.1.1.jar", "lib/celerity/htmlunit/cssparser-0.9.5.jar", "lib/celerity/htmlunit/htmlunit-2.6.jar", "lib/celerity/htmlunit/htmlunit-core-js-2.6.jar", "lib/celerity/htmlunit/nekohtml-1.9.13.jar", "lib/celerity/htmlunit/sac-1.3.jar", "lib/celerity/htmlunit/serializer-2.7.1.jar", "lib/celerity/htmlunit/xalan-2.7.1.jar", "lib/celerity/htmlunit/xercesImpl-2.9.1.jar", "lib/celerity/htmlunit/xml-apis-1.3.04.jar", "lib/celerity/identifier.rb", "lib/celerity/ignoring_web_connection.rb", "lib/celerity/input_element.rb", "lib/celerity/listener.rb", "lib/celerity/resources/no_viewer.png", "lib/celerity/short_inspect.rb", "lib/celerity/util.rb", "lib/celerity/version.rb", "lib/celerity/viewer_connection.rb", "lib/celerity/watir_compatibility.rb", "lib/celerity/xpath_support.rb", "spec/browser_authentication_spec.rb", "spec/browser_spec.rb", "spec/clickable_element_spec.rb", "spec/default_viewer_spec.rb", "spec/element_spec.rb", "spec/filefield_spec.rb", "spec/htmlunit_spec.rb", "spec/index_offset_spec.rb", "spec/listener_spec.rb", "spec/spec_helper.rb", "tasks/benchmark.rake", "tasks/deployment.rake", "tasks/environment.rake", "tasks/fix.rake", "tasks/jar.rake", "tasks/rdoc.rake", "tasks/rspec.rake", "tasks/simple_ci.rake", "tasks/snapshot.rake", "tasks/website.rake", "tasks/yard.rake"]
18
+ s.homepage = %q{http://celerity.rubyforge.org/}
19
+ s.rdoc_options = ["--main", "README.rdoc"]
20
+ s.require_paths = ["lib"]
21
+ s.rubyforge_project = %q{celerity}
22
+ s.rubygems_version = %q{1.3.5}
23
+ s.summary = %q{Celerity is a JRuby library for easy and fast functional test automation for web applications}
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 3
28
+
29
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
+ s.add_development_dependency(%q<sinatra>, [">= 0.9.4"])
31
+ s.add_development_dependency(%q<hoe>, [">= 2.3.3"])
32
+ else
33
+ s.add_dependency(%q<sinatra>, [">= 0.9.4"])
34
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<sinatra>, [">= 0.9.4"])
38
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
39
+ end
40
+ end
data/lib/celerity.rb CHANGED
@@ -2,13 +2,13 @@ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) ||
2
2
 
3
3
  raise "Celerity only works on JRuby at the moment." unless RUBY_PLATFORM =~ /java/
4
4
 
5
- require 'java'
5
+ require "java"
6
6
  require "logger"
7
7
  require "uri"
8
8
  require "pp"
9
9
  require "timeout"
10
10
  require "time"
11
- require 'drb'
11
+ require "socket"
12
12
  require "fileutils"
13
13
  require "thread"
14
14
 
@@ -16,12 +16,24 @@ module Celerity
16
16
  Log = Logger.new($DEBUG ? $stderr : nil)
17
17
  Log.level = Logger::DEBUG
18
18
 
19
- INDEX_OFFSET = 1
19
+ @index_offset = 1
20
+ class << self
21
+
22
+ #
23
+ # This index_offset attribute controls the indexing used when locating
24
+ # elements by :index or fetching from Celerity::ElementCollections.
25
+ #
26
+ # By default it is set to 1 for Watir compatibility, but users who use
27
+ # Celerity exlusively may want it set to 0 to make Celerity more consistent with Ruby.
28
+ #
29
+ attr_accessor :index_offset
30
+ end
31
+
20
32
  DIR = File.expand_path(File.dirname(__FILE__) + "/celerity")
21
33
  end
22
34
 
23
- require "celerity/htmlunit"
24
35
  require "celerity/version"
36
+ require "celerity/htmlunit"
25
37
  require "celerity/exception"
26
38
  require "celerity/clickable_element"
27
39
  require "celerity/disabled_element"
@@ -29,29 +41,33 @@ require "celerity/element_collection"
29
41
  require "celerity/collections"
30
42
  require "celerity/element_locator"
31
43
  require "celerity/identifier"
44
+ require "celerity/short_inspect"
32
45
  require "celerity/container"
46
+ require "celerity/xpath_support"
33
47
  require "celerity/element"
34
48
  require "celerity/input_element"
35
49
  require "celerity/elements/non_control_elements"
36
- require "celerity/elements/button.rb"
37
- require "celerity/elements/file_field.rb"
38
- require "celerity/elements/form.rb"
39
- require "celerity/elements/frame.rb"
40
- require "celerity/elements/image.rb"
41
- require "celerity/elements/label.rb"
42
- require "celerity/elements/link.rb"
43
- require "celerity/elements/meta.rb"
44
- require "celerity/elements/option.rb"
45
- require "celerity/elements/radio_check.rb"
46
- require "celerity/elements/select_list.rb"
47
- require "celerity/elements/table.rb"
48
- require "celerity/elements/table_elements.rb"
49
- require "celerity/elements/table_cell.rb"
50
- require "celerity/elements/table_row.rb"
51
- require "celerity/elements/text_field.rb"
50
+ require "celerity/elements/button"
51
+ require "celerity/elements/file_field"
52
+ require "celerity/elements/form"
53
+ require "celerity/elements/frame"
54
+ require "celerity/elements/image"
55
+ require "celerity/elements/label"
56
+ require "celerity/elements/link"
57
+ require "celerity/elements/meta"
58
+ require "celerity/elements/option"
59
+ require "celerity/elements/radio_check"
60
+ require "celerity/elements/select_list"
61
+ require "celerity/elements/table"
62
+ require "celerity/elements/table_elements"
63
+ require "celerity/elements/table_cell"
64
+ require "celerity/elements/table_row"
65
+ require "celerity/elements/text_field"
52
66
  require "celerity/util"
53
67
  require "celerity/default_viewer"
54
68
  require "celerity/listener"
69
+ require "celerity/ignoring_web_connection"
70
+ require "celerity/viewer_connection"
55
71
  require "celerity/browser"
56
72
  require "celerity/watir_compatibility"
57
73
 
@@ -1,16 +1,17 @@
1
1
  module Celerity
2
2
  class Browser
3
3
  include Container
4
+ include XpathSupport
4
5
 
5
6
  attr_accessor :page, :object, :charset
6
- attr_reader :webclient, :viewer
7
+ attr_reader :webclient, :viewer, :options
7
8
 
8
9
  #
9
10
  # Initialize a browser and go to the given URL
10
- #
11
+ #
11
12
  # @param [String] uri The URL to go to.
12
13
  # @return [Celerity::Browser] instance.
13
- #
14
+ #
14
15
 
15
16
  def self.start(uri)
16
17
  browser = new
@@ -26,27 +27,26 @@ module Celerity
26
27
  raise NotImplementedError, "use ClickableElement#click_and_attach instead"
27
28
  end
28
29
 
29
- def inspect
30
- vars = (instance_variables - %w[@webclient @browser @object])
31
- vars = vars.map { |var| "#{var}=#{instance_variable_get(var).inspect}" }.join(" ")
32
- '#<%s:0x%s %s>' % [self.class.name, self.hash.to_s(16), vars]
33
- end
34
-
35
30
  #
36
31
  # Creates a browser object.
37
32
  #
38
33
  # @see Celerity::Container for an introduction to the main API.
39
34
  #
40
- # @option opts :log_level [Symbol] (:warning) @see log_level=
41
- # @option opts :browser [:firefox, :internet_explorer] (:internet_explorer) Set the BrowserVersion used by HtmlUnit. Defaults to Internet Explorer.
35
+ # @option opts :browser [:internet_explorer, :firefox, :firefox3] (:firefox) Set the BrowserVersion used by HtmlUnit. Defaults to Firefox 2.
36
+ # @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.
42
37
  # @option opts :css [Boolean] (false) Enable CSS. Disabled by default.
43
- # @option opts :secure_ssl [Boolean] (true) Disable secure SSL. Enabled by default.
44
- # @option opts :resynchronize [Boolean] (false) Use HtmlUnit::NicelyResynchronizingAjaxController to resynchronize Ajax calls.
38
+ # @option opts :ignore_pattern [Regexp] See Browser#ignore_pattern=
39
+ # @option opts :javascript_enabled [Boolean] (true) Enable/disable JavaScript evaluation. Enabled by default.
45
40
  # @option opts :javascript_exceptions [Boolean] (false) Raise exceptions on script errors. Disabled by default.
46
- # @option opts :status_code_exceptions [Boolean] (false) Raise exceptions on failing status codes (404 etc.). Disabled by default.
47
- # @option opts :render [:html, :xml] (:html) What DOM representation to send to connected viewers.
48
- # @option opts :charset [String] ("UTF-8") Specify the charset that webclient will use by default.
41
+ # @option opts :log_level [Symbol] (:warning) @see log_level=
49
42
  # @option opts :proxy [String] (nil) Proxy server to use, in address:port format.
43
+ # @option opts :refresh_handler [:immediate, :waiting, :threaded] (:immediate) Set HtmlUnit's refresh handler.
44
+ # @option opts :render [:html, :xml] (:html) What DOM representation to send to connected viewers.
45
+ # @option opts :resynchronize [Boolean] (false) Use HtmlUnit::NicelyResynchronizingAjaxController to resynchronize Ajax calls.
46
+ # @option opts :secure_ssl [Boolean] (true) Enable/disable secure SSL. Enabled by default.
47
+ # @option opts :status_code_exceptions [Boolean] (false) Raise exceptions on failing status codes (404 etc.). Disabled by default.
48
+ # @option opts :user_agent [String] Override the User-Agent set by the :browser option
49
+ # @option opts :viewer [Boolean] (true) Connect to a CelerityViewer on port 6429 if available.
50
50
  #
51
51
  # @return [Celerity::Browser] An instance of the browser.
52
52
  #
@@ -58,22 +58,29 @@ module Celerity
58
58
  raise TypeError, "wrong argument type #{opts.class}, expected Hash"
59
59
  end
60
60
 
61
- unless (render_types = [:html, :xml, nil]).include?(opts[:render])
61
+ unless (render_types = [:html, :xml, nil, 'html', 'xml']).include?(opts[:render])
62
62
  raise ArgumentError, "expected one of #{render_types.inspect} for key :render"
63
63
  end
64
64
 
65
+ opts = opts.dup # we'll delete from opts, so dup to avoid side effects
66
+ @options = opts.dup # keep the unmodified version around as well
67
+
65
68
  @render_type = opts.delete(:render) || :html
66
69
  @charset = opts.delete(:charset) || "UTF-8"
67
- self.log_level = opts.delete(:log_level) || :warning
70
+ self.log_level = opts.delete(:log_level) || :off
68
71
 
69
- @last_url, @page = nil
70
- @error_checkers = []
71
- @browser = self # for Container#browser
72
+ @page = nil
73
+ @error_checkers = []
74
+ @browser = self # for Container#browser
75
+
76
+ setup_webclient opts
77
+ setup_viewer opts.delete(:viewer)
72
78
 
73
- setup_webclient(opts)
74
-
75
79
  raise ArgumentError, "unknown option #{opts.inspect}" unless opts.empty?
76
- find_viewer
80
+ end
81
+
82
+ def inspect
83
+ short_inspect :exclude => %w[@webclient @browser @object @options @listener @event_listener]
77
84
  end
78
85
 
79
86
  #
@@ -89,7 +96,9 @@ module Celerity
89
96
  request = HtmlUnit::WebRequestSettings.new(::Java::JavaNet::URL.new(uri))
90
97
  request.setCharset(@charset)
91
98
 
92
- self.page = @webclient.getPage(request)
99
+ rescue_status_code_exception do
100
+ self.page = @webclient.getPage(request)
101
+ end
93
102
 
94
103
  url()
95
104
  end
@@ -117,11 +126,12 @@ module Celerity
117
126
  def close
118
127
  @page = nil
119
128
  @webclient.closeAllWindows
129
+ @viewer.close
120
130
  end
121
131
 
122
132
  #
123
133
  # @return [String] the URL of the current page
124
- #
134
+ #
125
135
 
126
136
  def url
127
137
  assert_exists
@@ -136,18 +146,26 @@ module Celerity
136
146
  @page ? @page.getTitleText : ''
137
147
  end
138
148
 
149
+ #
150
+ # @return [String] the value of window.status
151
+ #
152
+
153
+ def status
154
+ execute_script "window.status" # avoid the listener overhead
155
+ end
156
+
139
157
  #
140
158
  # @return [String] the HTML content of the current page
141
159
  #
142
-
160
+
143
161
  def html
144
- @page ? @page.getWebResponse.getContentAsString : ''
162
+ @page ? @page.getWebResponse.getContentAsString(@charset) : ''
145
163
  end
146
-
164
+
147
165
  #
148
166
  # @return [String] the XML representation of the DOM
149
167
  #
150
-
168
+
151
169
  def xml
152
170
  return '' unless @page
153
171
  return @page.asXml if @page.respond_to?(:asXml)
@@ -157,14 +175,16 @@ module Celerity
157
175
  #
158
176
  # @return [String] a text representation of the current page
159
177
  #
160
-
178
+
161
179
  def text
162
180
  return '' unless @page
163
181
 
164
182
  if @page.respond_to?("getContent")
165
183
  string = @page.getContent.strip
166
- else
184
+ elsif @page.documentElement
167
185
  string = @page.documentElement.asText.strip
186
+ else
187
+ string = ''
168
188
  end
169
189
 
170
190
  # Celerity::Util.normalize_text(string)
@@ -177,27 +197,35 @@ module Celerity
177
197
 
178
198
  def response_headers
179
199
  return {} unless @page
180
-
200
+
181
201
  Hash[*@page.getWebResponse.getResponseHeaders.map { |obj| [obj.name, obj.value] }.flatten]
182
202
  end
183
203
 
204
+ #
205
+ # @return [Fixnum] status code of the last request
206
+ #
207
+
208
+ def status_code
209
+ @page.getWebResponse.getStatusCode
210
+ end
211
+
184
212
  #
185
213
  # @return [String] content-type as in 'text/html'
186
214
  #
187
215
 
188
216
  def content_type
189
217
  return '' unless @page
190
-
218
+
191
219
  @page.getWebResponse.getContentType
192
220
  end
193
221
 
194
222
  #
195
223
  # @return [IO, nil] page contents as an IO, returns nil if no page is loaded.
196
- #
197
-
224
+ #
225
+
198
226
  def io
199
227
  return nil unless @page
200
-
228
+
201
229
  @page.getWebResponse.getContentAsStream.to_io
202
230
  end
203
231
 
@@ -207,7 +235,7 @@ module Celerity
207
235
  # @param [String, Regexp] expected_text The text to look for.
208
236
  # @return [Numeric, nil] The index of the matched text, or nil if it isn't found.
209
237
  # @raise [TypeError]
210
- #
238
+ #
211
239
 
212
240
  def contains_text(expected_text)
213
241
  return nil unless exist?
@@ -215,131 +243,128 @@ module Celerity
215
243
  end
216
244
 
217
245
  #
218
- # Get the first element found matching the given XPath.
219
- #
220
- # @param [String] xpath
221
- # @return [Celerity::Element] An element subclass (or Element if none is found)
246
+ # @return [HtmlUnit::HtmlHtml] the underlying HtmlUnit document.
222
247
  #
223
-
224
- def element_by_xpath(xpath)
225
- assert_exists
226
- obj = @page.getFirstByXPath(xpath)
227
- element_from_dom_node(obj)
248
+
249
+ def document
250
+ @object
228
251
  end
229
252
 
230
253
  #
231
- # Get all the elements matching the given XPath.
232
- #
233
- # @param [String] xpath
234
- # @return [Array<Celerity::Element>] array of elements
254
+ # Goto back one history item
255
+ # @return [String] The url of the resulting page.
235
256
  #
236
-
237
- def elements_by_xpath(xpath)
238
- assert_exists
239
- objects = @page.getByXPath(xpath)
240
- # should use an ElementCollection here?
241
- objects.map { |o| element_from_dom_node(o) }.compact
242
- end
243
257
 
244
- #
245
- # @return [HtmlUnit::HtmlHtml] the underlying HtmlUnit document.
246
- #
247
-
248
- def document
249
- @object
258
+ def back
259
+ @webclient.getCurrentWindow.getHistory.back
260
+ refresh_page_from_window
261
+
262
+ url
250
263
  end
251
264
 
252
265
  #
253
- # Goto the last url - HtmlUnit doesn't have a 'back' functionality, so we only have 1 history item :)
254
- # @return [String, nil] The url of the resulting page, or nil if none was stored.
255
- #
266
+ # Go forward one history item
267
+ # @return [String] The url of the resulting page.
268
+ #
256
269
 
257
- def back
258
- # TODO: this is naive, need capability from HtmlUnit
259
- goto(@last_url) if @last_url
270
+ def forward
271
+ @webclient.getCurrentWindow.getHistory.forward
272
+ refresh_page_from_window
273
+
274
+ url
260
275
  end
261
276
 
262
277
  #
263
278
  # Wait for javascript jobs to finish
264
- #
279
+ #
265
280
 
266
281
  def wait
267
282
  assert_exists
268
- @page.getEnclosingWindow.getJobManager.waitForAllJobsToFinish(10000)
283
+ @webclient.waitForBackgroundJavaScript(10000);
269
284
  end
270
285
 
271
286
  #
272
287
  # Refresh the current page
273
- #
288
+ #
274
289
 
275
290
  def refresh
276
291
  assert_exists
277
- self.page = @page.refresh
292
+ @page.refresh
278
293
  end
279
294
 
280
295
  #
281
296
  # Clears all cookies. (Celerity only)
282
- #
297
+ #
283
298
 
284
299
  def clear_cookies
285
300
  @webclient.getCookieManager.clearCookies
286
301
  end
287
302
 
303
+ #
304
+ # Clears the cache of "compiled JavaScript files and parsed CSS snippets"
305
+ #
306
+
307
+ def clear_cache
308
+ @webclient.cache.clear
309
+ end
310
+
288
311
  #
289
312
  # Get the cookies for this session. (Celerity only)
290
- #
291
- # @return [Hash<domain, Hash<name, value>>]
313
+ #
314
+ # @return [Hash<domain, Hash<name, value>>]
292
315
  #
293
316
 
294
317
  def cookies
295
318
  result = Hash.new { |hash, key| hash[key] = {} }
296
-
319
+
297
320
  cookies = @webclient.getCookieManager.getCookies
298
321
  cookies.each do |cookie|
299
322
  result[cookie.getDomain][cookie.getName] = cookie.getValue
300
323
  end
301
-
324
+
302
325
  result
303
326
  end
304
-
327
+
305
328
  #
306
329
  # Add a cookie with the given parameters (Celerity only)
307
- #
330
+ #
308
331
  # @param [String] domain
309
332
  # @param [String] name
310
333
  # @param [String] value
311
334
  #
312
- # @option opts :path [String] ("/") A path
335
+ # @option opts :path [String] ("/") A path
313
336
  # @option opts :max_age [Fixnum] (??) A max age
314
- # @option opts :secure [Boolean] (false)
337
+ # @option opts :secure [Boolean] (false)
315
338
  #
316
-
339
+
317
340
  def add_cookie(domain, name, value, opts = {})
318
341
  path = opts.delete(:path) || "/"
319
342
  max_age = opts.delete(:max_age) || (Time.now + 60*60*24) # not sure if this is correct
320
343
  secure = opts.delete(:secure) || false
321
344
 
322
- raise "unknown option: #{opts.inspect}" unless opts.empty?
345
+ raise(ArgumentError, "unknown option: #{opts.inspect}") unless opts.empty?
323
346
 
324
347
  cookie = Cookie.new(domain, name, value, path, max_age, secure)
325
348
  @webclient.getCookieManager.addCookie(cookie)
326
349
  end
327
-
350
+
328
351
  #
329
352
  # Remove the cookie with the given domain and name (Celerity only)
330
353
  #
331
354
  # @param [String] domain
332
355
  # @param [String] name
333
356
  #
334
-
357
+ # @raise [CookieNotFoundError] if the cookie doesn't exist
358
+ #
359
+
335
360
  def remove_cookie(domain, name)
336
361
  cm = @webclient.getCookieManager
337
362
  cookie = cm.getCookies.find { |c| c.getDomain == domain && c.getName == name }
338
-
363
+
339
364
  if cookie.nil?
340
- raise "no cookie with domain #{domain.inspect} and name #{name.inspect}"
365
+ raise CookieNotFoundError, "no cookie with domain #{domain.inspect} and name #{name.inspect}"
341
366
  end
342
-
367
+
343
368
  cm.removeCookie(cookie)
344
369
  end
345
370
 
@@ -376,14 +401,18 @@ module Celerity
376
401
  # @yieldparam [Celerity::Browser] browser The browser instance.
377
402
  # @see Celerity::Browser#resynchronized
378
403
  #
379
-
404
+
380
405
  def wait_until(timeout = 30, &block)
406
+ returned = nil
407
+
381
408
  Timeout.timeout(timeout) do
382
- until yield(self)
409
+ until returned = yield(self)
383
410
  refresh_page_from_window
384
411
  sleep 0.1
385
412
  end
386
413
  end
414
+
415
+ returned
387
416
  end
388
417
 
389
418
  #
@@ -392,19 +421,24 @@ module Celerity
392
421
  # @param [Fixnum] timeout Number of seconds to wait before timing out (default: 30).
393
422
  # @yieldparam [Celerity::Browser] browser The browser instance.
394
423
  # @see Celerity::Browser#resynchronized
395
- #
424
+ #
396
425
 
397
426
  def wait_while(timeout = 30, &block)
427
+ returned = nil
428
+
398
429
  Timeout.timeout(timeout) do
399
- while yield(self)
430
+ while returned = yield(self)
400
431
  refresh_page_from_window
401
432
  sleep 0.1
402
433
  end
403
434
  end
435
+
436
+ returned
404
437
  end
405
438
 
406
439
  #
407
- # Allows you to temporarily switch to HtmlUnit's NicelyResynchronizingAjaxController to resynchronize ajax calls.
440
+ # Allows you to temporarily switch to HtmlUnit's NicelyResynchronizingAjaxController
441
+ # to resynchronize ajax calls.
408
442
  #
409
443
  # @browser.resynchronized do |b|
410
444
  # b.link(:id, 'trigger_ajax_call').click
@@ -420,15 +454,16 @@ module Celerity
420
454
  yield self
421
455
  @webclient.setAjaxController(old_controller)
422
456
  end
423
-
457
+
458
+ #
459
+ # Allows you to temporarliy switch to HtmlUnit's default AjaxController, so
460
+ # ajax calls are performed asynchronously. This is useful if you have created
461
+ # the Browser with :resynchronize => true, but want to switch it off temporarily.
424
462
  #
425
- # Allows you to temporarliy switch to HtmlUnit's default AjaxController, so ajax calls are performed asynchronously.
426
- # This is useful if you have created the Browser with :resynchronize => true, but want to switch it off temporarily.
427
- #
428
463
  # @yieldparam [Celerity::Browser] browser The current browser object.
429
464
  # @see Celerity::Browser#new
430
465
  #
431
-
466
+
432
467
  def asynchronized(&block)
433
468
  old_controller = @webclient.ajaxController
434
469
  @webclient.setAjaxController(::HtmlUnit::AjaxController.new)
@@ -440,21 +475,18 @@ module Celerity
440
475
  # Start or stop HtmlUnit's DebuggingWebConnection. (Celerity only)
441
476
  # The output will go to /tmp/«name»
442
477
  #
443
- # @param [Boolean] bool start or stop
444
- # @param [String] name required if bool is true
445
- #
446
-
447
- def debug_web_connection(bool, name = nil)
448
- if bool
449
- raise "no name given" unless name
450
- @old_webconnection = @webclient.getWebConnection
451
- dwc = HtmlUnit::Util::DebuggingWebConnection.new(@old_webconnection, name)
452
- @webclient.setWebConnection(dwc)
453
- $stderr.puts "debug-webconnection on"
454
- else
455
- @webclient.setWebConnection(@old_webconnection) if @old_webconnection
456
- $stderr.puts "debug-webconnection off"
457
- end
478
+ # @param [String] name directory name
479
+ # @param [block] blk block to execute
480
+ #
481
+
482
+ def debug_web_connection(name, &blk)
483
+ old_wc = @webclient.getWebConnection
484
+
485
+ @webclient.setWebConnection HtmlUnit::Util::DebuggingWebConnection.new(old_wc, name)
486
+ res = yield
487
+ @webclient.setWebConnection old_wc
488
+
489
+ res
458
490
  end
459
491
 
460
492
  #
@@ -469,23 +501,54 @@ module Celerity
469
501
  # :confirm => ConfirmHandler ( window.confirm() )
470
502
  # :prompt => PromptHandler ( window.prompt() )
471
503
  #
504
+ # Examples:
505
+ #
506
+ # browser.add_listener(:status) { |page, message| ... }
507
+ # browser.add_listener(:alert) { |page, message| ... }
508
+ # browser.add_listener(:web_window_event) { |web_window_event| ... }
509
+ # browser.add_listener(:html_parser) { |message, url, line, column, key| ... }
510
+ # browser.add_listener(:incorrectness) { |message, origin| ... }
511
+ # browser.add_listener(:confirm) { |page, message| ...; true }
512
+ # browser.add_listener(:prompt) { |page, message| ... }
513
+ #
472
514
  #
473
515
  # @param [Symbol] type One of the above symbols.
474
516
  # @param [Proc] block A block to be executed for events of this type.
475
- #
517
+ #
476
518
 
477
519
  def add_listener(type, &block)
478
- @listener ||= Celerity::Listener.new(@webclient)
479
- @listener.add_listener(type, &block)
520
+ listener.add_listener(type, &block)
521
+ end
522
+
523
+ def remove_listener(type, &block)
524
+ listener.remove_listener(type, &block)
480
525
  end
481
-
526
+
527
+ #
528
+ # Specify a boolean value to click either 'OK' or 'Cancel' in any confirm
529
+ # dialogs that might show up during the duration of the given block.
530
+ #
531
+ # (Celerity only)
532
+ #
533
+ # @param [Boolean] bool true to click 'OK', false to click 'cancel'
534
+ # @param [Proc] block A block that will trigger the confirm() call(s).
535
+ #
536
+
537
+ def confirm(bool, &block)
538
+ blk = lambda { bool }
539
+
540
+ listener.add_listener(:confirm, &blk)
541
+ yield
542
+ listener.remove_listener(:confirm, blk)
543
+ end
544
+
482
545
  #
483
546
  # Add a 'checker' proc that will be run on every page load
484
547
  #
485
548
  # @param [Proc] checker The proc to be run (can also be given as a block)
486
549
  # @yieldparam [Celerity::Browser] browser The current browser object.
487
550
  # @raise [ArgumentError] if no Proc or block was given.
488
- #
551
+ #
489
552
 
490
553
  def add_checker(checker = nil, &block)
491
554
  if block_given?
@@ -500,7 +563,7 @@ module Celerity
500
563
  #
501
564
  # Remove the given checker from the list of checkers
502
565
  # @param [Proc] checker The Proc to disable.
503
- #
566
+ #
504
567
 
505
568
  def disable_checker(checker)
506
569
  @error_checkers.delete(checker)
@@ -508,22 +571,45 @@ module Celerity
508
571
 
509
572
  #
510
573
  # :finest, :finer, :fine, :config, :info, :warning, :severe, or :off, :all
511
- #
574
+ #
512
575
  # @return [Symbol] the current log level
513
- #
576
+ #
514
577
 
515
578
  def log_level
516
- java.util.logging.Logger.getLogger('com.gargoylesoftware.htmlunit').level.to_s.downcase.to_sym
579
+ Celerity::Util.logger_for('com.gargoylesoftware.htmlunit').level.to_s.downcase.to_sym
517
580
  end
518
581
 
519
582
  #
520
- # Set Java log level (default is :warning)
583
+ # Set Java log level (default is :warning, can be any of :all, :finest, :finer, :fine, :config, :info, :warning, :severe, :off)
584
+ #
585
+ # @param [Symbol] level The new log level.
521
586
  #
522
- # @param [Symbol] level :finest, :finer, :fine, :config, :info, :warning, :severe, or :off, :all
523
- #
524
587
 
525
588
  def log_level=(level)
526
- java.util.logging.Logger.getLogger('com.gargoylesoftware.htmlunit').level = java.util.logging.Level.const_get(level.to_s.upcase)
589
+ log_level = java.util.logging.Level.const_get(level.to_s.upcase)
590
+
591
+ [ 'com.gargoylesoftware.htmlunit',
592
+ 'com.gargoylesoftware.htmlunit.html',
593
+ 'com.gargoylesoftware.htmlunit.javascript',
594
+ 'org.apache.commons.httpclient'
595
+ ].each { |package| Celerity::Util.logger_for(package).level = log_level }
596
+
597
+ level
598
+ end
599
+
600
+ #
601
+ # If a request is made to an URL that matches the pattern set here, Celerity
602
+ # will ignore the request and return an empty page with content type "text/html" instead.
603
+ #
604
+ # This is useful to block unwanted requests (like ads/banners).
605
+ #
606
+
607
+ def ignore_pattern=(regexp)
608
+ unless regexp.kind_of?(Regexp)
609
+ raise TypeError, "expected Regexp, got #{regexp.inspect}:#{regexp.class}"
610
+ end
611
+
612
+ Celerity::IgnoringWebConnection.new(@webclient, regexp)
527
613
  end
528
614
 
529
615
  #
@@ -536,6 +622,91 @@ module Celerity
536
622
  end
537
623
  alias_method :exists?, :exist?
538
624
 
625
+ #
626
+ # Turn on/off javascript exceptions
627
+ #
628
+ # @param [Bool]
629
+ #
630
+
631
+ def javascript_exceptions=(bool)
632
+ @webclient.throwExceptionOnScriptError = bool
633
+ end
634
+
635
+ def javascript_exceptions
636
+ @webclient.throwExceptionOnScriptError
637
+ end
638
+
639
+ #
640
+ # Turn on/off status code exceptions
641
+ #
642
+ # @param [Bool]
643
+ #
644
+
645
+ def status_code_exceptions=(bool)
646
+ @webclient.throwExceptionOnFailingStatusCode = bool
647
+ end
648
+
649
+ def status_code_exceptions
650
+ @webclient.throwExceptionOnFailingStatusCode
651
+ end
652
+
653
+ #
654
+ # Turn on/off CSS loading
655
+ #
656
+ # @param [Bool]
657
+ #
658
+
659
+ def css=(bool)
660
+ @webclient.cssEnabled = bool
661
+ end
662
+
663
+ def css
664
+ @webclient.cssEnabled
665
+ end
666
+
667
+ def refresh_handler=(symbol)
668
+ handler = case symbol
669
+ when :waiting
670
+ HtmlUnit::WaitingRefreshHandler.new
671
+ when :threaded
672
+ HtmlUnit::ThreadedRefreshHandler.new
673
+ when :immediate
674
+ HtmlUnit::ImmediateRefreshHandler.new
675
+ else
676
+ raise ArgumentError, "expected :waiting, :threaded or :immediate"
677
+ end
678
+
679
+ @webclient.setRefreshHandler handler
680
+ end
681
+
682
+ #
683
+ # Turn on/off secure SSL
684
+ #
685
+ # @param [Bool]
686
+ #
687
+
688
+ def secure_ssl=(bool)
689
+ @webclient.useInsecureSSL = !bool
690
+ end
691
+
692
+ def secure_ssl
693
+ !@webclient.useInsecureSSL
694
+ end
695
+
696
+ #
697
+ # Turn on/off JavaScript execution
698
+ #
699
+ # @param [Bool]
700
+ #
701
+
702
+ def javascript_enabled=(bool)
703
+ @webclient.setJavaScriptEnabled(bool)
704
+ end
705
+
706
+ def javascript_enabled
707
+ @webclient.isJavaScriptEnabled
708
+ end
709
+
539
710
  #
540
711
  # Sets the current page object for the browser
541
712
  #
@@ -544,11 +715,11 @@ module Celerity
544
715
  #
545
716
 
546
717
  def page=(value)
547
- @last_url = url() if exist?
718
+ return if @page == value
548
719
  @page = value
549
720
 
550
721
  if @page.respond_to?("getDocumentElement")
551
- @object = @page.getDocumentElement
722
+ @object = @page.getDocumentElement || @object
552
723
  elsif @page.is_a? HtmlUnit::UnexpectedPage
553
724
  raise UnexpectedPageException, @page.getWebResponse.getContentType
554
725
  end
@@ -562,21 +733,52 @@ module Celerity
562
733
  #
563
734
  # Check that we have a @page object.
564
735
  #
565
- # @raise [Celerity::Exception::UnknownObjectException] if no page is loaded.
736
+ # @raise [UnknownObjectException] if no page is loaded.
566
737
  # @api private
567
- #
568
-
738
+ #
739
+
569
740
  def assert_exists
570
741
  raise UnknownObjectException, "no page loaded" unless exist?
571
742
  end
572
-
743
+
573
744
  #
574
745
  # Returns the element that currently has the focus (Celerity only)
575
746
  #
576
747
 
577
748
  def focused_element
578
749
  element_from_dom_node(page.getFocusedElement())
579
- end
750
+ end
751
+
752
+ #
753
+ # Enable Celerity's internal WebWindowEventListener
754
+ #
755
+ # @api private
756
+ #
757
+
758
+ def enable_event_listener
759
+ @event_listener ||= lambda do |event|
760
+ self.page = @page ? @page.getEnclosingWindow.getEnclosedPage : event.getNewPage
761
+ end
762
+
763
+ listener.add_listener(:web_window_event, &@event_listener)
764
+ end
765
+
766
+ #
767
+ # Disable Celerity's internal WebWindowEventListener
768
+ #
769
+ # @api private
770
+ #
771
+
772
+ def disable_event_listener
773
+ listener.remove_listener(:web_window_event, @event_listener)
774
+
775
+ if block_given?
776
+ result = yield
777
+ enable_event_listener
778
+
779
+ result
780
+ end
781
+ end
580
782
 
581
783
  private
582
784
 
@@ -585,49 +787,78 @@ module Celerity
585
787
  #
586
788
  # @see add_checker
587
789
  # @api private
588
- #
589
-
790
+ #
791
+
590
792
  def run_error_checks
591
793
  @error_checkers.each { |e| e[self] }
592
794
  end
593
-
795
+
594
796
  #
595
797
  # Configure the webclient according to the options given to #new.
596
798
  # @see initialize
597
799
  #
598
800
 
599
801
  def setup_webclient(opts)
600
- browser = (opts.delete(:browser) || :internet_explorer).to_sym
802
+ browser = (opts.delete(:browser) || :firefox).to_sym
803
+
804
+ browser_version = case browser
805
+ when :firefox, :ff, :ff2
806
+ ::HtmlUnit::BrowserVersion::FIREFOX_2
807
+ when :firefox3, :ff3
808
+ ::HtmlUnit::BrowserVersion::FIREFOX_3
809
+ when :internet_explorer, :ie
810
+ ::HtmlUnit::BrowserVersion::INTERNET_EXPLORER_7
811
+ else
812
+ raise ArgumentError, "unknown browser: #{browser.inspect}"
813
+ end
814
+
815
+ if ua = opts.delete(:user_agent)
816
+ browser_version.setUserAgent(ua)
817
+ end
601
818
 
602
- case browser
603
- when :firefox
604
- browser_version = ::HtmlUnit::BrowserVersion::FIREFOX_2
605
- when :internet_explorer, :ie
606
- browser_version = ::HtmlUnit::BrowserVersion::INTERNET_EXPLORER_7_0
607
- else
608
- raise ArgumentError, "unknown browser: #{browser.inspect}"
819
+ @webclient = if proxy = opts.delete(:proxy)
820
+ phost, pport = proxy.split(":")
821
+ ::HtmlUnit::WebClient.new(browser_version, phost, pport.to_i)
822
+ else
823
+ ::HtmlUnit::WebClient.new(browser_version)
824
+ end
825
+
826
+ self.javascript_exceptions = false unless opts.delete(:javascript_exceptions)
827
+ self.status_code_exceptions = false unless opts.delete(:status_code_exceptions)
828
+ self.css = false unless opts.delete(:css)
829
+ self.javascript_enabled = opts.delete(:javascript_enabled) != false
830
+ self.secure_ssl = opts.delete(:secure_ssl) == false
831
+ self.ignore_pattern = opts.delete(:ignore_pattern) if opts[:ignore_pattern]
832
+ self.refresh_handler = opts.delete(:refresh_handler) if opts[:refresh_handler]
833
+
834
+ if opts.delete(:resynchronize)
835
+ controller = ::HtmlUnit::NicelyResynchronizingAjaxController.new
836
+ @webclient.setAjaxController controller
609
837
  end
610
838
 
611
- if proxy = opts.delete(:proxy)
612
- phost, pport = proxy.split(":")
613
- @webclient = ::HtmlUnit::WebClient.new(browser_version, phost, pport.to_i)
614
- else
615
- @webclient = ::HtmlUnit::WebClient.new(browser_version)
839
+ enable_event_listener
840
+ end
841
+
842
+ def setup_viewer(option)
843
+ @viewer = DefaultViewer
844
+ return if option == false
845
+
846
+ host_string = option.kind_of?(String) ? option : "127.0.0.1:6429"
847
+ host, port = host_string.split(":")
848
+
849
+ if viewer = ViewerConnection.create(host, port.to_i)
850
+ @viewer = viewer
616
851
  end
617
-
618
- @webclient.throwExceptionOnScriptError = false unless opts.delete(:javascript_exceptions)
619
- @webclient.throwExceptionOnFailingStatusCode = false unless opts.delete(:status_code_exceptions)
620
- @webclient.cssEnabled = false unless opts.delete(:css)
621
- @webclient.useInsecureSSL = opts.delete(:secure_ssl) == false
622
- @webclient.setAjaxController(::HtmlUnit::NicelyResynchronizingAjaxController.new) if opts.delete(:resynchronize)
852
+ rescue Errno::ECONNREFUSED => e
853
+ nil
623
854
  end
624
855
 
625
856
  #
626
857
  # This *should* be unneccessary, but sometimes the page we get from the
627
858
  # window is different (ie. a different object) from our current @page
628
859
  # (Used by #wait_while and #wait_until)
629
- #
630
-
860
+ #
861
+
631
862
  def refresh_page_from_window
632
863
  new_page = @page.getEnclosingWindow.getEnclosedPage
633
864
 
@@ -637,44 +868,20 @@ module Celerity
637
868
  Log.debug "unneccessary refresh"
638
869
  end
639
870
  end
640
-
871
+
641
872
  #
642
- # Render the current page on the viewer.
873
+ # Render the current page on the connected viewer.
643
874
  # @api private
644
- #
875
+ #
645
876
 
646
877
  def render
647
878
  @viewer.render_html(self.send(@render_type), url)
648
- rescue DRb::DRbConnError, Errno::ECONNREFUSED => e
879
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EPIPE
649
880
  @viewer = DefaultViewer
650
881
  end
651
882
 
652
- #
653
- # Check if we have a viewer available on druby://127.0.0.1:6429
654
- # @api private
655
- #
656
-
657
- def find_viewer
658
- viewer = DRbObject.new_with_uri("druby://127.0.0.1:6429")
659
- if viewer.respond_to?(:render_html)
660
- @viewer = viewer
661
- else
662
- @viewer = DefaultViewer
663
- end
664
- rescue DRb::DRbConnError, Errno::ECONNREFUSED
665
- @viewer = DefaultViewer
666
- end
667
-
668
- #
669
- # Convert the given HtmlUnit object to a Celerity object
670
- #
671
-
672
- def element_from_dom_node(obj)
673
- if element_class = Celerity::Util.htmlunit2celerity(obj.class)
674
- element_class.new(self, :object, obj)
675
- else
676
- Element.new(self, :object, nil)
677
- end
883
+ def listener
884
+ @listener ||= Celerity::Listener.new(@webclient)
678
885
  end
679
886
 
680
887
  end # Browser