testcentricity 2.3.13
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +93 -0
- data/LICENSE.txt +28 -0
- data/README.md +1634 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/devices/devices.yml +344 -0
- data/lib/testcentricity.rb +144 -0
- data/lib/testcentricity/app_core/appium_connect_helper.rb +154 -0
- data/lib/testcentricity/app_core/appium_server.rb +69 -0
- data/lib/testcentricity/app_core/screen_objects_helper.rb +180 -0
- data/lib/testcentricity/app_core/screen_sections_helper.rb +332 -0
- data/lib/testcentricity/app_elements/app_element_helper.rb +293 -0
- data/lib/testcentricity/app_elements/button.rb +8 -0
- data/lib/testcentricity/app_elements/checkbox.rb +20 -0
- data/lib/testcentricity/app_elements/label.rb +8 -0
- data/lib/testcentricity/app_elements/list.rb +25 -0
- data/lib/testcentricity/app_elements/switch.rb +20 -0
- data/lib/testcentricity/app_elements/textfield.rb +12 -0
- data/lib/testcentricity/browser_helper.rb +174 -0
- data/lib/testcentricity/data_objects/data_objects_helper.rb +78 -0
- data/lib/testcentricity/data_objects/environment.rb +281 -0
- data/lib/testcentricity/data_objects/excel_helper.rb +242 -0
- data/lib/testcentricity/exception_queue_helper.rb +51 -0
- data/lib/testcentricity/utility_helpers.rb +28 -0
- data/lib/testcentricity/version.rb +3 -0
- data/lib/testcentricity/web_core/drag_drop_helper.rb +15 -0
- data/lib/testcentricity/web_core/page_objects_helper.rb +669 -0
- data/lib/testcentricity/web_core/page_sections_helper.rb +866 -0
- data/lib/testcentricity/web_core/webdriver_helper.rb +579 -0
- data/lib/testcentricity/web_elements/button.rb +8 -0
- data/lib/testcentricity/web_elements/cell_button.rb +8 -0
- data/lib/testcentricity/web_elements/cell_checkbox.rb +38 -0
- data/lib/testcentricity/web_elements/cell_element.rb +69 -0
- data/lib/testcentricity/web_elements/cell_image.rb +8 -0
- data/lib/testcentricity/web_elements/cell_radio.rb +31 -0
- data/lib/testcentricity/web_elements/checkbox.rb +100 -0
- data/lib/testcentricity/web_elements/file_field.rb +45 -0
- data/lib/testcentricity/web_elements/image.rb +34 -0
- data/lib/testcentricity/web_elements/label.rb +8 -0
- data/lib/testcentricity/web_elements/link.rb +8 -0
- data/lib/testcentricity/web_elements/list.rb +73 -0
- data/lib/testcentricity/web_elements/list_button.rb +8 -0
- data/lib/testcentricity/web_elements/list_checkbox.rb +38 -0
- data/lib/testcentricity/web_elements/list_element.rb +61 -0
- data/lib/testcentricity/web_elements/list_radio.rb +31 -0
- data/lib/testcentricity/web_elements/radio.rb +74 -0
- data/lib/testcentricity/web_elements/select_list.rb +197 -0
- data/lib/testcentricity/web_elements/siebel_open_ui_helper.rb +15 -0
- data/lib/testcentricity/web_elements/table.rb +612 -0
- data/lib/testcentricity/web_elements/textfield.rb +114 -0
- data/lib/testcentricity/web_elements/ui_elements_helper.rb +502 -0
- data/lib/testcentricity/world_extensions.rb +26 -0
- data/my_templates/default/method_details/setup.rb +3 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/testcentricity_spec.rb +9 -0
- data/testcentricity.gemspec +47 -0
- metadata +328 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module TestCentricity
|
2
|
+
class ExceptionQueue
|
3
|
+
include Capybara::DSL
|
4
|
+
|
5
|
+
@error_queue
|
6
|
+
|
7
|
+
def self.enqueue_assert_equal(expected, actual, error_message)
|
8
|
+
unless expected == actual
|
9
|
+
enqueue("#{error_message} to be\n '#{expected}'\nbut found\n '#{actual}'")
|
10
|
+
enqueue_screenshot
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.enqueue_assert_not_equal(expected, actual, error_message)
|
15
|
+
unless expected != actual
|
16
|
+
enqueue("#{error_message} to not be equal to '#{expected}'")
|
17
|
+
enqueue_screenshot
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.enqueue_exception(error_message)
|
22
|
+
enqueue(error_message)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.post_exceptions
|
26
|
+
raise @error_queue unless @error_queue.nil?
|
27
|
+
ensure
|
28
|
+
@error_queue = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def self.enqueue(message)
|
34
|
+
@error_queue = "#{@error_queue}#{message}\n\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.enqueue_screenshot
|
38
|
+
timestamp = Time.now.strftime('%Y%m%d%H%M%S')
|
39
|
+
filename = "Screenshot-#{timestamp}"
|
40
|
+
path = File.join Dir.pwd, 'reports/screenshots/', filename
|
41
|
+
if Environ.driver == :appium
|
42
|
+
AppiumConnect.take_screenshot("#{path}.png")
|
43
|
+
else
|
44
|
+
Capybara.save_screenshot "#{path}.png"
|
45
|
+
end
|
46
|
+
puts "Screenshot saved at #{path}.png"
|
47
|
+
screen_shot = { :path => path, :filename => filename }
|
48
|
+
Environ.save_screen_shot(screen_shot)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Object
|
2
|
+
def blank?
|
3
|
+
respond_to?(:empty?) ? empty? : !self
|
4
|
+
end
|
5
|
+
|
6
|
+
def present?
|
7
|
+
!blank?
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
class String
|
13
|
+
def to_bool
|
14
|
+
return true if self == true || self =~ (/(true|t|yes|y|x|1)$/i)
|
15
|
+
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
|
16
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
17
|
+
end
|
18
|
+
|
19
|
+
def string_between(marker1, marker2)
|
20
|
+
self[/#{Regexp.escape(marker1)}(.*?)#{Regexp.escape(marker2)}/m, 1]
|
21
|
+
end
|
22
|
+
|
23
|
+
def format_date_time(date_time_format)
|
24
|
+
return if self.blank?
|
25
|
+
new_date = DateTime.parse(self)
|
26
|
+
new_date.strftime(date_time_format)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CapybaraExtension
|
2
|
+
def drag_by(right_by, down_by)
|
3
|
+
base.drag_by(right_by, down_by)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
module CapybaraSeleniumExtension
|
9
|
+
def drag_by(right_by, down_by)
|
10
|
+
driver.browser.action.drag_and_drop_by(native, right_by, down_by).perform
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
::Capybara::Selenium::Node.send :include, CapybaraSeleniumExtension
|
15
|
+
::Capybara::Node::Element.send :include, CapybaraExtension
|
@@ -0,0 +1,669 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
module TestCentricity
|
4
|
+
class PageObject
|
5
|
+
include Capybara::DSL
|
6
|
+
include Capybara::Node::Matchers
|
7
|
+
include Test::Unit::Assertions
|
8
|
+
|
9
|
+
# Define a trait for this page object.
|
10
|
+
#
|
11
|
+
# @param trait_name [Symbol] name of trait (as a symbol)
|
12
|
+
# @param block [&block] trait value
|
13
|
+
# @example
|
14
|
+
# trait(:page_name) { 'Shopping Basket' }
|
15
|
+
# trait(:page_url) { '/shopping_basket' }
|
16
|
+
# trait(:page_locator) { "//body[@class='shopping_baskets']" }
|
17
|
+
#
|
18
|
+
def self.trait(trait_name, &block)
|
19
|
+
define_method(trait_name.to_s, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Declare and instantiate a single generic UI Element for this page object.
|
23
|
+
#
|
24
|
+
# @param element_name [Symbol] name of UI object (as a symbol)
|
25
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
26
|
+
# @example
|
27
|
+
# element :siebel_view, 'div#_sweview'
|
28
|
+
# element :siebel_busy, "//html[contains(@class, 'siebui-busy')]"
|
29
|
+
#
|
30
|
+
def self.element(element_name, locator)
|
31
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::UIElement.new("#{element_name}", self, "#{locator}", :page);end))
|
32
|
+
end
|
33
|
+
|
34
|
+
# Declare and instantiate a collection of generic UI Elements for this page object.
|
35
|
+
#
|
36
|
+
# @param element_hash [Hash] names of UI objects (as a symbol) and CSS selectors or XPath expressions that uniquely identifies objects
|
37
|
+
# @example
|
38
|
+
# elements profile_item: 'a#profile',
|
39
|
+
# settings_item: 'a#userPreferencesTrigger',
|
40
|
+
# log_out_item: 'a#logout'
|
41
|
+
#
|
42
|
+
def self.elements(element_hash)
|
43
|
+
element_hash.each do |element_name, locator|
|
44
|
+
element(element_name, locator)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Declare and instantiate a single button UI Element for this page object.
|
49
|
+
#
|
50
|
+
# @param element_name [Symbol] name of button object (as a symbol)
|
51
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
52
|
+
# @example
|
53
|
+
# button :checkout_button, 'button.checkout_button'
|
54
|
+
# button :login_button, "//input[@id='submit_button']"
|
55
|
+
#
|
56
|
+
def self.button(element_name, locator)
|
57
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::Button.new("#{element_name}", self, "#{locator}", :page);end))
|
58
|
+
end
|
59
|
+
|
60
|
+
# Declare and instantiate a collection of buttons for this page object.
|
61
|
+
#
|
62
|
+
# @param element_hash [Hash] names of buttons (as a symbol) and CSS selectors or XPath expressions that uniquely identifies buttons
|
63
|
+
# @example
|
64
|
+
# buttons new_account_button: 'button#new-account',
|
65
|
+
# save_button: 'button#save',
|
66
|
+
# cancel_button: 'button#cancel'
|
67
|
+
#
|
68
|
+
def self.buttons(element_hash)
|
69
|
+
element_hash.each do |element_name, locator|
|
70
|
+
button(element_name, locator)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Declare and instantiate a single text field UI Element for this page object.
|
75
|
+
#
|
76
|
+
# @param element_name [Symbol] name of text field object (as a symbol)
|
77
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
78
|
+
# @example
|
79
|
+
# textfield :user_id_field, "//input[@id='UserName']"
|
80
|
+
# textfield :password_field, 'consumer_password'
|
81
|
+
#
|
82
|
+
def self.textfield(element_name, locator)
|
83
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::TextField.new("#{element_name}", self, "#{locator}", :page);end))
|
84
|
+
end
|
85
|
+
|
86
|
+
# Declare and instantiate a collection of text fields for this page object.
|
87
|
+
#
|
88
|
+
# @param element_hash [Hash] names of text fields (as a symbol) and CSS selectors or XPath expressions that uniquely identifies text fields
|
89
|
+
# @example
|
90
|
+
# textfields name_field: 'input#Name',
|
91
|
+
# title_field: 'input#Title',
|
92
|
+
# phone_field: 'input#PhoneNumber',
|
93
|
+
# fax_field: 'input#FaxNumber',
|
94
|
+
# email_field: 'input#Email'
|
95
|
+
#
|
96
|
+
def self.textfields(element_hash)
|
97
|
+
element_hash.each do |element_name, locator|
|
98
|
+
textfield(element_name, locator)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Declare and instantiate a single checkbox UI Element for this page object.
|
103
|
+
#
|
104
|
+
# @param element_name [Symbol] name of checkbox object (as a symbol)
|
105
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
106
|
+
# @param proxy [Symbol] Optional name (as a symbol) of proxy object to receive click actions
|
107
|
+
# @example
|
108
|
+
# checkbox :remember_checkbox, "//input[@id='RememberUser']"
|
109
|
+
# checkbox :accept_terms_checkbox, 'input#accept_terms_conditions', :accept_terms_label
|
110
|
+
#
|
111
|
+
def self.checkbox(element_name, locator, proxy = nil)
|
112
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::CheckBox.new("#{element_name}", self, "#{locator}", :page, #{proxy});end))
|
113
|
+
end
|
114
|
+
|
115
|
+
# Declare and instantiate a collection of checkboxes for this page object.
|
116
|
+
#
|
117
|
+
# @param element_hash [Hash] names of checkboxes (as a symbol) and CSS selectors or XPath expressions that uniquely identifies checkboxes
|
118
|
+
# @example
|
119
|
+
# checkboxes hazmat_certified_check: 'input#hazmatCertified',
|
120
|
+
# epa_certified_check: 'input#epaCertified',
|
121
|
+
# dhs_certified_check: 'input#homelandSecurityCertified',
|
122
|
+
# carb_compliant_check: 'input#carbCompliant'
|
123
|
+
#
|
124
|
+
def self.checkboxes(element_hash)
|
125
|
+
element_hash.each do |element_name, locator|
|
126
|
+
checkbox(element_name, locator)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Declare and instantiate a single radio button UI Element for this page object.
|
131
|
+
#
|
132
|
+
# @param element_name [Symbol] name of radio object (as a symbol)
|
133
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
134
|
+
# @param proxy [Symbol] Optional name (as a symbol) of proxy object to receive click actions
|
135
|
+
# @example
|
136
|
+
# radio :accept_terms_radio, "//input[@id='Accept_Terms']"
|
137
|
+
# radio :decline_terms_radio, '#decline_terms_conditions', :decline_terms_label
|
138
|
+
#
|
139
|
+
def self.radio(element_name, locator, proxy = nil)
|
140
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::Radio.new("#{element_name}", self, "#{locator}", :page, #{proxy});end))
|
141
|
+
end
|
142
|
+
|
143
|
+
# Declare and instantiate a collection of radio buttons for this page object.
|
144
|
+
#
|
145
|
+
# @param element_hash [Hash] names of radio buttons (as a symbol) and CSS selectors or XPath expressions that uniquely identifies radio buttons
|
146
|
+
# @example
|
147
|
+
# radios visa_radio: 'input#payWithVisa',
|
148
|
+
# mastercard_radio: 'input#payWithMastercard',
|
149
|
+
# discover_radio: 'input#payWithDiscover',
|
150
|
+
# amex_radio: 'input#payWithAmEx'
|
151
|
+
#
|
152
|
+
def self.radios(element_hash)
|
153
|
+
element_hash.each do |element_name, locator|
|
154
|
+
radio(element_name, locator)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Declare and instantiate a single label UI Element for this page object.
|
159
|
+
#
|
160
|
+
# @param element_name [Symbol] name of label object (as a symbol)
|
161
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
162
|
+
# @example
|
163
|
+
# label :welcome_label, 'div.Welcome'
|
164
|
+
# label :rollup_price_label, "//div[contains(@id, 'Rollup Item Price')]"
|
165
|
+
#
|
166
|
+
def self.label(element_name, locator)
|
167
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::Label.new("#{element_name}", self, "#{locator}", :page);end))
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.labels(element_hash)
|
171
|
+
element_hash.each do |element_name, locator|
|
172
|
+
label(element_name, locator)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Declare and instantiate a single link UI Element for this page object.
|
177
|
+
#
|
178
|
+
# @param element_name [Symbol] name of link object (as a symbol)
|
179
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
180
|
+
# @example
|
181
|
+
# link :registration_link, 'a.account-nav__link.register'
|
182
|
+
# link :shopping_basket_link, "//a[@href='shopping_basket']"
|
183
|
+
#
|
184
|
+
def self.link(element_name, locator)
|
185
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::Link.new("#{element_name}", self, "#{locator}", :page);end))
|
186
|
+
end
|
187
|
+
|
188
|
+
def self.links(element_hash)
|
189
|
+
element_hash.each do |element_name, locator|
|
190
|
+
link(element_name, locator)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Declare and instantiate a single table UI Element for this page object.
|
195
|
+
#
|
196
|
+
# @param element_name [Symbol] name of table object (as a symbol)
|
197
|
+
# @param locator [String] XPath expression that uniquely identifies object
|
198
|
+
# @example
|
199
|
+
# table :payments_table, "//table[@class='payments_table']"
|
200
|
+
#
|
201
|
+
def self.table(element_name, locator)
|
202
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::Table.new("#{element_name}", self, "#{locator}", :page);end))
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.tables(element_hash)
|
206
|
+
element_hash.each do |element_name, locator|
|
207
|
+
table(element_name, locator)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Declare and instantiate a single select list UI Element for this page object.
|
212
|
+
#
|
213
|
+
# @param element_name [Symbol] name of select list object (as a symbol)
|
214
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
215
|
+
# @example
|
216
|
+
# selectlist :category_selector, 'select#search_form_category_chosen'
|
217
|
+
# selectlist :gender_select, "//select[@id='customer_gender']"
|
218
|
+
#
|
219
|
+
def self.selectlist(element_name, locator)
|
220
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::SelectList.new("#{element_name}", self, "#{locator}", :page);end))
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.selectlists(element_hash)
|
224
|
+
element_hash.each do |element_name, locator|
|
225
|
+
selectlist(element_name, locator)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Declare and instantiate a single list UI Element for this page object.
|
230
|
+
#
|
231
|
+
# @param element_name [Symbol] name of list object (as a symbol)
|
232
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
233
|
+
# @example
|
234
|
+
# list :x_axis_list, 'g.x-axis'
|
235
|
+
#
|
236
|
+
def self.list(element_name, locator)
|
237
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::List.new("#{element_name}", self, "#{locator}", :page);end))
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.lists(element_hash)
|
241
|
+
element_hash.each do |element_name, locator|
|
242
|
+
list(element_name, locator)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Declare and instantiate an single image UI Element for this page object.
|
247
|
+
#
|
248
|
+
# @param element_name [Symbol] name of image object (as a symbol)
|
249
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
250
|
+
# @example
|
251
|
+
# image :basket_item_image, 'div.product_image'
|
252
|
+
# image :corporate_logo_image, "//img[@alt='MyCompany_logo']"
|
253
|
+
#
|
254
|
+
def self.image(element_name, locator)
|
255
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::Image.new("#{element_name}", self, "#{locator}", :page);end))
|
256
|
+
end
|
257
|
+
|
258
|
+
def self.images(element_hash)
|
259
|
+
element_hash.each do |element_name, locator|
|
260
|
+
image(element_name, locator)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Declare and instantiate a single File Field UI Element for this page object.
|
265
|
+
#
|
266
|
+
# @param element_name [Symbol] name of file field object (as a symbol)
|
267
|
+
# @param locator [String] CSS selector or XPath expression that uniquely identifies object
|
268
|
+
# @example
|
269
|
+
# filefield :attach_file, 's_SweFileName'
|
270
|
+
#
|
271
|
+
def self.filefield(element_name, locator)
|
272
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::FileField.new("#{element_name}", self, "#{locator}", :page);end))
|
273
|
+
end
|
274
|
+
|
275
|
+
def self.filefields(element_hash)
|
276
|
+
element_hash.each do |element_name, locator|
|
277
|
+
filefield(element_name, locator)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# Declare and instantiate a cell button in a table column on this page object.
|
282
|
+
#
|
283
|
+
# @param element_name [Symbol] name of cell button object (as a symbol)
|
284
|
+
# @param locator [String] XPath expression that uniquely identifies cell button within row and column of parent table object
|
285
|
+
# @param table [Symbol] Name (as a symbol) of parent table object
|
286
|
+
# @param column [Integer] 1-based index of table column that contains the cell button object
|
287
|
+
# @example
|
288
|
+
# cell_button :show_button, "a[@class='show']", :data_table, 5
|
289
|
+
# cell_button :edit_button, "a[@class='edit']", :data_table, 5
|
290
|
+
#
|
291
|
+
def self.cell_button(element_name, locator, table, column)
|
292
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::CellButton.new("#{element_name}", self, "#{locator}", :page, #{table}, #{column});end))
|
293
|
+
end
|
294
|
+
|
295
|
+
# Declare and instantiate a cell checkbox in a table column on this page object.
|
296
|
+
#
|
297
|
+
# @param element_name [Symbol] name of cell checkbox object (as a symbol)
|
298
|
+
# @param locator [String] XPath expression that uniquely identifies cell checkbox within row and column of parent table object
|
299
|
+
# @param table [Symbol] Name (as a symbol) of parent table object
|
300
|
+
# @param column [Integer] 1-based index of table column that contains the cell checkbox object
|
301
|
+
# @example
|
302
|
+
# cell_checkbox :is_registered_check, "a[@class='registered']", :data_table, 4
|
303
|
+
#
|
304
|
+
def self.cell_checkbox(element_name, locator, table, column, proxy = nil)
|
305
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::CellCheckBox.new("#{element_name}", self, "#{locator}", :page, #{table}, #{column}, #{proxy});end))
|
306
|
+
end
|
307
|
+
|
308
|
+
# Declare and instantiate a cell radio in a table column on this page object.
|
309
|
+
#
|
310
|
+
# @param element_name [Symbol] name of cell radio object (as a symbol)
|
311
|
+
# @param locator [String] XPath expression that uniquely identifies cell radio within row and column of parent table object
|
312
|
+
# @param table [Symbol] Name (as a symbol) of parent table object
|
313
|
+
# @param column [Integer] 1-based index of table column that contains the cell radio object
|
314
|
+
# @example
|
315
|
+
# cell_radio :track_a_radio, "a[@class='track_a']", :data_table, 8
|
316
|
+
#
|
317
|
+
def self.cell_radio(element_name, locator, table, column, proxy = nil)
|
318
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::CellRadio.new("#{element_name}", self, "#{locator}", :page, #{table}, #{column}, #{proxy});end))
|
319
|
+
end
|
320
|
+
|
321
|
+
# Declare and instantiate a cell image in a table column on this page object.
|
322
|
+
#
|
323
|
+
# @param element_name [Symbol] name of cell image object (as a symbol)
|
324
|
+
# @param locator [String] XPath expression that uniquely identifies cell image within row and column of parent table object
|
325
|
+
# @param table [Symbol] Name (as a symbol) of parent table object
|
326
|
+
# @param column [Integer] 1-based index of table column that contains the cell image object
|
327
|
+
# @example
|
328
|
+
# cell_image :ready_icon, "img[@class='ready']", :data_table, 3
|
329
|
+
# cell_image :send_icon, "img[@class='send']", :data_table, 3
|
330
|
+
#
|
331
|
+
def self.cell_image(element_name, locator, table, column)
|
332
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::CellImage.new("#{element_name}", self, "#{locator}", :page, #{table}, #{column});end))
|
333
|
+
end
|
334
|
+
|
335
|
+
# Declare and instantiate a list button in a row of a list object on this page object.
|
336
|
+
#
|
337
|
+
# @param element_name [Symbol] name of list button object (as a symbol)
|
338
|
+
# @param locator [String] XPath expression that uniquely identifies list button within row of parent list object
|
339
|
+
# @param list [Symbol] Name (as a symbol) of parent list object
|
340
|
+
# @example
|
341
|
+
# list_button :delete_button, "a[@class='delete']", :icon_list
|
342
|
+
# list_button :edit_button, "a[@class='edit']", :icon_list
|
343
|
+
#
|
344
|
+
def self.list_button(element_name, locator, list)
|
345
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::ListButton.new("#{element_name}", self, "#{locator}", :page, #{list});end))
|
346
|
+
end
|
347
|
+
|
348
|
+
# Declare and instantiate a list checkbox in a row of a list object on this page object.
|
349
|
+
#
|
350
|
+
# @param element_name [Symbol] name of list checkbox object (as a symbol)
|
351
|
+
# @param locator [String] XPath expression that uniquely identifies list checkbox within row of parent list object
|
352
|
+
# @param list [Symbol] Name (as a symbol) of parent list object
|
353
|
+
# @example
|
354
|
+
# list_checkbox :is_registered_check, "a[@class='registered']", :data_list
|
355
|
+
#
|
356
|
+
def self.list_checkbox(element_name, locator, list, proxy = nil)
|
357
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::ListCheckBox.new("#{element_name}", self, "#{locator}", :page, #{list}, #{proxy});end))
|
358
|
+
end
|
359
|
+
|
360
|
+
# Declare and instantiate a list radio in a row of a list object on this page object.
|
361
|
+
#
|
362
|
+
# @param element_name [Symbol] name of list radio object (as a symbol)
|
363
|
+
# @param locator [String] XPath expression that uniquely identifies list radio within row of parent list object
|
364
|
+
# @param list [Symbol] Name (as a symbol) of parent list object
|
365
|
+
# @example
|
366
|
+
# list_radio :sharing_radio, "a[@class='sharing']", :data_list
|
367
|
+
#
|
368
|
+
def self.list_radio(element_name, locator, list, proxy = nil)
|
369
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::ListRadio.new("#{element_name}", self, "#{locator}", :page, #{list}, #{proxy});end))
|
370
|
+
end
|
371
|
+
|
372
|
+
# Instantiate a single PageSection object for this page object.
|
373
|
+
#
|
374
|
+
# @param section_name [Symbol] name of PageSection object (as a symbol)
|
375
|
+
# @param class_name [String] Class name of PageSection object
|
376
|
+
# @example
|
377
|
+
# section :search_form, SearchForm
|
378
|
+
#
|
379
|
+
def self.section(section_name, class_name, locator = nil)
|
380
|
+
class_eval(%(def #{section_name};@#{section_name} ||= #{class_name}.new("#{section_name}", self, "#{locator}", :page);end))
|
381
|
+
end
|
382
|
+
|
383
|
+
def self.sections(section_hash)
|
384
|
+
section_hash.each do |section_name, class_name|
|
385
|
+
section(section_name, class_name)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def open_portal
|
390
|
+
environment = Environ.current
|
391
|
+
environment.hostname.blank? ?
|
392
|
+
url = "#{environment.base_url}#{environment.append}" :
|
393
|
+
url = "#{environment.hostname}/#{environment.base_url}#{environment.append}"
|
394
|
+
if environment.user_id.blank? || environment.password.blank?
|
395
|
+
visit "#{environment.protocol}://#{url}"
|
396
|
+
else
|
397
|
+
visit "#{environment.protocol}://#{environment.user_id}:#{environment.password}@#{url}"
|
398
|
+
end
|
399
|
+
Environ.portal_state = :open
|
400
|
+
end
|
401
|
+
|
402
|
+
def verify_page_exists
|
403
|
+
raise "Page object #{self.class.name} does not have a page_locator trait defined" unless defined?(page_locator)
|
404
|
+
unless page.has_selector?(page_locator)
|
405
|
+
body_class = find(:xpath, '//body')[:class]
|
406
|
+
error_message = %(
|
407
|
+
Expected page to have selector '#{page_locator}' but found '#{body_class}' instead.
|
408
|
+
Actual URL of page loaded = #{URI.parse(current_url)}.
|
409
|
+
)
|
410
|
+
error_message = "#{error_message}\nExpected URL of page was #{page_url}." if defined?(page_url)
|
411
|
+
raise error_message
|
412
|
+
end
|
413
|
+
PageManager.current_page = self
|
414
|
+
end
|
415
|
+
|
416
|
+
def navigate_to; end
|
417
|
+
|
418
|
+
def verify_page_ui; end
|
419
|
+
|
420
|
+
def load_page
|
421
|
+
return if exists?
|
422
|
+
if defined?(page_url) && !page_url.nil?
|
423
|
+
visit page_url
|
424
|
+
begin
|
425
|
+
page.driver.browser.switch_to.alert.accept
|
426
|
+
rescue => e
|
427
|
+
end unless Environ.browser == :safari || Environ.browser == :ie || Environ.is_device?
|
428
|
+
else
|
429
|
+
navigate_to
|
430
|
+
end
|
431
|
+
verify_page_exists
|
432
|
+
end
|
433
|
+
|
434
|
+
def verify_page_contains(content)
|
435
|
+
raise "Expected page to have content '#{content}'" unless page.has_content?(:visible, content)
|
436
|
+
end
|
437
|
+
|
438
|
+
# Does Page object exists?
|
439
|
+
#
|
440
|
+
# @return [Boolean]
|
441
|
+
# @example
|
442
|
+
# home_page.exists?
|
443
|
+
#
|
444
|
+
def exists?
|
445
|
+
raise "Page object #{self.class.name} does not have a page_locator trait defined" unless defined?(page_locator)
|
446
|
+
saved_wait_time = Capybara.default_max_wait_time
|
447
|
+
Capybara.default_max_wait_time = 0.1
|
448
|
+
tries ||= 2
|
449
|
+
attributes = [:id, :css, :xpath]
|
450
|
+
type = attributes[tries]
|
451
|
+
obj = page.find(type, page_locator)
|
452
|
+
obj != nil
|
453
|
+
rescue
|
454
|
+
Capybara.default_max_wait_time = saved_wait_time
|
455
|
+
retry if (tries -= 1) > 0
|
456
|
+
false
|
457
|
+
ensure
|
458
|
+
Capybara.default_max_wait_time = saved_wait_time
|
459
|
+
end
|
460
|
+
|
461
|
+
# Is current Page object URL secure?
|
462
|
+
#
|
463
|
+
# @return [Boolean]
|
464
|
+
# @example
|
465
|
+
# home_page.secure?
|
466
|
+
#
|
467
|
+
def secure?
|
468
|
+
!current_url.match(/^https/).nil?
|
469
|
+
end
|
470
|
+
|
471
|
+
def verify_ui_states(ui_states)
|
472
|
+
ui_states.each do |ui_object, object_states|
|
473
|
+
object_states.each do |property, state|
|
474
|
+
case property
|
475
|
+
when :class
|
476
|
+
actual = ui_object.get_attribute(:class)
|
477
|
+
when :exists
|
478
|
+
actual = ui_object.exists?
|
479
|
+
when :enabled
|
480
|
+
actual = ui_object.enabled?
|
481
|
+
when :disabled
|
482
|
+
actual = ui_object.disabled?
|
483
|
+
when :visible
|
484
|
+
actual = ui_object.visible?
|
485
|
+
when :hidden
|
486
|
+
actual = ui_object.hidden?
|
487
|
+
when :displayed
|
488
|
+
actual = ui_object.displayed?
|
489
|
+
when :width
|
490
|
+
actual = ui_object.width
|
491
|
+
when :height
|
492
|
+
actual = ui_object.height
|
493
|
+
when :x
|
494
|
+
actual = ui_object.x
|
495
|
+
when :y
|
496
|
+
actual = ui_object.y
|
497
|
+
when :readonly
|
498
|
+
actual = ui_object.read_only?
|
499
|
+
when :checked
|
500
|
+
actual = ui_object.checked?
|
501
|
+
when :selected
|
502
|
+
actual = ui_object.selected?
|
503
|
+
when :value, :caption
|
504
|
+
actual = ui_object.get_value
|
505
|
+
when :maxlength
|
506
|
+
actual = ui_object.get_max_length
|
507
|
+
when :rowcount
|
508
|
+
actual = ui_object.get_row_count
|
509
|
+
when :columncount
|
510
|
+
actual = ui_object.get_column_count
|
511
|
+
when :placeholder
|
512
|
+
actual = ui_object.get_placeholder
|
513
|
+
when :min
|
514
|
+
actual = ui_object.get_min
|
515
|
+
when :max
|
516
|
+
actual = ui_object.get_max
|
517
|
+
when :step
|
518
|
+
actual = ui_object.get_step
|
519
|
+
when :options, :items, :list_items
|
520
|
+
actual = ui_object.get_list_items
|
521
|
+
when :optioncount, :itemcount
|
522
|
+
actual = ui_object.get_item_count
|
523
|
+
when :all_items, :all_list_items
|
524
|
+
actual = ui_object.get_all_list_items
|
525
|
+
when :all_items_count
|
526
|
+
actual = ui_object.get_all_items_count
|
527
|
+
when :column_headers
|
528
|
+
actual = ui_object.get_header_columns
|
529
|
+
when :siebel_options
|
530
|
+
actual = ui_object.get_siebel_options
|
531
|
+
else
|
532
|
+
if property.is_a?(Hash)
|
533
|
+
property.each do |key, value|
|
534
|
+
case key
|
535
|
+
when :cell
|
536
|
+
actual = ui_object.get_table_cell(value[0].to_i, value[1].to_i)
|
537
|
+
when :row
|
538
|
+
actual = ui_object.get_table_row(value.to_i)
|
539
|
+
when :column
|
540
|
+
actual = ui_object.get_table_column(value.to_i)
|
541
|
+
when :item
|
542
|
+
actual = ui_object.get_list_item(value.to_i)
|
543
|
+
when :attribute
|
544
|
+
actual = ui_object.get_attribute(value)
|
545
|
+
when :native_attribute
|
546
|
+
actual = ui_object.get_native_attribute(value)
|
547
|
+
end
|
548
|
+
end
|
549
|
+
else
|
550
|
+
props = property.to_s.split('_')
|
551
|
+
case props[0].to_sym
|
552
|
+
when :cell
|
553
|
+
cell = property.to_s.delete('cell_')
|
554
|
+
cell = cell.split('_')
|
555
|
+
actual = ui_object.get_table_cell(cell[0].to_i, cell[1].to_i)
|
556
|
+
when :row
|
557
|
+
row = property.to_s.delete('row_')
|
558
|
+
actual = ui_object.get_table_row(row.to_i)
|
559
|
+
when :column
|
560
|
+
column = property.to_s.delete('column_')
|
561
|
+
actual = ui_object.get_table_column(column.to_i)
|
562
|
+
when :item
|
563
|
+
item = property.to_s.delete('item_')
|
564
|
+
actual = ui_object.get_list_item(item.to_i)
|
565
|
+
end
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
if state.is_a?(Hash) && state.length == 1
|
570
|
+
error_msg = "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) #{property} property to"
|
571
|
+
state.each do |key, value|
|
572
|
+
case key
|
573
|
+
when :lt, :less_than
|
574
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be less than #{value} but found '#{actual}'") unless actual < value
|
575
|
+
when :lt_eq, :less_than_or_equal
|
576
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be less than or equal to #{value} but found '#{actual}'") unless actual <= value
|
577
|
+
when :gt, :greater_than
|
578
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be greater than #{value} but found '#{actual}'") unless actual > value
|
579
|
+
when :gt_eq, :greater_than_or_equal
|
580
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be greater than or equal to #{value} but found '#{actual}'") unless actual >= value
|
581
|
+
when :starts_with
|
582
|
+
ExceptionQueue.enqueue_exception("#{error_msg} start with '#{value}' but found '#{actual}'") unless actual.start_with?(value)
|
583
|
+
when :ends_with
|
584
|
+
ExceptionQueue.enqueue_exception("#{error_msg} end with '#{value}' but found '#{actual}'") unless actual.end_with?(value)
|
585
|
+
when :contains
|
586
|
+
ExceptionQueue.enqueue_exception("#{error_msg} contain '#{value}' but found '#{actual}'") unless actual.include?(value)
|
587
|
+
when :not_contains, :does_not_contain
|
588
|
+
ExceptionQueue.enqueue_exception("#{error_msg} not contain '#{value}' but found '#{actual}'") if actual.include?(value)
|
589
|
+
when :not_equal
|
590
|
+
ExceptionQueue.enqueue_exception("#{error_msg} not equal '#{value}' but found '#{actual}'") if actual == value
|
591
|
+
when :like, :is_like
|
592
|
+
actual_like = actual.delete("\n")
|
593
|
+
actual_like = actual_like.delete("\r")
|
594
|
+
actual_like = actual_like.delete("\t")
|
595
|
+
actual_like = actual_like.delete(' ')
|
596
|
+
actual_like = actual_like.downcase
|
597
|
+
expected = value.delete("\n")
|
598
|
+
expected = expected.delete("\r")
|
599
|
+
expected = expected.delete("\t")
|
600
|
+
expected = expected.delete(' ')
|
601
|
+
expected = expected.downcase
|
602
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be like '#{value}' but found '#{actual}'") unless actual_like.include?(expected)
|
603
|
+
when :translate
|
604
|
+
expected = I18n.t(value)
|
605
|
+
ExceptionQueue.enqueue_assert_equal(expected, actual, "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) translated #{property} property")
|
606
|
+
end
|
607
|
+
end
|
608
|
+
else
|
609
|
+
ExceptionQueue.enqueue_assert_equal(state, actual, "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) #{property} property")
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
ExceptionQueue.post_exceptions
|
614
|
+
end
|
615
|
+
|
616
|
+
# Populate the specified UI elements on this page with the associated data from a Hash passed as an argument. Data
|
617
|
+
# values must be in the form of a String for textfield and select list controls. For checkbox and radio buttons,
|
618
|
+
# data must either be a Boolean or a String that evaluates to a Boolean value (Yes, No, 1, 0, true, false).
|
619
|
+
#
|
620
|
+
# The optional wait_time parameter is used to specify the time (in seconds) to wait for each UI element to become
|
621
|
+
# visible before entering the associated data value. This option is useful in situations where entering data, or
|
622
|
+
# setting the state of a UI element might cause other UI elements to become visible or active. Specifying a wait_time
|
623
|
+
# value ensures that the subsequent UI elements will be ready to be interacted with as states are changed. If the wait
|
624
|
+
# time is nil, then the wait time will be 5 seconds.
|
625
|
+
#
|
626
|
+
# To delete all text content in a text field, pass !DELETE as the data to be entered.
|
627
|
+
#
|
628
|
+
# @param data [Hash] UI element(s) and associated data to be entered
|
629
|
+
# @param wait_time [Integer] wait time in seconds
|
630
|
+
# @example
|
631
|
+
# field_data = { prefix_select => 'Ms',
|
632
|
+
# first_name_field => 'Priscilla',
|
633
|
+
# last_name_field => 'Pumperknickle',
|
634
|
+
# gender_select => 'Female',
|
635
|
+
# dob_field => '11/18/1976',
|
636
|
+
# email_field => 'p.pumperknickle4876@gmail.com',
|
637
|
+
# mailing_list_check => 'Yes'
|
638
|
+
# }
|
639
|
+
# populate_data_fields(field_data)
|
640
|
+
#
|
641
|
+
def populate_data_fields(data, wait_time = nil)
|
642
|
+
timeout = wait_time.nil? ? 5 : wait_time
|
643
|
+
data.each do |data_field, data_param|
|
644
|
+
unless data_param.blank?
|
645
|
+
# make sure the intended UI target element is visible before trying to set its value
|
646
|
+
data_field.wait_until_visible(timeout)
|
647
|
+
if data_param == '!DELETE'
|
648
|
+
data_field.clear
|
649
|
+
else
|
650
|
+
case data_field.get_object_type
|
651
|
+
when :checkbox
|
652
|
+
data_field.set_checkbox_state(data_param.to_bool)
|
653
|
+
when :selectlist
|
654
|
+
data_field.get_siebel_object_type == 'JComboBox' ?
|
655
|
+
data_field.set("#{data_param}\t") :
|
656
|
+
data_field.choose_option(data_param)
|
657
|
+
when :radio
|
658
|
+
data_field.set_selected_state(data_param.to_bool)
|
659
|
+
when :textfield
|
660
|
+
data_field.set("#{data_param}\t")
|
661
|
+
when :section
|
662
|
+
data_field.set(data_param)
|
663
|
+
end
|
664
|
+
end
|
665
|
+
end
|
666
|
+
end
|
667
|
+
end
|
668
|
+
end
|
669
|
+
end
|