seleniumrc 0.0.1

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 (35) hide show
  1. data/CHANGES +2 -0
  2. data/README +0 -0
  3. data/Rakefile +68 -0
  4. data/lib/seleniumrc/app_server_checker.rb +43 -0
  5. data/lib/seleniumrc/dsl/selenium_dsl.rb +186 -0
  6. data/lib/seleniumrc/dsl/test_unit_dsl.rb +95 -0
  7. data/lib/seleniumrc/extensions/selenium_driver.rb +33 -0
  8. data/lib/seleniumrc/extensions/testrunnermediator.rb +19 -0
  9. data/lib/seleniumrc/mongrel_selenium_server_runner.rb +35 -0
  10. data/lib/seleniumrc/selenium_configuration.rb +78 -0
  11. data/lib/seleniumrc/selenium_context.rb +226 -0
  12. data/lib/seleniumrc/selenium_element.rb +195 -0
  13. data/lib/seleniumrc/selenium_helper.rb +5 -0
  14. data/lib/seleniumrc/selenium_page.rb +76 -0
  15. data/lib/seleniumrc/selenium_server_runner.rb +33 -0
  16. data/lib/seleniumrc/selenium_test_case.rb +95 -0
  17. data/lib/seleniumrc/tasks/selenium_test_task.rb +21 -0
  18. data/lib/seleniumrc/wait_for.rb +47 -0
  19. data/lib/seleniumrc/webrick_selenium_server_runner.rb +33 -0
  20. data/lib/seleniumrc.rb +28 -0
  21. data/spec/seleniumrc/app_server_checker_spec.rb +56 -0
  22. data/spec/seleniumrc/mongrel_selenium_server_runner_spec.rb +42 -0
  23. data/spec/seleniumrc/selenese_interpreter_spec.rb +25 -0
  24. data/spec/seleniumrc/selenium_configuration_spec.rb +21 -0
  25. data/spec/seleniumrc/selenium_context_spec.rb +362 -0
  26. data/spec/seleniumrc/selenium_element_spec.rb +530 -0
  27. data/spec/seleniumrc/selenium_page_spec.rb +226 -0
  28. data/spec/seleniumrc/selenium_server_runner_spec.rb +42 -0
  29. data/spec/seleniumrc/selenium_test_case_class_method_spec.rb +41 -0
  30. data/spec/seleniumrc/selenium_test_case_spec.rb +908 -0
  31. data/spec/seleniumrc/selenium_test_case_spec_helper.rb +23 -0
  32. data/spec/seleniumrc/webrick_selenium_server_runner_spec.rb +116 -0
  33. data/spec/spec_helper.rb +57 -0
  34. data/spec/spec_suite.rb +4 -0
  35. metadata +83 -0
