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
data/CHANGES ADDED
@@ -0,0 +1,2 @@
1
+ 0.0.1
2
+ * Initial Release. More documentation to come.
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+ require "rake"
2
+ require 'rake/gempackagetask'
3
+ require 'rake/contrib/rubyforgepublisher'
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+ require 'rake/rdoctask'
7
+
8
+ desc "Runs the Rspec suite"
9
+ task(:default) do
10
+ run_suite
11
+ end
12
+
13
+ desc "Runs the Rspec suite"
14
+ task(:spec) do
15
+ run_suite
16
+ end
17
+
18
+ desc "Copies the trunk to a tag with the name of the current release"
19
+ task(:tag_release) do
20
+ tag_release
21
+ end
22
+
23
+ def run_suite
24
+ dir = File.dirname(__FILE__)
25
+ system("ruby #{dir}/spec/spec_suite.rb") || raise("Example Suite failed")
26
+ end
27
+
28
+ PKG_NAME = "seleniumrc"
29
+ PKG_VERSION = "0.0.1"
30
+ PKG_FILES = FileList[
31
+ '[A-Z]*',
32
+ '*.rb',
33
+ 'lib/**/*.rb',
34
+ 'spec/**/*.rb'
35
+ ]
36
+
37
+ spec = Gem::Specification.new do |s|
38
+ s.name = PKG_NAME
39
+ s.version = PKG_VERSION
40
+ s.summary = "Selenium RC with enhanced assertions that also runs your rails app."
41
+ s.test_files = "examples/example_suite.rb"
42
+ s.description = s.summary
43
+
44
+ s.files = PKG_FILES.to_a
45
+ s.require_path = 'lib'
46
+
47
+ s.has_rdoc = true
48
+ s.extra_rdoc_files = [ "README", "CHANGES" ]
49
+ s.rdoc_options = ["--main", "README", "--inline-source", "--line-numbers"]
50
+
51
+ s.test_files = Dir.glob('spec/*_spec.rb')
52
+ s.require_path = 'lib'
53
+ s.autorequire = 'rr'
54
+ s.author = "Pivotal Labs"
55
+ s.email = "opensource@pivotallabs.com"
56
+ s.homepage = "http://pivotallabs.com"
57
+ s.rubyforge_project = "pivotalrb"
58
+ end
59
+
60
+ Rake::GemPackageTask.new(spec) do |pkg|
61
+ pkg.need_zip = true
62
+ pkg.need_tar = true
63
+ end
64
+
65
+ def tag_release
66
+ dashed_version = PKG_VERSION.gsub('.', '-')
67
+ `svn cp svn+ssh://rubyforge.org/var/svn/pivotalrb/seleniumrc/trunk svn+ssh://rubyforge.org/var/svn/pivotalrb/seleniumrc/tags/REL-#{dashed_version} -m 'Version #{PKG_VERSION}'`
68
+ end
@@ -0,0 +1,43 @@
1
+ module Seleniumrc
2
+ class AppServerChecker
3
+
4
+ attr_accessor :tcp_socket_class
5
+ attr_accessor :context
6
+
7
+ def is_server_started?
8
+ @host = @context.internal_app_server_host
9
+ @port = @context.internal_app_server_port
10
+ if (@host == '0.0.0.0')
11
+ @host = '127.0.0.1'
12
+ end
13
+ if (@host == '127.0.0.1' || @host == 'localhost')
14
+ return is_started?
15
+ end
16
+
17
+ # must be remote
18
+ return true if @context.verify_remote_app_server_is_running == false
19
+
20
+ # should be verified
21
+ return true if is_started?
22
+ # is not started but should be verified, so throw exception
23
+ error_message = "The 'verify_remote_app_server_is_running flag' was true, but the server was not accessible at '#{@host}:#{@port}'. " \
24
+ "You should either start the server, or set the environment variable 'verify_remote_app_server_is_running' to false " \
25
+ "(IF you are SURE that the server is actually running, but just not accessible from this box)."
26
+ raise RuntimeError.new(error_message)
27
+ end
28
+
29
+ def is_started?
30
+ begin
31
+ @socket = @tcp_socket_class.new(@host, @port)
32
+ rescue SocketError
33
+ return false
34
+ rescue Errno::EBADF
35
+ return false
36
+ rescue Errno::ECONNREFUSED
37
+ return false
38
+ end
39
+ @socket.close unless @socket.nil?
40
+ return true
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,186 @@
1
+ module Seleniumrc
2
+ module SeleniumDsl
3
+ # The SeleniumConfiguration object.
4
+ def configuration
5
+ @configuration ||= SeleniumConfiguration.instance
6
+ end
7
+ attr_writer :configuration
8
+ include WaitFor
9
+ include TestUnitDsl
10
+
11
+ def type(locator,value)
12
+ element(locator).is_present
13
+ selenium.type(locator,value)
14
+ end
15
+
16
+ def click(locator)
17
+ element(locator).is_present
18
+ selenium.click(locator)
19
+ end
20
+
21
+ alias_method :wait_for_and_click, :click
22
+
23
+ # Download a file from the Application Server
24
+ def download(path)
25
+ uri = URI.parse(configuration.browser_url + path)
26
+ puts "downloading #{uri.to_s}"
27
+ Net::HTTP.get(uri)
28
+ end
29
+
30
+ def select(select_locator,option_locator)
31
+ element(select_locator).is_present
32
+ selenium.select(select_locator,option_locator)
33
+ end
34
+
35
+ # Reload the current page that the browser is on.
36
+ def reload
37
+ selenium.get_eval("selenium.browserbot.getCurrentWindow().location.reload()")
38
+ end
39
+
40
+ def method_missing(name, *args)
41
+ return selenium.send(name, *args)
42
+ end
43
+
44
+
45
+ #--------- Commands
46
+
47
+ # Open a location and wait for the page to load.
48
+ def open_and_wait(url)
49
+ page.open_and_wait url
50
+ end
51
+
52
+ # Click a link and wait for the page to load.
53
+ def click_and_wait(locator, wait_for = default_timeout)
54
+ selenium.click locator
55
+ wait_for_page_to_load(wait_for)
56
+ end
57
+ alias_method :click_and_wait_for_page_to_load, :click_and_wait
58
+
59
+ # Click the back button and wait for the page to load.
60
+ def go_back_and_wait
61
+ selenium.go_back
62
+ wait_for_page_to_load
63
+ end
64
+
65
+ # Open the home page of the Application and wait for the page to load.
66
+ def open_home_page
67
+ selenium.open(configuration.browser_url)
68
+ wait_for_page_to_load
69
+ end
70
+
71
+ # Get the inner html of the located element.
72
+ def get_inner_html(locator)
73
+ element(locator).inner_html
74
+ end
75
+
76
+ # Does the element at locator contain the text?
77
+ def element_contains_text(locator, text)
78
+ selenium.is_element_present(locator) && get_inner_html(locator).include?(text)
79
+ end
80
+
81
+ # Does the element at locator not contain the text?
82
+ def element_does_not_contain_text(locator, text)
83
+ return true unless selenium.is_element_present(locator)
84
+ return !get_inner_html(locator).include?(text)
85
+ end
86
+
87
+ # Does locator element have text fragments in a certain order?
88
+ def is_text_in_order(locator, *text_fragments)
89
+ container = Hpricot(get_text(locator))
90
+
91
+ everything_found = true
92
+ wasnt_found_message = "Certain fragments weren't found:\n"
93
+
94
+ everything_in_order = true
95
+ wasnt_in_order_message = "Certain fragments were out of order:\n"
96
+
97
+ text_fragments.inject([-1, nil]) do |old_results, new_fragment|
98
+ old_index = old_results[0]
99
+ old_fragment = old_results[1]
100
+ new_index = container.inner_html.index(new_fragment)
101
+
102
+ unless new_index
103
+ everything_found = false
104
+ wasnt_found_message << "Fragment #{new_fragment} was not found\n"
105
+ end
106
+
107
+ if new_index < old_index
108
+ everything_in_order = false
109
+ wasnt_in_order_message << "Fragment #{new_fragment} out of order:\n"
110
+ wasnt_in_order_message << "\texpected '#{old_fragment}'\n"
111
+ wasnt_in_order_message << "\tto come before '#{new_fragment}'\n"
112
+ end
113
+
114
+ [new_index, new_fragment]
115
+ end
116
+
117
+ wasnt_found_message << "\n\nhtml follows:\n #{container.inner_html}\n"
118
+ wasnt_in_order_message << "\n\nhtml follows:\n #{container.inner_html}\n"
119
+
120
+ unless everything_found && everything_in_order
121
+ yield(everything_found, wasnt_found_message, everything_in_order, wasnt_in_order_message)
122
+ end
123
+ end
124
+ #----- Waiting for conditions
125
+
126
+ def wait_for_page_to_load(timeout=default_timeout)
127
+ selenium.wait_for_page_to_load timeout
128
+ if get_title.include?("Exception caught")
129
+ flunk "We got a new page, but it was an application exception page.\n\n" + get_html_source
130
+ end
131
+ end
132
+
133
+ def wait_for_element_to_contain(locator, text, message=nil, timeout=default_wait_for_time)
134
+ wait_for({:message => message, :timeout => timeout}) {element_contains_text(locator, text)}
135
+ end
136
+ alias_method :wait_for_element_to_contain_text, :wait_for_element_to_contain
137
+
138
+ # Open the log window on the browser. This is useful to diagnose issues with Selenium Core.
139
+ def show_log(log_level = "debug")
140
+ get_eval "LOG.setLogLevelThreshold('#{log_level}')"
141
+ end
142
+
143
+ # Slow down each Selenese step after this method is called.
144
+ def slow_mode
145
+ get_eval "slowMode = true"
146
+ get_eval 'window.document.getElementsByName("FASTMODE")[0].checked = true'
147
+ end
148
+
149
+ # Speeds up each Selenese step to normal speed after this method is called.
150
+ def fast_mode
151
+ get_eval "slowMode = false"
152
+ get_eval 'window.document.getElementsByName("FASTMODE")[0].checked = false'
153
+ end
154
+
155
+ def page
156
+ SeleniumPage.new(@selenium)
157
+ end
158
+
159
+ def element(locator)
160
+ SeleniumElement.new(@selenium, locator)
161
+ end
162
+
163
+ protected
164
+ attr_accessor :selenium
165
+ delegate :open,
166
+ :wait_for_condition,
167
+ :get_select_options,
168
+ :get_selected_id,
169
+ :get_selected_id,
170
+ :get_selected_ids,
171
+ :get_selected_index,
172
+ :get_selected_indexes,
173
+ :get_selected_label,
174
+ :get_selected_labels,
175
+ :get_selected_value,
176
+ :get_selected_values,
177
+ :get_body_text,
178
+ :get_html_source,
179
+ :to => :selenium
180
+
181
+ def should_stop_selenese_interpreter?
182
+ return false unless configuration.test_browser_mode?
183
+ configuration.stop_selenese_interpreter?(passed?)
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,95 @@
1
+ module Seleniumrc
2
+ module TestUnitDsl
3
+ #------ Assertions and Conditions
4
+ # Assert and wait for the page title.
5
+ def assert_title(title, params={})
6
+ page.has_title(title, params)
7
+ end
8
+
9
+ # Assert and wait for page to contain text.
10
+ def assert_text_present(pattern, options = {})
11
+ page.is_text_present(pattern, options)
12
+ end
13
+
14
+ # Assert and wait for page to not contain text.
15
+ def assert_text_not_present(pattern, options = {})
16
+ page.is_text_not_present(pattern, options)
17
+ end
18
+
19
+ # Assert and wait for the locator element to have value.
20
+ def assert_value(locator, value)
21
+ element(locator).has_value(value)
22
+ end
23
+
24
+ # Assert and wait for the locator attribute to have a value.
25
+ def assert_attribute(locator, value)
26
+ element(locator).has_attribute(value)
27
+ end
28
+
29
+ # Assert and wait for locator select element to have value option selected.
30
+ def assert_selected(locator, value)
31
+ element(locator).has_selected(value)
32
+ end
33
+
34
+ # Assert and wait for locator check box to be checked.
35
+ def assert_checked(locator)
36
+ element(locator).is_checked
37
+ end
38
+
39
+ # Assert and wait for locator check box to not be checked.
40
+ def assert_not_checked(locator)
41
+ element(locator).is_not_checked
42
+ end
43
+
44
+ # Assert and wait for locator element to have text equal to passed in text.
45
+ def assert_text(locator, text, options={})
46
+ element(locator).has_text(text, options)
47
+ end
48
+
49
+ # Assert and wait for locator element to be present.
50
+ def assert_element_present(locator, params = {})
51
+ element(locator).is_present(params)
52
+ end
53
+
54
+ # Assert and wait for locator element to not be present.
55
+ def assert_element_not_present(locator, params = {})
56
+ element(locator).is_not_present(params)
57
+ end
58
+
59
+ # Assert and wait for locator element to contain text.
60
+ def assert_element_contains(locator, text, options = {})
61
+ element(locator).contains_text(text, options)
62
+ end
63
+
64
+ # Assert and wait for locator element to not contain text.
65
+ def assert_element_does_not_contain_text(locator, text, options={})
66
+ element(locator).does_not_contain_text(text, options)
67
+ end
68
+ alias_method :assert_element_does_not_contain, :assert_element_does_not_contain_text
69
+ alias_method :wait_for_element_to_not_contain_text, :assert_element_does_not_contain_text
70
+
71
+ # Assert and wait for the element with id next sibling is the element with id expected_sibling_id.
72
+ def assert_next_sibling(locator, expected_sibling_id, options = {})
73
+ element(locator).has_next_sibling(expected_sibling_id, options)
74
+ end
75
+
76
+ # Assert browser url ends with passed in url.
77
+ def assert_location_ends_in(ends_with, options={})
78
+ page.url_ends_with(ends_with, options)
79
+ end
80
+
81
+ # Assert and wait for locator element has text fragments in a certain order.
82
+ def assert_text_in_order(locator, *text_fragments)
83
+ element(locator).has_text_in_order(*text_fragments)
84
+ end
85
+ alias_method :wait_for_text_in_order, :assert_text_in_order
86
+
87
+ def assert_visible(locator, options = {})
88
+ element(locator).is_visible(options)
89
+ end
90
+
91
+ def assert_not_visible(locator, options = {})
92
+ element(locator).is_not_visible(options)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,33 @@
1
+ module Selenium
2
+ class SeleniumDriver
3
+ attr_reader :server_host, :server_port
4
+
5
+ def browser_start_command
6
+ @browserStartCommand
7
+ end
8
+
9
+ def browser_url
10
+ @browserURL
11
+ end
12
+
13
+ def timeout_in_milliseconds
14
+ @timeout
15
+ end
16
+
17
+ alias_method :confirm, :get_confirmation
18
+
19
+ def insert_javascript_file(uri)
20
+ js = <<-USEREXTENSIONS
21
+ var headTag = document.getElementsByTagName("head").item(0);
22
+ var scriptTag = document.createElement("script");
23
+ scriptTag.src = "#{uri}";
24
+ headTag.appendChild( scriptTag );
25
+ USEREXTENSIONS
26
+ get_eval(js)
27
+ end
28
+
29
+ def insert_user_extensions
30
+ insert_javascript_file("/selenium/user-extensions.js")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ class Test::Unit::UI::TestRunnerMediator
2
+ alias_method :initialize_without_seleniumrc, :initialize
3
+ def initialize_with_seleniumrc(suite)
4
+ initialize_without_seleniumrc(suite)
5
+ add_listener(TestCase::STARTED, &method(:start_app_server))
6
+ add_listener(TestCase::FINISHED, &method(:stop_app_server))
7
+ end
8
+ alias_method :initialize, :initialize_with_seleniumrc
9
+
10
+ protected
11
+ def start_app_server
12
+ @app_runner = Seleniumrc::SeleniumConfiguration.instance.create_server_runner
13
+ @app_runner.start
14
+ end
15
+
16
+ def stop_app_server
17
+ @app_runner.stop
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ module Seleniumrc
2
+ class MongrelSeleniumServerRunner < SeleniumServerRunner
3
+ def start
4
+ @configurator = @context.create_mongrel_configurator
5
+ initialize_server(@configurator)
6
+
7
+ @thread_class.start do
8
+ start_server
9
+ end
10
+ @started = true
11
+ end
12
+
13
+ protected
14
+ def start_server
15
+ @configurator.run
16
+ @configurator.log "Mongrel running at #{@context.internal_app_server_host}:#{@context.internal_app_server_port}"
17
+ @configurator.join
18
+ end
19
+
20
+ def initialize_server(config)
21
+ config.listener do |*args|
22
+ mongrel = (args.first || self)
23
+ mongrel.log "Starting Rails in environment #{defaults[:environment]} ..."
24
+ mongrel.uri "/", :handler => mongrel.rails
25
+ mongrel.log "Rails loaded."
26
+
27
+ mongrel.log "Loading any Rails specific GemPlugins"
28
+ mongrel.load_plugins
29
+ end
30
+ end
31
+
32
+ def stop_server
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,78 @@
1
+ module Seleniumrc
2
+ # The configuration interface. This SeleniumConfiguration acts as a singleton to a SeleniumContext.
3
+ # You can access the SeleniumContext object by calling
4
+ # Seleniumrc::SeleniumContext.instance
5
+ class SeleniumConfiguration
6
+ module BrowserMode
7
+ Suite = "suite" unless const_defined? :Suite
8
+ Test = "test" unless const_defined? :Test
9
+ end
10
+ FIREFOX = "firefox" unless const_defined? :FIREFOX
11
+ IEXPLORE = "iexplore" unless const_defined? :IEXPLORE
12
+
13
+ module ClassMethods
14
+ # The instance of the Singleton SeleniumContext. On its initial call, the initial configuration is set.
15
+ # The initial configuration is based on Environment variables and defaults.
16
+ # The environment variables are:
17
+ # * RAILS_ENV - The Rails environment (defaults: test)
18
+ # * selenium_server_host - The host name for the Selenium RC server (default: localhost)
19
+ # * selenium_server_port - The port for the Selenium RC server (default: 4444)
20
+ # * webrick_host - The host name that the application server will start under (default: localhost)
21
+ # * webrick_port - The port that the application server will start under (default: 4000)
22
+ # * app_server_engine - The type of server the application will be run with (webrick or mongrel)
23
+ # * browsers - A comma-delimited list of browsers that will be tested (e.g. firebox,iexplore)
24
+ # * internal_app_server_host - The host name for the Application server that the Browser will access (default: localhost)
25
+ # * internal_app_server_host - The port for the Application server that the Browser will access (default: 4000)
26
+ # * keep_browser_open_on_failure - If there is a failure in the test suite, keep the browser window open (default: true)
27
+ # * verify_remote_app_server_is_running - Raise an exception if the Application Server is not running (default: true)
28
+ def instance
29
+ return @context if @context
30
+ @context = SeleniumContext.new
31
+ @context.env = ENV
32
+
33
+ # TODO: BT - We need to only run one browser per run. Having an array makes the architecture wack.
34
+ @context.browsers = [FIREFOX] # Crack is wack
35
+ @context.failure_has_not_occurred!
36
+ @context.selenium_server_host = "localhost" # address of selenium RC server (java)
37
+ @context.selenium_server_port = 4444
38
+ @context.app_server_engine = :webrick
39
+ @context.internal_app_server_host = "0.0.0.0" # internal address of app server (webrick)
40
+ @context.internal_app_server_port = 4000
41
+ @context.external_app_server_host = "localhost" # external address of app server (webrick)
42
+ @context.external_app_server_port = 4000
43
+ @context.server_engine = :webrick
44
+ @context.keep_browser_open_on_failure = true
45
+ @context.browser_mode = BrowserMode::Suite
46
+ @context.verify_remote_app_server_is_running = true
47
+
48
+ establish_environment
49
+ @context
50
+ end
51
+
52
+ private
53
+ def context
54
+ @context || SeleniumContext.new
55
+ end
56
+
57
+ def establish_environment
58
+ @context.rails_env = env['RAILS_ENV'] if env.include?('RAILS_ENV')
59
+ @context.rails_root = Object.const_get(:RAILS_ROOT) if Object.const_defined?(:RAILS_ROOT)
60
+ ['selenium_server_host', 'selenium_server_port', 'internal_app_server_port', 'internal_app_server_host',
61
+ 'app_server_engine', 'external_app_server_host', 'external_app_server_port'].each do |env_key|
62
+ @context.send(env_key + "=", env[env_key]) if env.include?(env_key)
63
+ end
64
+ ['keep_browser_open_on_failure', 'verify_remote_app_server_is_running'].each do |env_key|
65
+ @context.send(env_key + "=", env[env_key].to_s != false.to_s) if env.include?(env_key)
66
+ end
67
+ ['browsers'].each do |env_key|
68
+ @context.send(env_key + "=", env[env_key].split(",")) if env.include?(env_key)
69
+ end
70
+ end
71
+
72
+ def env
73
+ @context.env
74
+ end
75
+ end
76
+ extend ClassMethods
77
+ end
78
+ end