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
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