@@ -0,0 +1,226 @@
1
+ module Seleniumrc
2
+ # The application state and Dependency Injection container of the Seleniumrc objects.
3
+ # All objects are created through the SeleniumContext. All global state is encapsulated here.
4
+ class SeleniumContext
5
+ attr_accessor :configuration,
6
+ :env,
7
+ :rails_env,
8
+ :rails_root,
9
+ :browsers,
10
+ :current_browser,
11
+ :interpreter,
12
+ :browser_mode,
13
+ :selenium_server_host,
14
+ :selenium_server_port,
15
+ :app_server_engine,
16
+ :internal_app_server_host,
17
+ :internal_app_server_port,
18
+ :external_app_server_host,
19
+ :external_app_server_port,
20
+ :server_engine,
21
+ :keep_browser_open_on_failure,
22
+ :verify_remote_app_server_is_running
23
+
24
+ def initialize
25
+ self.verify_remote_app_server_is_running = true
26
+ @before_suite_listeners = []
27
+ @after_selenese_interpreter_started_listeners = []
28
+ end
29
+
30
+ # A callback hook that gets run before the suite is run.
31
+ def before_suite(&block)
32
+ @before_suite_listeners << block
33
+ end
34
+
35
+ # Notify all before_suite callbacks.
36
+ def notify_before_suite
37
+ for listener in @before_suite_listeners
38
+ listener.call
39
+ end
40
+ end
41
+
42
+ # A callback hook that gets run after the Selenese Interpreter is started.
43
+ def after_selenese_interpreter_started(&block)
44
+ @after_selenese_interpreter_started_listeners << block
45
+ end
46
+
47
+ # Notify all after_selenese_interpreter_started callbacks.
48
+ def notify_after_selenese_interpreter_started(interpreter)
49
+ for listener in @after_selenese_interpreter_started_listeners
50
+ listener.call(interpreter)
51
+ end
52
+ end
53
+
54
+ # The browser formatted for the Selenese interpreter.
55
+ def formatted_browser
56
+ return "*#{@current_browser}"
57
+ end
58
+
59
+ # Has a failure occurred in the tests?
60
+ def failure_has_occurred?
61
+ @failure_has_occurred = true
62
+ end
63
+
64
+ # Sets the failure state to true
65
+ def failure_has_occurred!
66
+ @failure_has_occurred = true
67
+ end
68
+
69
+ # Sets the failure state to false
70
+ def failure_has_not_occurred!
71
+ @failure_has_occurred = false
72
+ end
73
+
74
+ # The http host name and port to be entered into the browser address bar
75
+ def browser_url
76
+ "http://#{external_app_server_host}:#{external_app_server_port}"
77
+ end
78
+
79
+ # The root directory (public) of the Rails application
80
+ def server_root
81
+ File.expand_path("#{rails_root}/public/")
82
+ end
83
+
84
+ # Sets the Test Suite to open a new browser instance for each TestCase
85
+ def test_browser_mode!
86
+ @browser_mode = SeleniumConfiguration::BrowserMode::Test
87
+ end
88
+
89
+ # Are we going to open a new browser instance for each TestCase?
90
+ def test_browser_mode?
91
+ @browser_mode == SeleniumConfiguration::BrowserMode::Test
92
+ end
93
+
94
+ # Sets the Test Suite to use one browser instance
95
+ def suite_browser_mode!
96
+ @browser_mode = SeleniumConfiguration::BrowserMode::Suite
97
+ end
98
+
99
+ # Does the Test Suite to use one browser instance?
100
+ def suite_browser_mode?
101
+ @browser_mode == SeleniumConfiguration::BrowserMode::Suite
102
+ end
103
+
104
+ def run_each_browser # nodoc
105
+ browsers.each do |browser|
106
+ self.current_browser = browser
107
+ yield
108
+ break if @failure_has_occurred
109
+ end
110
+ end
111
+
112
+ # The Selenese Interpreter object. This is the Interpreter provided by the Selenium RC (http://openqa.org/selenium-rc/) project.
113
+ def selenese_interpreter
114
+ return nil unless suite_browser_mode?
115
+ unless @interpreter
116
+ @interpreter = create_and_initialize_interpreter
117
+ end
118
+ @interpreter
119
+ end
120
+
121
+ def stop_interpreter_if_necessary(suite_passed) # nodoc
122
+ failure_has_occurred! unless suite_passed
123
+ if @interpreter && stop_selenese_interpreter?(suite_passed)
124
+ @interpreter.stop
125
+ @interpreter = nil
126
+ end
127
+ end
128
+
129
+ def stop_selenese_interpreter?(passed) # nodoc
130
+ return true if passed
131
+ return !keep_browser_open_on_failure
132
+ end
133
+
134
+ def create_app_server_checker # nodoc
135
+ app_server_checker = AppServerChecker.new()
136
+ app_server_checker.context = self
137
+ app_server_checker.tcp_socket_class = TCPSocket
138
+ return app_server_checker
139
+ end
140
+
141
+ def create_and_initialize_interpreter # nodoc
142
+ interpreter = create_interpreter
143
+ interpreter.start
144
+ notify_after_selenese_interpreter_started(interpreter)
145
+ interpreter
146
+ end
147
+
148
+ def create_interpreter # nodoc
149
+ return Selenium::SeleneseInterpreter.new(
150
+ selenium_server_host,
151
+ selenium_server_port,
152
+ formatted_browser,
153
+ browser_url,
154
+ 15000
155
+ )
156
+ end
157
+
158
+ def create_server_runner # nodoc
159
+ case @app_server_engine.to_sym
160
+ when :mongrel
161
+ create_mongrel_runner
162
+ when :webrick
163
+ create_webrick_runner
164
+ else
165
+ raise "Invalid server type: #{selenium_context.app_server_type}"
166
+ end
167
+ end
168
+
169
+ def create_webrick_runner # nodoc
170
+ require 'webrick_server'
171
+ runner = WebrickSeleniumServerRunner.new
172
+ runner.context = self
173
+ runner.thread_class = Thread
174
+ runner.socket = Socket
175
+ runner.dispatch_servlet = DispatchServlet
176
+ runner.environment_path = File.expand_path("#{@rails_root}/config/environment")
177
+ runner
178
+ end
179
+
180
+ def create_webrick_server # nodoc
181
+ WEBrick::HTTPServer.new({
182
+ :Port => @internal_app_server_port,
183
+ :BindAddress => @internal_app_server_host,
184
+ :ServerType => WEBrick::SimpleServer,
185
+ :MimeTypes => WEBrick::HTTPUtils::DefaultMimeTypes,
186
+ :Logger => new_logger,
187
+ :AccessLog => []
188
+ })
189
+ end
190
+
191
+ def new_logger
192
+ Logger.new(StringIO.new)
193
+ end
194
+
195
+ def create_mongrel_runner # nodoc
196
+ runner = MongrelSeleniumServerRunner.new
197
+ runner.context = self
198
+ runner.thread_class = Thread
199
+ runner
200
+ end
201
+
202
+ def create_mongrel_configurator # nodoc
203
+ dir = File.dirname(__FILE__)
204
+ require 'mongrel/rails'
205
+ settings = {
206
+ :host => internal_app_server_host,
207
+ :port => internal_app_server_port,
208
+ :cwd => @rails_root,
209
+ :log_file => "#{@rails_root}/log/mongrel.log",
210
+ :pid_file => "#{@rails_root}/log/mongrel.pid",
211
+ :environment => @rails_env,
212
+ :docroot => "public",
213
+ :mime_map => nil,
214
+ :daemon => false,
215
+ :debug => false,
216
+ :includes => ["mongrel"],
217
+ :config_script => nil
218
+ }
219
+
220
+ configurator = Mongrel::Rails::RailsConfigurator.new(settings) do
221
+ log "Starting Mongrel in #{defaults[:environment]} mode at #{defaults[:host]}:#{defaults[:port]}"
222
+ end
223
+ configurator
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,195 @@
1
+ module Seleniumrc
2
+ class SeleniumElement
3
+ include WaitFor
4
+ attr_reader :selenium, :locator
5
+
6
+ def initialize(selenium, locator)
7
+ @selenium = selenium
8
+ @locator = locator
9
+ end
10
+
11
+ def is_present(params={})
12
+ params = {:message => "Expected element '#{locator}' to be present, but it was not"}.merge(params)
13
+ wait_for(params) do
14
+ is_present?
15
+ end
16
+ end
17
+ def is_present?
18
+ selenium.is_element_present(locator)
19
+ end
20
+
21
+ def is_not_present(params={})
22
+ params = {:message => "Expected element '#{locator}' to be absent, but it was not"}.merge(params)
23
+ wait_for(:message => params[:message]) do
24
+ is_not_present?
25
+ end
26
+ end
27
+ def is_not_present?
28
+ !selenium.is_element_present(locator)
29
+ end
30
+
31
+ def has_value(expected_value)
32
+ is_present
33
+ wait_for do |context|
34
+ actual_value = selenium.get_value(locator)
35
+ context.message = "Expected '#{locator}' to be '#{expected_value}' but was '#{actual_value}'"
36
+ has_value? expected_value, actual_value
37
+ end
38
+ end
39
+ def has_value?(expected_value, actual_value=selenium.get_value(locator))
40
+ expected_value == actual_value
41
+ end
42
+
43
+ def has_attribute(expected_value)
44
+ is_present
45
+ wait_for do |context|
46
+ actual = selenium.get_attribute(locator) #todo: actual value
47
+ context.message = "Expected attribute '#{locator}' to be '#{expected_value}' but was '#{actual}'"
48
+ expected_value == actual
49
+ end
50
+ end
51
+
52
+ def has_selected(expected_value)
53
+ is_present
54
+ wait_for do |context|
55
+ actual = selenium.get_selected_label(locator)
56
+ context.message = "Expected '#{locator}' to be selected with '#{expected_value}' but was '#{actual}"
57
+ expected_value == actual
58
+ end
59
+ end
60
+
61
+ def is_visible(options={})
62
+ is_present
63
+ options = {
64
+ :message => "Expected '#{locator}' to be visible, but it wasn't"
65
+ }.merge(options)
66
+ wait_for(options) do
67
+ selenium.is_visible(locator)
68
+ end
69
+ end
70
+
71
+ def is_not_visible(options={})
72
+ is_present
73
+ options = {
74
+ :message => "Expected '#{locator}' to be hidden, but it wasn't"
75
+ }.merge(options)
76
+ wait_for(options) do
77
+ !selenium.is_visible(locator)
78
+ end
79
+ end
80
+
81
+ def is_checked
82
+ is_present
83
+ wait_for(:message => "Expected '#{locator}' to be checked") do
84
+ selenium.is_checked(locator)
85
+ end
86
+ end
87
+
88
+ def is_not_checked
89
+ is_present
90
+ wait_for(:message => "Expected '#{locator}' to be checked") do
91
+ !selenium.is_checked(locator)
92
+ end
93
+ end
94
+
95
+ def has_text(expected_text, options={})
96
+ is_present
97
+ wait_for(options) do |context|
98
+ actual = selenium.get_text(locator)
99
+ context.message = "Expected text '#{expected_text}' to be full contents of #{locator} but was '#{actual}')"
100
+ expected_text == actual
101
+ end
102
+ end
103
+
104
+ def contains_text(expected_text, options={})
105
+ is_present
106
+ options = {
107
+ :message => "#{locator} should contain #{expected_text}"
108
+ }.merge(options)
109
+ wait_for(options) do
110
+ inner_html.include?(expected_text)
111
+ end
112
+ end
113
+
114
+ def does_not_contain_text(expected_text, options={})
115
+ is_present
116
+ wait_for(options) do
117
+ !inner_html.include?(expected_text)
118
+ end
119
+ end
120
+
121
+ def has_next_sibling(expected_sibling_id, options = {})
122
+ is_present
123
+ eval_js = "this.page().findElement('#{locator}').nextSibling.id"
124
+ wait_for(:message => "id '#{locator}' should be next to '#{expected_sibling_id}'") do
125
+ actual_sibling_id = selenium.get_eval(eval_js)
126
+ expected_sibling_id == actual_sibling_id
127
+ end
128
+ end
129
+
130
+ def has_text_in_order(*text_fragments)
131
+ is_present
132
+ wait_for do |context|
133
+ success = false
134
+
135
+ html = selenium.get_text(locator)
136
+ results = find_text_order_error_fragments(html, text_fragments)
137
+ fragments_not_found = results[:fragments_not_found]
138
+ fragments_out_of_order = results[:fragments_out_of_order]
139
+
140
+ if !fragments_not_found.empty?
141
+ context.message = "Certain fragments weren't found:\n" <<
142
+ "#{fragments_not_found.join("\n")}\n" <<
143
+ "\nhtml follows:\n #{html}\n"
144
+ elsif !fragments_out_of_order.empty?
145
+ context.message = "Certain fragments were out of order:\n" <<
146
+ "#{fragments_out_of_order.join("\n")}\n" <<
147
+ "\nhtml follows:\n #{html}\n"
148
+ else
149
+ success = true
150
+ end
151
+
152
+ success
153
+ end
154
+ end
155
+
156
+ def inner_html
157
+ selenium.get_eval("this.page().findElement(\"#{locator}\").innerHTML")
158
+ end
159
+
160
+ def ==(other)
161
+ return false unless other.is_a?(SeleniumElement)
162
+ return false unless self.selenium == other.selenium
163
+ return false unless self.locator == other.locator
164
+ true
165
+ end
166
+
167
+ protected
168
+ def find_text_order_error_fragments(html, text_fragments)
169
+ fragments_not_found = []
170
+ fragments_out_of_order = []
171
+
172
+ previous_index = -1
173
+ previous_fragment = ''
174
+ text_fragments.each do |current_fragment|
175
+ current_index = html.index(current_fragment)
176
+ if current_index
177
+ if current_index < previous_index
178
+ message = "Fragment #{current_fragment} out of order:\n" <<
179
+ "\texpected '#{previous_fragment}'\n" <<
180
+ "\tto come before '#{current_fragment}'\n"
181
+ fragments_out_of_order << message
182
+ end
183
+ else
184
+ fragments_not_found << "Fragment #{current_fragment} was not found\n"
185
+ end
186
+ previous_index = current_index
187
+ previous_fragment = current_fragment
188
+ end
189
+ {
190
+ :fragments_not_found => fragments_not_found,
191
+ :fragments_out_of_order => fragments_out_of_order
192
+ }
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,5 @@
1
+ # Expand the path to environment so that Ruby does not load it multiple times
2
+ # File.expand_path can be removed if Ruby 1.9 is in use.
3
+ if (Object.const_defined?(:ActiveRecord) && !ActiveRecord::Base.allow_concurrency)
4
+ raise "Since Selenium spawns an internal app server, we need ActiveRecord to be multi-threaded. Please set 'ActiveRecord::Base.allow_concurrency = true' in your environment file (e.g. test.rb)."
5
+ end
@@ -0,0 +1,76 @@
1
+ module Seleniumrc
2
+ class SeleniumPage
3
+ include WaitFor
4
+ attr_reader :selenium
5
+ PAGE_LOADED_COMMAND = "this.browserbot.getDocument().body ? true : false"
6
+
7
+ def initialize(selenium)
8
+ @selenium = selenium
9
+ end
10
+
11
+ def open_and_wait(url)
12
+ selenium.open(url)
13
+ wait_for_page_to_load
14
+ end
15
+
16
+ def has_title(expected_title, params = {})
17
+ wait_for(params) do |context|
18
+ actual_title = selenium.get_title
19
+ context.message = "Expected title '#{expected_title}' but was '#{actual_title}'"
20
+ has_title? expected_title, actual_title
21
+ end
22
+ end
23
+ def has_title?(expected_title, actual_title=selenium.get_title)
24
+ expected_title == actual_title
25
+ end
26
+
27
+ def is_text_present(expected_text, options = {})
28
+ options = {
29
+ :message => "Expected '#{expected_text}' to be present, but it wasn't"
30
+ }.merge(options)
31
+ wait_for(options) do
32
+ is_text_present? expected_text
33
+ end
34
+ end
35
+ def is_text_present?(expected_text)
36
+ page_loaded? && selenium.is_text_present(expected_text)
37
+ end
38
+
39
+ def is_text_not_present(unexpected_text, options = {})
40
+ options = {
41
+ :message => "Expected '#{unexpected_text}' to be absent, but it wasn't"
42
+ }.merge(options)
43
+ wait_for(options) do
44
+ is_text_not_present? unexpected_text
45
+ end
46
+ end
47
+ def is_text_not_present?(unexpected_text)
48
+ page_loaded? && !selenium.is_text_present(unexpected_text)
49
+ end
50
+
51
+ def page_loaded?
52
+ selenium.get_eval(PAGE_LOADED_COMMAND) == true.to_s
53
+ end
54
+
55
+ def url_ends_with(ends_with, options={})
56
+ options = {
57
+ :message => "Expected '#{selenium.get_location}' to end with '#{ends_with}'"
58
+ }.merge(options)
59
+ wait_for(options) do
60
+ url_ends_with? ends_with
61
+ end
62
+ end
63
+ def url_ends_with?(ends_with)
64
+ if selenium.get_location =~ Regexp.new("#{Regexp.escape(ends_with)}$")
65
+ true
66
+ else
67
+ false
68
+ end
69
+ end
70
+
71
+ def ==(other)
72
+ return false unless other.is_a?(SeleniumPage)
73
+ self.selenium == other.selenium
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,33 @@
1
+ module Seleniumrc
2
+ class SeleniumServerRunner
3
+ attr_accessor :context, :thread_class
4
+ def initialize
5
+ @started = false
6
+ end
7
+
8
+ def start
9
+ @thread_class.start do
10
+ start_server
11
+ end
12
+ @started = true
13
+ end
14
+
15
+ def stop
16
+ stop_server
17
+ @started = false
18
+ end
19
+
20
+ def started?
21
+ @started
22
+ end
23
+
24
+ protected
25
+ def start_server
26
+ raise NotImplementedError.new("this is abstract!")
27
+ end
28
+
29
+ def stop_server
30
+ raise NotImplementedError.new("this is abstract!")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,95 @@
1
+ module Seleniumrc
2
+ # The Test Case class that runs your Selenium tests.
3
+ # You are able to use all methods provided by Selenium::SeleneseInterpreter with some additions.
4
+ class SeleniumTestCase < Test::Unit::TestCase
5
+ module ClassMethods
6
+ def subclasses
7
+ @subclasses ||= []
8
+ end
9
+
10
+ def inherited(subclass)
11
+ # keep a list of all subclasses on the fly, so we can run them all later from the Runner
12
+ subclasses << subclass unless subclasses.include?(subclass)
13
+ super
14
+ end
15
+
16
+ def all_subclasses_as_suite(configuration)
17
+ suite = Test::Unit::TestSuite.new
18
+ all_descendant_classes.each do |test_case_class|
19
+ test_case_class.suite.tests.each do |test_case|
20
+ test_case.configuration = configuration
21
+ suite << test_case
22
+ end
23
+ end
24
+ suite
25
+ end
26
+
27
+ def all_descendant_classes
28
+ extract_subclasses(self)
29
+ end
30
+
31
+ def extract_subclasses(parent_class)
32
+ classes = []
33
+ parent_class.subclasses.each do |subclass|
34
+ classes << subclass
35
+ classes.push(*extract_subclasses(subclass))
36
+ end
37
+ classes
38
+ end
39
+
40
+ unless Object.const_defined?(:RAILS_ROOT)
41
+ attr_accessor :use_transactional_fixtures, :use_instantiated_fixtures
42
+ end
43
+ end
44
+ extend ClassMethods
45
+
46
+ self.use_transactional_fixtures = false
47
+ self.use_instantiated_fixtures = true
48
+
49
+ include SeleniumDsl
50
+ def setup
51
+ # set "setup_once" to true
52
+ # to prevent fixtures from being re-loaded and data deleted from the DB.
53
+ # this is handy if you want to generate a DB full of sample data
54
+ # from the tests. Make sure none of your selenium tests manually
55
+ # reset data!
56
+ #TODO: make this configurable
57
+ setup_once = false
58
+
59
+ raise "Cannot use transactional fixtures if ActiveRecord concurrency is turned on (which is required for Selenium tests to work)." if self.class.use_transactional_fixtures
60
+ # @beginning = time_class.now
61
+ unless setup_once
62
+ ActiveRecord::Base.connection.update('SET FOREIGN_KEY_CHECKS = 0')
63
+ super
64
+ ActiveRecord::Base.connection.update('SET FOREIGN_KEY_CHECKS = 1')
65
+ else
66
+ unless InstanceMethods.const_defined?("ALREADY_SETUP_ONCE")
67
+ super
68
+ InstanceMethods.const_set("ALREADY_SETUP_ONCE", true)
69
+ end
70
+ end
71
+ # puts self.class.to_s + "#" + @method_name
72
+ @selenium = configuration.selenese_interpreter
73
+ end
74
+
75
+ def teardown
76
+ @selenium.stop if should_stop_selenese_interpreter?
77
+ super
78
+ if @beginning
79
+ duration = (time_class.now - @beginning).to_f
80
+ puts "#{duration} seconds"
81
+ end
82
+ end
83
+
84
+ def selenium_test_case
85
+ @selenium_test_case ||= SeleniumTestCase
86
+ end
87
+
88
+ def run(result, &block)
89
+ return if @method_name.nil? || @method_name.to_sym == :default_test
90
+ super
91
+ end
92
+ end
93
+ end
94
+
95
+ SeleniumTestCase = Seleniumrc::SeleniumTestCase
@@ -0,0 +1,21 @@
1
+
2
+ module Seleniumrc
3
+ module Tasks
4
+ class SeleniumTestTask
5
+ attr_reader :rails_env, :rails_root
6
+
7
+ def initialize(rails_env = RAILS_ENV, rails_root = RAILS_ROOT)
8
+ @rails_env = rails_env
9
+ @rails_root = rails_root
10
+ end
11
+
12
+ def invoke(suite_relative_path = "test/selenium/selenium_suite")
13
+ rails_env.replace "test"
14
+ require "#{rails_root}/" + suite_relative_path
15
+
16
+ passed = Test::Unit::AutoRunner.run
17
+ raise "Test failures" unless passed
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ module Seleniumrc
2
+ module WaitFor
3
+ Context = Struct.new(:message)
4
+ # Poll continuously for the return value of the block to be true. You can use this to assert that a client side
5
+ # or server side condition was met.
6
+ # wait_for do
7
+ # User.count == 5
8
+ # end
9
+ def wait_for(params={})
10
+ timeout = params[:timeout] || default_wait_for_time
11
+ message = params[:message] || "Timeout exceeded"
12
+ context = Context.new(message)
13
+ begin_time = time_class.now
14
+ while (time_class.now - begin_time) < timeout
15
+ return if yield(context)
16
+ sleep 0.25
17
+ end
18
+ flunk(context.message + " (after #{timeout} sec)")
19
+ true
20
+ end
21
+
22
+ def default_wait_for_time
23
+ 5
24
+ end
25
+
26
+ def time_class
27
+ Time
28
+ end
29
+
30
+ def wait_for_page_to_load(timeout=default_timeout)
31
+ selenium.wait_for_page_to_load timeout
32
+ if selenium.get_title.include?("Exception caught")
33
+ flunk "We got a new page, but it was an application exception page.\n\n" + get_html_source
34
+ end
35
+ end
36
+
37
+ # The default Selenium Core client side timeout.
38
+ def default_timeout
39
+ @default_timeout ||= 20000
40
+ end
41
+ attr_writer :default_timeout
42
+
43
+ def flunk(message)
44
+ raise Test::Unit::AssertionFailedError, message
45
+ end
46
+ end
47
+ end