testcentricity 2.3.13
Sign up to get free protection for your applications and to get access to all the features.
- 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,154 @@
|
|
1
|
+
require 'appium_lib'
|
2
|
+
|
3
|
+
|
4
|
+
module TestCentricity
|
5
|
+
module AppiumConnect
|
6
|
+
|
7
|
+
attr_accessor :running
|
8
|
+
attr_accessor :config_file
|
9
|
+
|
10
|
+
def self.initialize_appium(project_path = nil)
|
11
|
+
Environ.platform = :mobile
|
12
|
+
Environ.driver = :appium
|
13
|
+
Environ.device_type = ENV['DEVICE_TYPE'] if ENV['DEVICE_TYPE']
|
14
|
+
|
15
|
+
@config_file = project_path
|
16
|
+
|
17
|
+
if project_path.nil?
|
18
|
+
Environ.device_name = ENV['APP_DEVICE']
|
19
|
+
Environ.device_os = ENV['APP_PLATFORM_NAME']
|
20
|
+
Environ.device_orientation = ENV['ORIENTATION'] if ENV['ORIENTATION']
|
21
|
+
if ENV['UDID']
|
22
|
+
Environ.device = :device
|
23
|
+
else
|
24
|
+
Environ.device = :simulator
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@running = false
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.start_driver
|
31
|
+
if @config_file.nil?
|
32
|
+
desired_capabilities = {
|
33
|
+
caps: {
|
34
|
+
platformName: ENV['APP_PLATFORM_NAME'],
|
35
|
+
platformVersion: ENV['APP_VERSION'],
|
36
|
+
deviceName: ENV['APP_DEVICE'],
|
37
|
+
automationName: ENV['AUTOMATION_ENGINE']
|
38
|
+
}
|
39
|
+
}
|
40
|
+
capabilities = desired_capabilities[:caps]
|
41
|
+
capabilities[:avd] = ENV['APP_DEVICE'] if ENV['APP_PLATFORM_NAME'].downcase.to_sym == :android
|
42
|
+
capabilities[:orientation] = ENV['ORIENTATION'].upcase if ENV['ORIENTATION']
|
43
|
+
capabilities[:language] = ENV['LANGUAGE'] if ENV['LANGUAGE']
|
44
|
+
capabilities[:locale] = ENV['LOCALE'].gsub('-', '_') if ENV['LOCALE']
|
45
|
+
capabilities[:newCommandTimeout] = ENV['NEW_COMMAND_TIMEOUT'] if ENV['NEW_COMMAND_TIMEOUT']
|
46
|
+
capabilities[:noReset] = ENV['APP_NO_RESET'] if ENV['APP_NO_RESET']
|
47
|
+
capabilities[:fullReset] = ENV['APP_FULL_RESET'] if ENV['APP_FULL_RESET']
|
48
|
+
if ENV['UDID']
|
49
|
+
capabilities[:udid] = ENV['UDID']
|
50
|
+
capabilities[:bundleId] = ENV['BUNDLE_ID'] if ENV['BUNDLE_ID']
|
51
|
+
capabilities[:xcodeOrgId] = ENV['TEAM_ID'] if ENV['TEAM_ID']
|
52
|
+
capabilities[:xcodeSigningId] = ENV['TEAM_NAME'] if ENV['TEAM_NAME']
|
53
|
+
capabilities[:appActivity] = ENV['APP_ACTIVITY'] if ENV['APP_ACTIVITY']
|
54
|
+
capabilities[:appPackage] = ENV['APP_PACKAGE'] if ENV['APP_PACKAGE']
|
55
|
+
end
|
56
|
+
|
57
|
+
if ENV['APP']
|
58
|
+
capabilities[:app] = ENV['APP']
|
59
|
+
else
|
60
|
+
if Environ.is_android?
|
61
|
+
capabilities[:app] = Environ.current.android_apk_path
|
62
|
+
elsif Environ.is_ios?
|
63
|
+
if Environ.is_device?
|
64
|
+
capabilities[:app] = Environ.current.ios_ipa_path
|
65
|
+
else
|
66
|
+
capabilities[:app] = Environ.current.ios_app_path
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
else
|
72
|
+
base_path = 'config'
|
73
|
+
unless File.directory?(File.join(@config_file, base_path))
|
74
|
+
raise 'Could not find appium.txt files in /config folder'
|
75
|
+
end
|
76
|
+
appium_caps = File.join(@config_file, base_path, 'appium.txt')
|
77
|
+
desired_capabilities = Appium.load_appium_txt file: appium_caps
|
78
|
+
end
|
79
|
+
Appium::Driver.new(desired_capabilities).start_driver
|
80
|
+
@running = true
|
81
|
+
Appium.promote_appium_methods TestCentricity::ScreenObject
|
82
|
+
Appium.promote_appium_methods TestCentricity::AppUIElement
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.quit_driver
|
86
|
+
if @running
|
87
|
+
$driver.driver_quit
|
88
|
+
@running = false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.driver
|
93
|
+
$driver
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.take_screenshot(png_save_path)
|
97
|
+
FileUtils.mkdir_p(File.dirname(png_save_path))
|
98
|
+
$driver.driver.save_screenshot(png_save_path)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.install_app(app_path)
|
102
|
+
$driver.install_app(app_path)
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.app_installed?(bundle_id)
|
106
|
+
$driver.app_installed?(bundle_id)
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.launch_app
|
110
|
+
$driver.launch_app
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.close_app
|
114
|
+
$driver.close_app
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.reset_app
|
118
|
+
$driver.reset
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.remove_app(bundle_id)
|
122
|
+
$driver.remove_app(bundle_id)
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.implicit_wait(timeout)
|
126
|
+
$driver.manage.timeouts.implicit_wait = timeout
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.hide_keyboard
|
130
|
+
$driver.hide_keyboard
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.keyboard_shown?
|
134
|
+
$driver.is_keyboard_shown
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.set_geolocation(latitude, longitude, altitude)
|
138
|
+
$driver.set_location(latitude, longitude, altitude)
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.current_context
|
142
|
+
$driver.current_context
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.set_context(context)
|
146
|
+
$driver.set_context(context)
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.available_contexts
|
150
|
+
$driver.available_contexts
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'childprocess'
|
2
|
+
|
3
|
+
#
|
4
|
+
# This class is designed to start and stop the Appium Server process. In order to use it you must have Appium
|
5
|
+
# and node installed on your computer. You can pass parameters to Appium at startup via the constructor.
|
6
|
+
#
|
7
|
+
module TestCentricity
|
8
|
+
class AppiumServer
|
9
|
+
|
10
|
+
attr_accessor :process
|
11
|
+
|
12
|
+
def initialize(params={})
|
13
|
+
@params = params
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Start the Appium Server
|
18
|
+
#
|
19
|
+
def start
|
20
|
+
# terminate any currently running Appium Server
|
21
|
+
if running?
|
22
|
+
system('killall -9 node')
|
23
|
+
puts 'Terminating existing Appium Server'
|
24
|
+
sleep(5)
|
25
|
+
puts 'Appium Server is being restarted'
|
26
|
+
else
|
27
|
+
puts 'Appium Server is being started'
|
28
|
+
end
|
29
|
+
# start new Appium Server
|
30
|
+
@process = ChildProcess.build(*parameters)
|
31
|
+
process.start
|
32
|
+
# wait until confirmation that Appium Server is running
|
33
|
+
wait = Selenium::WebDriver::Wait.new(timeout: 30)
|
34
|
+
wait.until { running? }
|
35
|
+
puts "Appium Server is running - PID = #{process.pid}"
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Check to see if Appium Server is running
|
40
|
+
#
|
41
|
+
def running?
|
42
|
+
response = nil
|
43
|
+
begin
|
44
|
+
response = Net::HTTP.get_response(URI('http://127.0.0.1:4723/wd/hub/sessions'))
|
45
|
+
rescue
|
46
|
+
end
|
47
|
+
response && response.code_type == Net::HTTPOK
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Stop the Appium Server
|
52
|
+
#
|
53
|
+
def stop
|
54
|
+
process.stop
|
55
|
+
puts 'Appium Server has been terminated'
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def parameters
|
61
|
+
cmd = ['appium']
|
62
|
+
@params.each do |key, value|
|
63
|
+
cmd << '--' + key.to_s
|
64
|
+
cmd << value.to_s if not value.nil? and value.size > 0
|
65
|
+
end
|
66
|
+
cmd
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
module TestCentricity
|
4
|
+
class ScreenObject
|
5
|
+
include Test::Unit::Assertions
|
6
|
+
|
7
|
+
attr_reader :strategy, :locator
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
raise "Screen object #{self.class.name} does not have a page_locator trait defined" unless defined?(page_locator)
|
11
|
+
@strategy = page_locator[0].to_sym
|
12
|
+
@locator = page_locator[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.trait(trait_name, &block)
|
16
|
+
define_method(trait_name.to_s, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.element(element_name, strategy, locator)
|
20
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppUIElement.new("#{element_name}", self, "#{strategy}", "#{locator}", :page);end))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.button(element_name, strategy, locator)
|
24
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppButton.new("#{element_name}", self, "#{strategy}", "#{locator}", :page);end))
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.textfield(element_name, strategy, locator)
|
28
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppTextField.new("#{element_name}", self, "#{strategy}", "#{locator}", :page);end))
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.switch(element_name, strategy, locator)
|
32
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppSwitch.new("#{element_name}", self, "#{strategy}", "#{locator}", :page);end))
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.checkbox(element_name, strategy, locator)
|
36
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppCheckBox.new("#{element_name}", self, "#{strategy}", "#{locator}", :page);end))
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.label(element_name, strategy, locator)
|
40
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppLabel.new("#{element_name}", self, "#{strategy}", "#{locator}", :page);end))
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.list(element_name, strategy, locator)
|
44
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppList.new("#{element_name}", self, "#{strategy}", "#{locator}", :page);end))
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.section(section_name, class_name)
|
48
|
+
class_eval(%(def #{section_name};@#{section_name} ||= #{class_name}.new("#{section_name}", self, :page);end))
|
49
|
+
end
|
50
|
+
|
51
|
+
def open_portal
|
52
|
+
environment = Environ.current
|
53
|
+
|
54
|
+
Environ.portal_state = :open
|
55
|
+
end
|
56
|
+
|
57
|
+
def verify_page_exists
|
58
|
+
wait = Selenium::WebDriver::Wait.new(timeout: Environ.default_max_wait_time)
|
59
|
+
wait.until { $driver.find_element(@strategy.to_sym, @locator).displayed? }
|
60
|
+
PageManager.current_page = self
|
61
|
+
rescue
|
62
|
+
raise "Could not find page_locator for screen object '#{self.class.name}' (:#{@strategy}, #{@locator}) after #{Environ.default_max_wait_time} seconds"
|
63
|
+
end
|
64
|
+
|
65
|
+
def navigate_to; end
|
66
|
+
|
67
|
+
def verify_page_ui; end
|
68
|
+
|
69
|
+
def load_page
|
70
|
+
verify_page_exists
|
71
|
+
PageManager.current_page = self
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
def verify_ui_states(ui_states)
|
77
|
+
ui_states.each do |ui_object, object_states|
|
78
|
+
object_states.each do |property, state|
|
79
|
+
|
80
|
+
|
81
|
+
puts "#{ui_object.get_name} - #{property} = #{state}" if ENV['DEBUG']
|
82
|
+
|
83
|
+
|
84
|
+
case property
|
85
|
+
when :exists
|
86
|
+
actual = ui_object.exists?
|
87
|
+
when :enabled
|
88
|
+
actual = ui_object.enabled?
|
89
|
+
when :disabled
|
90
|
+
actual = ui_object.disabled?
|
91
|
+
when :visible
|
92
|
+
actual = ui_object.visible?
|
93
|
+
when :hidden
|
94
|
+
actual = ui_object.hidden?
|
95
|
+
when :checked
|
96
|
+
actual = ui_object.checked?
|
97
|
+
when :selected
|
98
|
+
actual = ui_object.selected?
|
99
|
+
when :value
|
100
|
+
actual = ui_object.get_value
|
101
|
+
when :caption
|
102
|
+
actual = ui_object.get_caption
|
103
|
+
when :name
|
104
|
+
actual = ui_object.tag_name
|
105
|
+
when :placeholder
|
106
|
+
actual = ui_object.get_placeholder
|
107
|
+
when :items
|
108
|
+
actual = ui_object.get_list_items
|
109
|
+
when :itemcount
|
110
|
+
actual = ui_object.get_item_count
|
111
|
+
end
|
112
|
+
|
113
|
+
if state.is_a?(Hash) && state.length == 1
|
114
|
+
error_msg = "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) #{property} property to"
|
115
|
+
state.each do |key, value|
|
116
|
+
case key
|
117
|
+
when :lt, :less_than
|
118
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be less than #{value} but found '#{actual}'") unless actual < value
|
119
|
+
when :lt_eq, :less_than_or_equal
|
120
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be less than or equal to #{value} but found '#{actual}'") unless actual <= value
|
121
|
+
when :gt, :greater_than
|
122
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be greater than #{value} but found '#{actual}'") unless actual > value
|
123
|
+
when :gt_eq, :greater_than_or_equal
|
124
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be greater than or equal to #{value} but found '#{actual}'") unless actual >= value
|
125
|
+
when :starts_with
|
126
|
+
ExceptionQueue.enqueue_exception("#{error_msg} start with '#{value}' but found '#{actual}'") unless actual.start_with?(value)
|
127
|
+
when :ends_with
|
128
|
+
ExceptionQueue.enqueue_exception("#{error_msg} end with '#{value}' but found '#{actual}'") unless actual.end_with?(value)
|
129
|
+
when :contains
|
130
|
+
ExceptionQueue.enqueue_exception("#{error_msg} contain '#{value}' but found '#{actual}'") unless actual.include?(value)
|
131
|
+
when :not_contains, :does_not_contain
|
132
|
+
ExceptionQueue.enqueue_exception("#{error_msg} not contain '#{value}' but found '#{actual}'") if actual.include?(value)
|
133
|
+
when :not_equal
|
134
|
+
ExceptionQueue.enqueue_exception("#{error_msg} not equal '#{value}' but found '#{actual}'") if actual == value
|
135
|
+
when :like, :is_like
|
136
|
+
actual_like = actual.delete("\n")
|
137
|
+
actual_like = actual_like.delete("\r")
|
138
|
+
actual_like = actual_like.delete("\t")
|
139
|
+
actual_like = actual_like.delete(' ')
|
140
|
+
actual_like = actual_like.downcase
|
141
|
+
expected = value.delete("\n")
|
142
|
+
expected = expected.delete("\r")
|
143
|
+
expected = expected.delete("\t")
|
144
|
+
expected = expected.delete(' ')
|
145
|
+
expected = expected.downcase
|
146
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be like '#{value}' but found '#{actual}'") unless actual_like.include?(expected)
|
147
|
+
when :translate
|
148
|
+
expected = I18n.t(value)
|
149
|
+
ExceptionQueue.enqueue_assert_equal(expected, actual, "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) translated #{property} property")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
else
|
153
|
+
ExceptionQueue.enqueue_assert_equal(state, actual, "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) #{property} property")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
ExceptionQueue.post_exceptions
|
158
|
+
end
|
159
|
+
|
160
|
+
def populate_data_fields(data, wait_time = nil)
|
161
|
+
timeout = wait_time.nil? ? 5 : wait_time
|
162
|
+
data.each do |data_field, data_param|
|
163
|
+
unless data_param.blank?
|
164
|
+
# make sure the intended UI target element is visible before trying to set its value
|
165
|
+
data_field.wait_until_visible(timeout)
|
166
|
+
if data_param == '!DELETE'
|
167
|
+
data_field.clear
|
168
|
+
else
|
169
|
+
case data_field.get_object_type
|
170
|
+
when :checkbox
|
171
|
+
data_field.set_checkbox_state(data_param.to_bool)
|
172
|
+
when :textfield
|
173
|
+
data_field.set("#{data_param}\t")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,332 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
module TestCentricity
|
4
|
+
class ScreenSection
|
5
|
+
include Test::Unit::Assertions
|
6
|
+
|
7
|
+
attr_reader :context, :name
|
8
|
+
attr_accessor :locator
|
9
|
+
attr_accessor :parent
|
10
|
+
attr_accessor :strategy
|
11
|
+
attr_accessor :parent_list
|
12
|
+
attr_accessor :list_index
|
13
|
+
|
14
|
+
def initialize(name, parent, context)
|
15
|
+
@name = name
|
16
|
+
@parent = parent
|
17
|
+
@context = context
|
18
|
+
@parent_list = nil
|
19
|
+
@list_index = nil
|
20
|
+
@strategy = nil
|
21
|
+
@locator = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_locator
|
25
|
+
if @locator.nil? && defined?(section_locator)
|
26
|
+
@strategy = section_locator[0]
|
27
|
+
@locator = section_locator[1]
|
28
|
+
end
|
29
|
+
|
30
|
+
locators = []
|
31
|
+
if @context == :section && !@parent.nil?
|
32
|
+
parent_strategy, parent_locator = @parent.get_locator
|
33
|
+
end
|
34
|
+
|
35
|
+
if @parent_list.nil?
|
36
|
+
if parent_strategy == @strategy
|
37
|
+
locators.push([@strategy, @locator])
|
38
|
+
else
|
39
|
+
locators.push([parent_strategy, parent_locator]) unless parent_strategy.nil?
|
40
|
+
locators.push([@strategy, "#{parent_locator}#{@locator}"])
|
41
|
+
end
|
42
|
+
else
|
43
|
+
list_strategy, list_locator = @parent_list.get_locator
|
44
|
+
if parent_strategy == list_strategy
|
45
|
+
list_locator = "#{parent_locator}#{list_locator}"
|
46
|
+
else
|
47
|
+
locators.push([parent_strategy, parent_locator]) unless parent_strategy.nil?
|
48
|
+
end
|
49
|
+
if list_strategy == @strategy
|
50
|
+
obj_locator = "#{list_locator}#{@locator}"
|
51
|
+
else
|
52
|
+
obj_locator = @locator
|
53
|
+
locators.push([list_strategy, list_locator])
|
54
|
+
end
|
55
|
+
unless @list_index.nil?
|
56
|
+
obj_locator = "#{obj_locator}[#{@list_index}]"
|
57
|
+
end
|
58
|
+
locators.push([@strategy, obj_locator])
|
59
|
+
end
|
60
|
+
locators
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def set_list_index(list, index = 1)
|
65
|
+
@parent_list = list unless list.nil?
|
66
|
+
@list_index = index
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_item_count
|
70
|
+
raise 'No parent list defined' if @parent_list.nil?
|
71
|
+
@parent_list.get_item_count
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_list_items
|
75
|
+
items = []
|
76
|
+
(1..get_item_count).each do |item|
|
77
|
+
set_list_index(nil, item)
|
78
|
+
items.push(get_value)
|
79
|
+
end
|
80
|
+
items
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_object_type
|
84
|
+
:section
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_name
|
88
|
+
@name
|
89
|
+
end
|
90
|
+
|
91
|
+
def set_parent(parent)
|
92
|
+
@parent = parent
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
def self.trait(trait_name, &block)
|
97
|
+
define_method(trait_name.to_s, &block)
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.element(element_name, strategy, locator)
|
101
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppUIElement.new("#{element_name}", self, "#{strategy}", "#{locator}", :section);end))
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.button(element_name, strategy, locator)
|
105
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppButton.new("#{element_name}", self, "#{strategy}", "#{locator}", :section);end))
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.textfield(element_name, strategy, locator)
|
109
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppTextField.new("#{element_name}", self, "#{strategy}", "#{locator}", :section);end))
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.switch(element_name, strategy, locator)
|
113
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppSwitch.new("#{element_name}", self, "#{strategy}", "#{locator}", :section);end))
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.checkbox(element_name, strategy, locator)
|
117
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppCheckBox.new("#{element_name}", self, "#{strategy}", "#{locator}", :section);end))
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.label(element_name, strategy, locator)
|
121
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppLabel.new("#{element_name}", self, "#{strategy}", "#{locator}", :section);end))
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.list(element_name, strategy, locator)
|
125
|
+
class_eval(%(def #{element_name};@#{element_name} ||= TestCentricity::AppList.new("#{element_name}", self, "#{strategy}", "#{locator}", :section);end))
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.section(section_name, class_name)
|
129
|
+
class_eval(%(def #{section_name};@#{section_name} ||= #{class_name}.new("#{section_name}", self, :section);end))
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
def click
|
135
|
+
section = find_section
|
136
|
+
raise "Section object '#{get_name}' (#{get_locator}) not found" unless section
|
137
|
+
section.click
|
138
|
+
end
|
139
|
+
|
140
|
+
def tap
|
141
|
+
section = find_section
|
142
|
+
raise "Section object '#{get_name}' (#{get_locator}) not found" unless section
|
143
|
+
x = section.location.x
|
144
|
+
y = section.location.y
|
145
|
+
tap_action = Appium::TouchAction.new.tap(element: section, x: x, y: y)
|
146
|
+
tap_action.perform
|
147
|
+
end
|
148
|
+
|
149
|
+
def double_tap
|
150
|
+
section = find_section
|
151
|
+
raise "Section object '#{get_name}' (#{get_locator}) not found" unless section
|
152
|
+
x = section.location.x
|
153
|
+
y = section.location.y
|
154
|
+
tap_action = Appium::TouchAction.new.double_tap(element: section, x: x, y: y)
|
155
|
+
tap_action.perform
|
156
|
+
end
|
157
|
+
|
158
|
+
def exists?
|
159
|
+
section = find_section
|
160
|
+
section != nil
|
161
|
+
end
|
162
|
+
|
163
|
+
def enabled?
|
164
|
+
section = find_section
|
165
|
+
raise "Section object '#{get_name}' (#{get_locator}) not found" unless section
|
166
|
+
section.enabled?
|
167
|
+
end
|
168
|
+
|
169
|
+
def disabled?
|
170
|
+
section = find_section
|
171
|
+
raise "Section object '#{get_name}' (#{get_locator}) not found" unless section
|
172
|
+
section.enabled?
|
173
|
+
end
|
174
|
+
|
175
|
+
def visible?
|
176
|
+
if exists?
|
177
|
+
section.displayed?
|
178
|
+
else
|
179
|
+
false
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def hidden?
|
184
|
+
!visible?
|
185
|
+
end
|
186
|
+
|
187
|
+
def wait_until_exists(seconds = nil)
|
188
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
189
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
190
|
+
wait.until { exists? }
|
191
|
+
rescue
|
192
|
+
raise "Could not find Section object '#{get_name}' (#{get_locator}) after #{timeout} seconds" unless exists?
|
193
|
+
end
|
194
|
+
|
195
|
+
def wait_until_gone(seconds = nil)
|
196
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
197
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
198
|
+
wait.until { !exists? }
|
199
|
+
rescue
|
200
|
+
raise "Section object '#{get_name}' (#{get_locator}) remained visible after #{timeout} seconds" if exists?
|
201
|
+
end
|
202
|
+
|
203
|
+
def wait_until_visible(seconds = nil)
|
204
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
205
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
206
|
+
wait.until { visible? }
|
207
|
+
rescue
|
208
|
+
raise "Could not find Section object '#{get_name}' (#{get_locator}) after #{timeout} seconds" unless visible?
|
209
|
+
end
|
210
|
+
|
211
|
+
def wait_until_hidden(seconds = nil)
|
212
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
213
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
214
|
+
wait.until { hidden? }
|
215
|
+
rescue
|
216
|
+
raise "Section object '#{get_name}' (#{get_locator}) remained visible after #{timeout} seconds" if visible?
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
def verify_ui_states(ui_states)
|
221
|
+
ui_states.each do |ui_object, object_states|
|
222
|
+
object_states.each do |property, state|
|
223
|
+
|
224
|
+
|
225
|
+
puts "#{ui_object.get_name} - #{property} = #{state}" if ENV['DEBUG']
|
226
|
+
|
227
|
+
|
228
|
+
case property
|
229
|
+
when :exists
|
230
|
+
actual = ui_object.exists?
|
231
|
+
when :enabled
|
232
|
+
actual = ui_object.enabled?
|
233
|
+
when :disabled
|
234
|
+
actual = ui_object.disabled?
|
235
|
+
when :visible
|
236
|
+
actual = ui_object.visible?
|
237
|
+
when :hidden
|
238
|
+
actual = ui_object.hidden?
|
239
|
+
when :checked
|
240
|
+
actual = ui_object.checked?
|
241
|
+
when :selected
|
242
|
+
actual = ui_object.selected?
|
243
|
+
when :value
|
244
|
+
actual = ui_object.get_value
|
245
|
+
when :caption
|
246
|
+
actual = ui_object.get_caption
|
247
|
+
when :name
|
248
|
+
actual = ui_object.tag_name
|
249
|
+
when :placeholder
|
250
|
+
actual = ui_object.get_placeholder
|
251
|
+
when :items
|
252
|
+
actual = ui_object.get_list_items
|
253
|
+
when :itemcount
|
254
|
+
actual = ui_object.get_item_count
|
255
|
+
end
|
256
|
+
|
257
|
+
if state.is_a?(Hash) && state.length == 1
|
258
|
+
error_msg = "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) #{property} property to"
|
259
|
+
state.each do |key, value|
|
260
|
+
case key
|
261
|
+
when :lt, :less_than
|
262
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be less than #{value} but found '#{actual}'") unless actual < value
|
263
|
+
when :lt_eq, :less_than_or_equal
|
264
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be less than or equal to #{value} but found '#{actual}'") unless actual <= value
|
265
|
+
when :gt, :greater_than
|
266
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be greater than #{value} but found '#{actual}'") unless actual > value
|
267
|
+
when :gt_eq, :greater_than_or_equal
|
268
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be greater than or equal to #{value} but found '#{actual}'") unless actual >= value
|
269
|
+
when :starts_with
|
270
|
+
ExceptionQueue.enqueue_exception("#{error_msg} start with '#{value}' but found '#{actual}'") unless actual.start_with?(value)
|
271
|
+
when :ends_with
|
272
|
+
ExceptionQueue.enqueue_exception("#{error_msg} end with '#{value}' but found '#{actual}'") unless actual.end_with?(value)
|
273
|
+
when :contains
|
274
|
+
ExceptionQueue.enqueue_exception("#{error_msg} contain '#{value}' but found '#{actual}'") unless actual.include?(value)
|
275
|
+
when :not_contains, :does_not_contain
|
276
|
+
ExceptionQueue.enqueue_exception("#{error_msg} not contain '#{value}' but found '#{actual}'") if actual.include?(value)
|
277
|
+
when :not_equal
|
278
|
+
ExceptionQueue.enqueue_exception("#{error_msg} not equal '#{value}' but found '#{actual}'") if actual == value
|
279
|
+
when :like, :is_like
|
280
|
+
actual_like = actual.delete("\n")
|
281
|
+
actual_like = actual_like.delete("\r")
|
282
|
+
actual_like = actual_like.delete("\t")
|
283
|
+
actual_like = actual_like.delete(' ')
|
284
|
+
actual_like = actual_like.downcase
|
285
|
+
expected = value.delete("\n")
|
286
|
+
expected = expected.delete("\r")
|
287
|
+
expected = expected.delete("\t")
|
288
|
+
expected = expected.delete(' ')
|
289
|
+
expected = expected.downcase
|
290
|
+
ExceptionQueue.enqueue_exception("#{error_msg} be like '#{value}' but found '#{actual}'") unless actual_like.include?(expected)
|
291
|
+
when :translate
|
292
|
+
expected = I18n.t(value)
|
293
|
+
ExceptionQueue.enqueue_assert_equal(expected, actual, "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) translated #{property} property")
|
294
|
+
end
|
295
|
+
end
|
296
|
+
else
|
297
|
+
ExceptionQueue.enqueue_assert_equal(state, actual, "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) #{property} property")
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
ExceptionQueue.post_exceptions
|
302
|
+
end
|
303
|
+
|
304
|
+
def populate_data_fields(data, wait_time = nil)
|
305
|
+
timeout = wait_time.nil? ? 5 : wait_time
|
306
|
+
data.each do |data_field, data_param|
|
307
|
+
unless data_param.blank?
|
308
|
+
# make sure the intended UI target element is visible before trying to set its value
|
309
|
+
data_field.wait_until_visible(timeout)
|
310
|
+
if data_param == '!DELETE'
|
311
|
+
data_field.clear
|
312
|
+
else
|
313
|
+
case data_field.get_object_type
|
314
|
+
when :checkbox
|
315
|
+
data_field.set_checkbox_state(data_param.to_bool)
|
316
|
+
when :textfield
|
317
|
+
data_field.set("#{data_param}\t")
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
private
|
325
|
+
|
326
|
+
def find_section
|
327
|
+
find_element(@strategy, @locator)
|
328
|
+
rescue
|
329
|
+
nil
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|