polonium 0.1.0
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.
- data/CHANGES +10 -0
- data/README +38 -0
- data/Rakefile +68 -0
- data/lib/polonium.rb +28 -0
- data/lib/polonium/configuration.rb +271 -0
- data/lib/polonium/driver.rb +155 -0
- data/lib/polonium/dsl/selenium_dsl.rb +33 -0
- data/lib/polonium/dsl/test_unit_dsl.rb +58 -0
- data/lib/polonium/element.rb +207 -0
- data/lib/polonium/extensions/module.rb +8 -0
- data/lib/polonium/extensions/testrunnermediator.rb +22 -0
- data/lib/polonium/mongrel_selenium_server_runner.rb +37 -0
- data/lib/polonium/page.rb +84 -0
- data/lib/polonium/selenium_helper.rb +5 -0
- data/lib/polonium/server_runner.rb +33 -0
- data/lib/polonium/tasks/selenium_test_task.rb +21 -0
- data/lib/polonium/test_case.rb +93 -0
- data/lib/polonium/wait_for.rb +40 -0
- data/lib/polonium/webrick_selenium_server_runner.rb +33 -0
- data/spec/polonium/extensions/module_spec.rb +29 -0
- data/spec/polonium/extensions/testrunnermediator_spec.rb +19 -0
- data/spec/polonium/mongrel_selenium_server_runner_spec.rb +35 -0
- data/spec/polonium/selenium_configuration_spec.rb +359 -0
- data/spec/polonium/selenium_driver_spec.rb +104 -0
- data/spec/polonium/selenium_element_spec.rb +551 -0
- data/spec/polonium/selenium_page_spec.rb +249 -0
- data/spec/polonium/selenium_server_runner_spec.rb +42 -0
- data/spec/polonium/selenium_test_case_class_method_spec.rb +41 -0
- data/spec/polonium/selenium_test_case_spec.rb +870 -0
- data/spec/polonium/selenium_test_case_spec_helper.rb +16 -0
- data/spec/polonium/webrick_selenium_server_runner_spec.rb +117 -0
- data/spec/spec_helper.rb +63 -0
- data/spec/spec_suite.rb +6 -0
- metadata +82 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
module Polonium
|
2
|
+
module SeleniumDsl
|
3
|
+
# The Configuration object.
|
4
|
+
def configuration
|
5
|
+
@configuration ||= Configuration.instance
|
6
|
+
end
|
7
|
+
attr_writer :configuration
|
8
|
+
attr_accessor :selenium_driver
|
9
|
+
include WaitFor
|
10
|
+
|
11
|
+
# Download a file from the Application Server
|
12
|
+
def download(path)
|
13
|
+
uri = URI.parse(configuration.browser_url + path)
|
14
|
+
puts "downloading #{uri.to_s}"
|
15
|
+
Net::HTTP.get(uri)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Open the home page of the Application and wait for the page to load.
|
19
|
+
def open_home_page
|
20
|
+
selenium_driver.open(configuration.browser_url)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
Driver.public_instance_methods(false).each do |method_name|
|
25
|
+
delegate method_name, :to => :selenium_driver
|
26
|
+
end
|
27
|
+
|
28
|
+
def should_stop_driver?
|
29
|
+
return false unless configuration.test_browser_mode?
|
30
|
+
configuration.stop_driver?(passed?)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Polonium
|
2
|
+
module TestUnitDsl
|
3
|
+
include SeleniumDsl
|
4
|
+
class << self
|
5
|
+
def page_assertion(name)
|
6
|
+
module_eval(
|
7
|
+
"def assert_#{name}(value, params={})\n" +
|
8
|
+
" page.assert_#{name}(value, params)\n" +
|
9
|
+
"end",
|
10
|
+
__FILE__,
|
11
|
+
__LINE__ - 4
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def element_assertion(name)
|
16
|
+
module_eval(
|
17
|
+
"def assert_#{name}(locator, *args)\n" +
|
18
|
+
" element(locator).assert_#{name}(*args)\n" +
|
19
|
+
"end",
|
20
|
+
__FILE__,
|
21
|
+
__LINE__ - 4
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
page_assertion :title
|
27
|
+
page_assertion :text_present
|
28
|
+
page_assertion :text_not_present
|
29
|
+
page_assertion :location_ends_with
|
30
|
+
deprecate :assert_location_ends_in, :assert_location_ends_with
|
31
|
+
|
32
|
+
element_assertion :value
|
33
|
+
element_assertion :attribute # yes, it's a little weird... in this case element is really an attribute
|
34
|
+
element_assertion :selected
|
35
|
+
element_assertion :checked
|
36
|
+
element_assertion :not_checked
|
37
|
+
element_assertion :text
|
38
|
+
element_assertion :element_present
|
39
|
+
element_assertion :element_not_present
|
40
|
+
element_assertion :next_sibling
|
41
|
+
element_assertion :contains_in_order
|
42
|
+
element_assertion :visible
|
43
|
+
element_assertion :not_visible
|
44
|
+
|
45
|
+
# Assert and wait for locator element to contain text.
|
46
|
+
def assert_element_contains(locator, text, options = {})
|
47
|
+
element(locator).assert_contains(text, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Assert and wait for locator element to not contain text.
|
51
|
+
def assert_element_does_not_contain(locator, text, options={})
|
52
|
+
element(locator).assert_does_not_contain(text, options)
|
53
|
+
end
|
54
|
+
deprecate :assert_element_does_not_contain_text, :assert_element_does_not_contain
|
55
|
+
deprecate :wait_for_element_to_not_contain_text, :assert_element_does_not_contain
|
56
|
+
deprecate :wait_for_text_in_order, :assert_contains_in_order
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
module Polonium
|
2
|
+
class Element
|
3
|
+
include WaitFor
|
4
|
+
attr_reader :driver, :locator
|
5
|
+
|
6
|
+
def initialize(driver, locator)
|
7
|
+
@driver = driver
|
8
|
+
@locator = locator
|
9
|
+
end
|
10
|
+
|
11
|
+
def assert_element_present(params={})
|
12
|
+
driver.wait_for_is_element_present(locator, params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def assert_element_not_present(params={})
|
16
|
+
driver.wait_for_is_element_not_present(locator, params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def assert_value(expected_value)
|
20
|
+
assert_element_present
|
21
|
+
wait_for do |configuration|
|
22
|
+
actual_value = driver.get_value(locator)
|
23
|
+
configuration.message = "Expected '#{locator}' to be '#{expected_value}' but was '#{actual_value}'"
|
24
|
+
has_value? expected_value, actual_value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_attribute(expected_value)
|
29
|
+
assert_element_present
|
30
|
+
wait_for do |configuration|
|
31
|
+
actual = driver.get_attribute(locator) #todo: actual value
|
32
|
+
configuration.message = "Expected attribute '#{locator}' to be '#{expected_value}' but was '#{actual}'"
|
33
|
+
expected_value == actual
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_selected(expected_value)
|
38
|
+
assert_element_present
|
39
|
+
wait_for do |configuration|
|
40
|
+
actual = driver.get_selected_label(locator)
|
41
|
+
configuration.message = "Expected '#{locator}' to be selected with '#{expected_value}' but was '#{actual}"
|
42
|
+
expected_value == actual
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def assert_visible(options={})
|
47
|
+
assert_element_present
|
48
|
+
options = {
|
49
|
+
:message => "Expected '#{locator}' to be visible, but it wasn't"
|
50
|
+
}.merge(options)
|
51
|
+
wait_for(options) do
|
52
|
+
driver.is_visible(locator)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def assert_not_visible(options={})
|
57
|
+
assert_element_present
|
58
|
+
options = {
|
59
|
+
:message => "Expected '#{locator}' to be hidden, but it wasn't"
|
60
|
+
}.merge(options)
|
61
|
+
wait_for(options) do
|
62
|
+
!driver.is_visible(locator)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def assert_checked
|
67
|
+
assert_element_present
|
68
|
+
wait_for(:message => "Expected '#{locator}' to be checked") do
|
69
|
+
driver.is_checked(locator)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def assert_not_checked
|
74
|
+
assert_element_present
|
75
|
+
wait_for(:message => "Expected '#{locator}' to be checked") do
|
76
|
+
!driver.is_checked(locator)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def assert_text(expected_text, options={})
|
81
|
+
assert_element_present
|
82
|
+
wait_for(options) do |configuration|
|
83
|
+
actual = driver.get_text(locator)
|
84
|
+
configuration.message = "Expected text '#{expected_text}' to be full contents of #{locator} but was '#{actual}')"
|
85
|
+
expected_text == actual
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def assert_contains(expected_text, options={})
|
90
|
+
return assert_contains_in_order(*expected_text) if expected_text.is_a? Array
|
91
|
+
assert_element_present
|
92
|
+
options = {
|
93
|
+
:message => "#{locator} should contain #{expected_text}"
|
94
|
+
}.merge(options)
|
95
|
+
wait_for(options) do
|
96
|
+
contains?(expected_text)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def assert_does_not_contain(expected_text, options={})
|
101
|
+
assert_element_present
|
102
|
+
wait_for(options) do
|
103
|
+
!inner_html.include?(expected_text)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def assert_next_sibling(expected_sibling_id, options = {})
|
108
|
+
assert_element_present
|
109
|
+
eval_js = "this.page().findElement('#{locator}').nextSibling.id"
|
110
|
+
wait_for(:message => "id '#{locator}' should be next to '#{expected_sibling_id}'") do
|
111
|
+
actual_sibling_id = driver.get_eval(eval_js)
|
112
|
+
expected_sibling_id == actual_sibling_id
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def assert_contains_in_order(*text_fragments)
|
117
|
+
assert_element_present
|
118
|
+
wait_for do |configuration|
|
119
|
+
success = false
|
120
|
+
|
121
|
+
html = driver.get_text(locator)
|
122
|
+
results = find_text_order_error_fragments(html, text_fragments)
|
123
|
+
fragments_not_found = results[:fragments_not_found]
|
124
|
+
fragments_out_of_order = results[:fragments_out_of_order]
|
125
|
+
|
126
|
+
if !fragments_not_found.empty?
|
127
|
+
configuration.message = "Certain fragments weren't found:\n" <<
|
128
|
+
"#{fragments_not_found.join("\n")}\n" <<
|
129
|
+
"\nhtml follows:\n #{html}\n"
|
130
|
+
elsif !fragments_out_of_order.empty?
|
131
|
+
configuration.message = "Certain fragments were out of order:\n" <<
|
132
|
+
"#{fragments_out_of_order.join("\n")}\n" <<
|
133
|
+
"\nhtml follows:\n #{html}\n"
|
134
|
+
else
|
135
|
+
success = true
|
136
|
+
end
|
137
|
+
|
138
|
+
success
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def is_present?
|
144
|
+
driver.is_element_present(locator)
|
145
|
+
end
|
146
|
+
|
147
|
+
def is_not_present?
|
148
|
+
!driver.is_element_present(locator)
|
149
|
+
end
|
150
|
+
|
151
|
+
def has_value?(expected_value, actual_value=driver.get_value(locator))
|
152
|
+
expected_value == actual_value
|
153
|
+
end
|
154
|
+
|
155
|
+
def inner_html
|
156
|
+
driver.get_inner_html(locator)
|
157
|
+
end
|
158
|
+
|
159
|
+
def contains?(text)
|
160
|
+
inner_html.include?(text)
|
161
|
+
end
|
162
|
+
|
163
|
+
def ==(other)
|
164
|
+
return false unless other.is_a?(Element)
|
165
|
+
return false unless self.driver == other.driver
|
166
|
+
return false unless self.locator == other.locator
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
|
+
protected
|
171
|
+
def method_missing(method_name, *args, &blk)
|
172
|
+
if driver.respond_to?(method_name)
|
173
|
+
driver_args = [locator] + args
|
174
|
+
driver.__send__(method_name, *driver_args, &blk)
|
175
|
+
else
|
176
|
+
super
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def find_text_order_error_fragments(html, text_fragments)
|
181
|
+
fragments_not_found = []
|
182
|
+
fragments_out_of_order = []
|
183
|
+
|
184
|
+
previous_index = -1
|
185
|
+
previous_fragment = ''
|
186
|
+
text_fragments.each do |current_fragment|
|
187
|
+
current_index = html.index(current_fragment)
|
188
|
+
if current_index
|
189
|
+
if current_index < previous_index
|
190
|
+
message = "Fragment #{current_fragment} out of order:\n" <<
|
191
|
+
"\texpected '#{previous_fragment}'\n" <<
|
192
|
+
"\tto come before '#{current_fragment}'\n"
|
193
|
+
fragments_out_of_order << message
|
194
|
+
end
|
195
|
+
else
|
196
|
+
fragments_not_found << "Fragment #{current_fragment} was not found\n"
|
197
|
+
end
|
198
|
+
previous_index = current_index
|
199
|
+
previous_fragment = current_fragment
|
200
|
+
end
|
201
|
+
{
|
202
|
+
:fragments_not_found => fragments_not_found,
|
203
|
+
:fragments_out_of_order => fragments_out_of_order
|
204
|
+
}
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Test::Unit::UI::TestRunnerMediator
|
2
|
+
alias_method :run_suite_without_seleniumrc, :run_suite
|
3
|
+
def run_suite_with_seleniumrc
|
4
|
+
start_app_server
|
5
|
+
result = run_suite_without_seleniumrc
|
6
|
+
stop_app_server(result)
|
7
|
+
result
|
8
|
+
end
|
9
|
+
alias_method :run_suite, :run_suite_with_seleniumrc
|
10
|
+
|
11
|
+
protected
|
12
|
+
def start_app_server
|
13
|
+
@selenium_driver = Polonium::Configuration.instance
|
14
|
+
@app_runner = @selenium_driver.create_server_runner
|
15
|
+
@app_runner.start
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop_app_server(result)
|
19
|
+
@app_runner.stop
|
20
|
+
@selenium_driver.stop_driver_if_necessary(result.passed?)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Polonium
|
2
|
+
class MongrelSeleniumServerRunner < ServerRunner
|
3
|
+
def start
|
4
|
+
mongrel_configurator = configuration.create_mongrel_configurator
|
5
|
+
initialize_server(mongrel_configurator)
|
6
|
+
|
7
|
+
@thread_class.start do
|
8
|
+
start_server(mongrel_configurator)
|
9
|
+
end
|
10
|
+
@started = true
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
def start_server(mongrel_configurator)
|
15
|
+
mongrel_configurator.run
|
16
|
+
mongrel_configurator.log "Mongrel running at #{configuration.internal_app_server_host}:#{configuration.internal_app_server_port}"
|
17
|
+
mongrel_configurator.join
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize_server(config)
|
21
|
+
configuration = self.configuration
|
22
|
+
config.listener do |*args|
|
23
|
+
mongrel = (args.first || self)
|
24
|
+
mongrel.log "Starting Rails in environment #{defaults[:environment]} ..."
|
25
|
+
mongrel.uri "/", :handler => mongrel.rails
|
26
|
+
mongrel.log "Rails loaded."
|
27
|
+
|
28
|
+
mongrel.log "Loading any Rails specific GemPlugins"
|
29
|
+
mongrel.load_plugins
|
30
|
+
configuration.app_server_initialization.call(mongrel)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop_server
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Polonium
|
2
|
+
class Page
|
3
|
+
include WaitFor
|
4
|
+
attr_reader :driver
|
5
|
+
PAGE_LOADED_COMMAND = "this.browserbot.getDocument().body ? true : false"
|
6
|
+
|
7
|
+
def initialize(driver)
|
8
|
+
@driver = driver
|
9
|
+
end
|
10
|
+
|
11
|
+
def open(url)
|
12
|
+
driver.open(url)
|
13
|
+
end
|
14
|
+
alias_method :open_and_wait, :open
|
15
|
+
|
16
|
+
def assert_title(expected_title, params = {})
|
17
|
+
wait_for(params) do |configuration|
|
18
|
+
actual_title = title
|
19
|
+
configuration.message = "Expected title '#{expected_title}' but was '#{actual_title}'"
|
20
|
+
expected_title == actual_title
|
21
|
+
end
|
22
|
+
end
|
23
|
+
def title
|
24
|
+
driver.get_title
|
25
|
+
end
|
26
|
+
|
27
|
+
def assert_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? && driver.is_text_present(expected_text)
|
37
|
+
end
|
38
|
+
|
39
|
+
def assert_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? && !driver.is_text_present(unexpected_text)
|
49
|
+
end
|
50
|
+
|
51
|
+
def page_loaded?
|
52
|
+
driver.get_eval(PAGE_LOADED_COMMAND) == true.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
def assert_location_ends_with(ends_with, options ={})
|
56
|
+
options = {
|
57
|
+
:message => "Expected '#{driver.get_location}' to end with '#{ends_with}'"
|
58
|
+
}.merge(options)
|
59
|
+
wait_for(options) do
|
60
|
+
location_ends_with? ends_with
|
61
|
+
end
|
62
|
+
end
|
63
|
+
def location_ends_with?(ends_with)
|
64
|
+
if driver.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?(Page)
|
73
|
+
self.driver == other.driver
|
74
|
+
end
|
75
|
+
|
76
|
+
def method_missing(method_name, *args, &blk)
|
77
|
+
if driver.respond_to?(method_name)
|
78
|
+
driver.__send__(method_name, *args, &blk)
|
79
|
+
else
|
80
|
+
super
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|