celerity 0.0.6 → 0.0.7

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