seleniumrc 0.0.1

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