automation_object 0.0.4
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/lib/automation_object/blue_print.rb +106 -0
- data/lib/automation_object/blue_print_validation/base_validation.rb +44 -0
- data/lib/automation_object/blue_print_validation/common_methods.rb +106 -0
- data/lib/automation_object/blue_print_validation/element_validation.rb +198 -0
- data/lib/automation_object/blue_print_validation/formatted_errors.rb +41 -0
- data/lib/automation_object/blue_print_validation/hook_validation.rb +393 -0
- data/lib/automation_object/blue_print_validation/key_value_constants.rb +75 -0
- data/lib/automation_object/blue_print_validation/modal_validation.rb +37 -0
- data/lib/automation_object/blue_print_validation/screen_modal_common_methods.rb +119 -0
- data/lib/automation_object/blue_print_validation/screen_validation.rb +21 -0
- data/lib/automation_object/blue_print_validation/validation_object.rb +32 -0
- data/lib/automation_object/driver/anonymous.rb +27 -0
- data/lib/automation_object/driver/driver.rb +281 -0
- data/lib/automation_object/driver/element.rb +243 -0
- data/lib/automation_object/element/element.rb +145 -0
- data/lib/automation_object/element/element_array.rb +12 -0
- data/lib/automation_object/element/element_cell.rb +126 -0
- data/lib/automation_object/element/element_group.rb +33 -0
- data/lib/automation_object/element/element_hash.rb +25 -0
- data/lib/automation_object/element/element_helpers.rb +29 -0
- data/lib/automation_object/element/element_methods.rb +134 -0
- data/lib/automation_object/element/elements_helpers.rb +204 -0
- data/lib/automation_object/framework/events.rb +8 -0
- data/lib/automation_object/framework/helpers.rb +101 -0
- data/lib/automation_object/framework/print_objects.rb +67 -0
- data/lib/automation_object/framework/screen_monitor.rb +55 -0
- data/lib/automation_object/framework/screen_routing.rb +310 -0
- data/lib/automation_object/framework/window_helpers.rb +181 -0
- data/lib/automation_object/framework.rb +408 -0
- data/lib/automation_object/hash.rb +6 -0
- data/lib/automation_object/hook_helpers.rb +27 -0
- data/lib/automation_object/logger.rb +179 -0
- data/lib/automation_object/object.rb +22 -0
- data/lib/automation_object/screen/modal.rb +8 -0
- data/lib/automation_object/screen/screen.rb +209 -0
- data/lib/automation_object/screen/screen_hook_helpers.rb +319 -0
- data/lib/automation_object/screen/screen_modal_helpers.rb +101 -0
- data/lib/automation_object/screen/screen_prompt_helpers.rb +21 -0
- data/lib/automation_object/screen/screen_window_helpers.rb +149 -0
- data/lib/automation_object/version.rb +3 -0
- data/lib/automation_object.rb +80 -0
- metadata +279 -0
@@ -0,0 +1,209 @@
|
|
1
|
+
module AutomationObject
|
2
|
+
class Screen
|
3
|
+
include EventEmitter
|
4
|
+
|
5
|
+
include AutomationObject::ScreenWindowHelpers
|
6
|
+
include AutomationObject::ScreenHookHelpers
|
7
|
+
include AutomationObject::ScreenPromptHelpers
|
8
|
+
include AutomationObject::ScreenModalHelpers
|
9
|
+
|
10
|
+
attr_accessor :framework_object, :driver_object,
|
11
|
+
:configuration,
|
12
|
+
:framework_location,
|
13
|
+
:screen_name,
|
14
|
+
:active_modal,
|
15
|
+
:added_elements,
|
16
|
+
:element_storage,
|
17
|
+
:window_handle
|
18
|
+
|
19
|
+
def initialize(params)
|
20
|
+
self.added_elements = Array.new
|
21
|
+
self.element_storage = Hash.new
|
22
|
+
self.window_handle = nil
|
23
|
+
|
24
|
+
#Set params to properties
|
25
|
+
self.framework_object = params[:framework_object] || raise(ArgumentError, 'framework_object is required in params')
|
26
|
+
self.driver_object = params[:driver_object] || raise(ArgumentError, 'driver_object is required in params')
|
27
|
+
#Clone configuration, this will allow edit/deletes on different levels
|
28
|
+
params[:blue_prints] = Hash.new unless params[:blue_prints].class == Hash #Allow empty screen configs
|
29
|
+
self.configuration = params[:blue_prints].clone || raise(ArgumentError, 'configuration is required in params')
|
30
|
+
|
31
|
+
self.screen_name = params[:screen_name] || raise(ArgumentError, 'screen_name is required in params')
|
32
|
+
|
33
|
+
#Validate properties
|
34
|
+
raise ArgumentError, 'framework_object should be an Framework Object' unless self.framework_object.is_a? Framework
|
35
|
+
raise ArgumentError, 'configuration should be a Hash Object' unless self.configuration.is_a? Hash
|
36
|
+
raise ArgumentError, 'screen_name should be a String Object' unless self.screen_name.is_a? String
|
37
|
+
|
38
|
+
#Framework Location for Debugging
|
39
|
+
self.framework_location = self.screen_name
|
40
|
+
|
41
|
+
#Add Modals
|
42
|
+
self.add_modals(params, self.configuration['modals']) if self.configuration['modals'].is_a?(Hash)
|
43
|
+
|
44
|
+
#Add ElementGroups
|
45
|
+
self.add_element_groups(self.configuration['element_groups']) if self.configuration['element_groups'].is_a?(Hash)
|
46
|
+
|
47
|
+
#Add Elements
|
48
|
+
self.add_elements(self.configuration['elements']) if self.configuration['elements'].is_a?(Hash)
|
49
|
+
end
|
50
|
+
|
51
|
+
def respond_to?(method_symbol, include_private = false)
|
52
|
+
#Translate method in possible internal storage attribute
|
53
|
+
class_symbol = self.translate_string_to_class(method_symbol)
|
54
|
+
instance_symbol = class_symbol.to_s.gsub(/^@/, '')
|
55
|
+
instance_symbol = "@#{instance_symbol}".to_sym
|
56
|
+
|
57
|
+
self.instance_variables.each { |instance_variable|
|
58
|
+
return true if instance_variable == instance_symbol
|
59
|
+
}
|
60
|
+
|
61
|
+
#If not then do the super on the method_symbol
|
62
|
+
super.respond_to?(method_symbol, include_private)
|
63
|
+
end
|
64
|
+
|
65
|
+
def respond_to_element?(method_symbol, include_private = false)
|
66
|
+
element_symbol = self.translate_string_to_class(method_symbol)
|
67
|
+
instance_symbol = element_symbol.to_s.gsub(/^@/, '')
|
68
|
+
instance_symbol = "@#{instance_symbol}".to_sym
|
69
|
+
|
70
|
+
self.instance_variables.each { |instance_variable|
|
71
|
+
if instance_variable == instance_symbol
|
72
|
+
method_class = self.send(element_symbol).class
|
73
|
+
return ([Element, ElementHash, ElementArray, ElementGroup].include?(method_class))
|
74
|
+
end
|
75
|
+
}
|
76
|
+
|
77
|
+
return false
|
78
|
+
end
|
79
|
+
|
80
|
+
def method_missing(method_requested, *args, &block)
|
81
|
+
class_symbol = self.translate_string_to_class(method_requested)
|
82
|
+
|
83
|
+
unless self.respond_to?(class_symbol)
|
84
|
+
raise "Element or Modal (#{method_requested}) is not defined in screen object (#{self.screen_name})"
|
85
|
+
end
|
86
|
+
|
87
|
+
if self.window_in_iframe? and self.respond_to_element?(method_requested)
|
88
|
+
unless self.element_in_current_iframe?(method_requested)
|
89
|
+
self.switch_to_default_content
|
90
|
+
end
|
91
|
+
else
|
92
|
+
self.switch_to_default_content
|
93
|
+
end
|
94
|
+
|
95
|
+
#Preload elements for ElementHash/ElementArray
|
96
|
+
if self.send(class_symbol).class == ElementHash or self.send(class_symbol).class == ElementArray or self.send(class_symbol).class == ElementGroup
|
97
|
+
self.send(class_symbol).load_elements unless self.send(class_symbol).elements_loaded
|
98
|
+
end
|
99
|
+
|
100
|
+
#Load modal if needed
|
101
|
+
if self.send(class_symbol).class == Modal
|
102
|
+
#Skip opening the modal again if it's active
|
103
|
+
return self.send(class_symbol, *args, &block) if self.active_modal == class_symbol
|
104
|
+
|
105
|
+
#Try to make the modal active
|
106
|
+
self.route_to_modal(method_requested)
|
107
|
+
end
|
108
|
+
|
109
|
+
self.send(class_symbol, *args, &block)
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_element_groups(configuration)
|
113
|
+
return unless configuration.is_a?(Hash)
|
114
|
+
|
115
|
+
configuration.each { |group_name, group_configuration|
|
116
|
+
group_class_name = self.translate_string_to_class(group_name)
|
117
|
+
|
118
|
+
setter = "#{group_class_name}="
|
119
|
+
self.class.send(:attr_accessor, group_class_name) unless self.respond_to?(setter)
|
120
|
+
|
121
|
+
group_object_options = {
|
122
|
+
:framework_object => self.framework_object,
|
123
|
+
:screen_object => self,
|
124
|
+
:driver_object => self.driver_object,
|
125
|
+
:blue_prints => group_configuration,
|
126
|
+
:screen_name => self.screen_name,
|
127
|
+
:element_name => group_name
|
128
|
+
}
|
129
|
+
|
130
|
+
send setter, AutomationObject::ElementGroup.new(group_object_options)
|
131
|
+
|
132
|
+
this = self
|
133
|
+
self.send(group_class_name).on :hook do |args|
|
134
|
+
this.hook_listener(args)
|
135
|
+
end
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
def add_elements(configuration)
|
140
|
+
return unless configuration.is_a?(Hash)
|
141
|
+
|
142
|
+
configuration.each { |element_name, element_configuration|
|
143
|
+
element_class_name = self.translate_string_to_class(element_name)
|
144
|
+
|
145
|
+
setter = "#{element_class_name}="
|
146
|
+
self.class.send(:attr_accessor, element_class_name) unless self.respond_to?(setter)
|
147
|
+
|
148
|
+
element_object_options = {
|
149
|
+
:framework_object => self.framework_object,
|
150
|
+
:screen_object => self,
|
151
|
+
:driver_object => self.driver_object,
|
152
|
+
:blue_prints => element_configuration,
|
153
|
+
:screen_name => self.screen_name,
|
154
|
+
:element_name => element_name
|
155
|
+
}
|
156
|
+
|
157
|
+
if element_configuration['multiple'] #Use element hash class for multiples
|
158
|
+
if element_configuration['define_elements_by']
|
159
|
+
send setter, AutomationObject::ElementHash.new(element_object_options)
|
160
|
+
else
|
161
|
+
send setter, AutomationObject::ElementArray.new(element_object_options)
|
162
|
+
end
|
163
|
+
else
|
164
|
+
send setter, AutomationObject::Element.new(element_object_options)
|
165
|
+
end
|
166
|
+
|
167
|
+
this = self
|
168
|
+
self.send(element_class_name).on :hook do |args|
|
169
|
+
this.hook_listener(args)
|
170
|
+
end
|
171
|
+
|
172
|
+
self.added_elements.push(element_class_name)
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
def reset_screen(skip_window_handle = false)
|
177
|
+
AutomationObject::Logger::add('Resetting screen', [self.framework_location])
|
178
|
+
|
179
|
+
self.switch_to_default_content
|
180
|
+
|
181
|
+
#Reset elements
|
182
|
+
self.added_elements.each { |added_element|
|
183
|
+
class_name = self.send(added_element).class.name
|
184
|
+
case class_name
|
185
|
+
when 'AutomationObject::ElementArray', 'AutomationObject::ElementHash', 'AutomationObject::ElementGroup'
|
186
|
+
self.send(added_element).reset_elements
|
187
|
+
when 'AutomationObject::Element'
|
188
|
+
self.send(added_element).reset_element
|
189
|
+
end
|
190
|
+
}
|
191
|
+
|
192
|
+
#Set active modal to nil
|
193
|
+
self.active_modal = nil
|
194
|
+
self.window_handle = nil unless skip_window_handle
|
195
|
+
end
|
196
|
+
|
197
|
+
def get_element_object(element_name)
|
198
|
+
unless self.respond_to?(element_name)
|
199
|
+
raise ArgumentError, "Element (#{element_name}) is not defined in the screen (#{self.screen_name})"
|
200
|
+
end
|
201
|
+
|
202
|
+
unless self.respond_to_element?(element_name)
|
203
|
+
raise ArgumentError, "Expected an element for iframe (#{element_name}) defined in screen (#{self.screen_name})"
|
204
|
+
end
|
205
|
+
|
206
|
+
return self.send(element_name)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
module AutomationObject
|
2
|
+
module ScreenHookHelpers
|
3
|
+
def hook_listener(args)
|
4
|
+
self.hook(args[:configuration], args[:created_window_handle])
|
5
|
+
end
|
6
|
+
|
7
|
+
def before_load
|
8
|
+
AutomationObject::Logger::add('Running Before Load Hook', [self.framework_location])
|
9
|
+
|
10
|
+
return unless self.configuration.has_key?('before_load')
|
11
|
+
unless self.configuration['before_load'].class == Hash
|
12
|
+
raise ArgumentError, "Expecting before_load in screen (#{self.screen_name}) to be a Hash"
|
13
|
+
end
|
14
|
+
|
15
|
+
self.hook(self.configuration['before_load'])
|
16
|
+
end
|
17
|
+
|
18
|
+
def hook(configuration, created_window_handle = false)
|
19
|
+
#Use each, allow for ordering of wait, change_screen in configuration
|
20
|
+
configuration.each { |key, value|
|
21
|
+
case key
|
22
|
+
when 'wait_for_new_window'
|
23
|
+
unless value == true
|
24
|
+
raise ArgumentError, "Only expecting the value of true for wait_for_new_window hook in screen (#{self.screen_name})"
|
25
|
+
end
|
26
|
+
created_window_handle = self.wait_for_new_window unless created_window_handle
|
27
|
+
when 'show_modal'
|
28
|
+
#Add modal to active modal, prevent multiple requests to do the same thing or error out
|
29
|
+
self.activate_modal(self.translate_string_to_class(value))
|
30
|
+
when 'close_window'
|
31
|
+
self.close_window(true) #Don't close the window, already closed
|
32
|
+
when 'change_screen'
|
33
|
+
screen_class_symbol = self.translate_string_to_class(value)
|
34
|
+
self.emit :change_screen, {
|
35
|
+
:screen_class_symbol => screen_class_symbol,
|
36
|
+
:created_window_handle => created_window_handle
|
37
|
+
}
|
38
|
+
when 'possible_screen_changes'
|
39
|
+
unless value.is_a?(Array)
|
40
|
+
raise ArgumentError, "Expected possible_screen_changes to be an Array in screen (#{self.screen_name})"
|
41
|
+
end
|
42
|
+
|
43
|
+
self.emit :possible_screen_changes, {
|
44
|
+
:possible_screens => value,
|
45
|
+
:created_window_handle => created_window_handle
|
46
|
+
}
|
47
|
+
when 'sleep'
|
48
|
+
sleep(value.to_f)
|
49
|
+
when 'wait_for_elements'
|
50
|
+
self.wait_for_elements(value)
|
51
|
+
when 'change_to_previous_screen'
|
52
|
+
self.emit :change_screen, {
|
53
|
+
:screen_class_symbol => self.framework_object.previous_screen_class,
|
54
|
+
:created_window_handle => created_window_handle
|
55
|
+
}
|
56
|
+
when 'close_modal'
|
57
|
+
self.active_modal = nil
|
58
|
+
when 'automatic_onload_modals'
|
59
|
+
self.automatic_onload_modals_hook(value)
|
60
|
+
when 'reset_screen'
|
61
|
+
self.reset_screen(true)
|
62
|
+
else
|
63
|
+
raise ArgumentError, "Hook requested (#{key}) is not implemented, found in screen #{self.screen_name}"
|
64
|
+
end
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def automatic_onload_modals_hook(configuration)
|
69
|
+
return unless configuration.class == Array
|
70
|
+
|
71
|
+
configuration.each { |modal_configuration|
|
72
|
+
next unless modal_configuration.class == Hash
|
73
|
+
next unless modal_configuration.has_key?('modal_name')
|
74
|
+
|
75
|
+
|
76
|
+
if modal_configuration['number_of_checks']
|
77
|
+
number_of_checks = modal_configuration['number_of_checks'].to_i
|
78
|
+
else
|
79
|
+
number_of_checks = 10
|
80
|
+
end
|
81
|
+
|
82
|
+
number_of_checks.times do
|
83
|
+
modal_symbol = self.translate_string_to_class(modal_configuration['modal_name'])
|
84
|
+
if self.send(modal_symbol).live?
|
85
|
+
self.activate_modal(modal_symbol)
|
86
|
+
if modal_configuration['action'] == 'close'
|
87
|
+
self.close_modal(modal_symbol)
|
88
|
+
end
|
89
|
+
break
|
90
|
+
end
|
91
|
+
|
92
|
+
sleep(1)
|
93
|
+
end
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def wait_for_new_window
|
98
|
+
loops = 0
|
99
|
+
max_loops = 30
|
100
|
+
loop_sleep = 1
|
101
|
+
|
102
|
+
stored_window_handles = self.framework_object.current_screen_hash.keys
|
103
|
+
new_window_handle = nil
|
104
|
+
|
105
|
+
until new_window_handle
|
106
|
+
loops = loops + 1
|
107
|
+
if loops > max_loops
|
108
|
+
raise "Max loop breached waiting for new window in screen #{self.screen_name}"
|
109
|
+
end
|
110
|
+
|
111
|
+
window_handles = self.framework_object.get_window_handles.clone
|
112
|
+
window_handle_difference = window_handles.length - stored_window_handles.length
|
113
|
+
|
114
|
+
#Still waiting for new window
|
115
|
+
if window_handle_difference == 0
|
116
|
+
sleep(loop_sleep)
|
117
|
+
next
|
118
|
+
end
|
119
|
+
|
120
|
+
window_handle_difference = window_handles - stored_window_handles
|
121
|
+
|
122
|
+
#Throw error if more than one extra window, not sure which one to use
|
123
|
+
if window_handle_difference.length > 1
|
124
|
+
raise "More than one window was opened on an element action, found in screen #{self.screen_name}"
|
125
|
+
end
|
126
|
+
|
127
|
+
new_window_handle = window_handle_difference.shift
|
128
|
+
break
|
129
|
+
end
|
130
|
+
|
131
|
+
return new_window_handle
|
132
|
+
end
|
133
|
+
|
134
|
+
def wait_for_elements(configuration)
|
135
|
+
unless configuration.class == Array
|
136
|
+
raise ArgumentError, "Expecting Array for wait_for_elements, got #{configuration.class} in screen #{self.screen_name}"
|
137
|
+
end
|
138
|
+
|
139
|
+
AutomationObject::Logger::add('Running Wait for Elements Hook', [self.framework_location])
|
140
|
+
|
141
|
+
configuration.each { |element_configuration|
|
142
|
+
unless element_configuration.class == Hash
|
143
|
+
raise ArgumentError, "Expecting wait_for_elements array to have Hash items got #{element_configuration.class} in screen #{self.screen_name}"
|
144
|
+
end
|
145
|
+
|
146
|
+
unless element_configuration.has_key?('element_name')
|
147
|
+
raise ArgumentError, "Expecting wait_for_elements array item hash to include the 'element_name' key in screen #{self.screen_name}"
|
148
|
+
end
|
149
|
+
|
150
|
+
element_name = element_configuration['element_name']
|
151
|
+
element_class_symbol = self.translate_string_to_class(element_name)
|
152
|
+
#Add exists? to requirements if it doesn't exist
|
153
|
+
unless element_configuration.has_key?('exists?')
|
154
|
+
unless self.send(element_class_symbol).configuration['multiple']
|
155
|
+
element_configuration['exists?'] = true
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
element_requirements = Hash.new
|
160
|
+
#Always put exists? at top if exists? is true
|
161
|
+
if element_configuration['exists?']
|
162
|
+
element_requirements['exists?'] = true
|
163
|
+
element_configuration.each { |key, value|
|
164
|
+
next if key == 'exists?' || key == 'element_name'
|
165
|
+
element_requirements[key] = value
|
166
|
+
}
|
167
|
+
else
|
168
|
+
element_configuration.each { |key, value|
|
169
|
+
next if key == 'element_name'
|
170
|
+
element_requirements[key] = value
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
self.wait_for_element(element_name, element_requirements)
|
175
|
+
}
|
176
|
+
end
|
177
|
+
|
178
|
+
def wait_for_element(element_name, element_requirements)
|
179
|
+
AutomationObject::Logger::add('Running Wait for Element Hook', [self.framework_location])
|
180
|
+
|
181
|
+
element_class_symbol = self.translate_string_to_class(element_name)
|
182
|
+
|
183
|
+
unless self.respond_to?(element_class_symbol)
|
184
|
+
raise "Element class was not defined correctly in screen class (#{self.screen_name}) for element (#{element_name})"
|
185
|
+
end
|
186
|
+
|
187
|
+
element_requirements.each { |requirement, requirement_value|
|
188
|
+
requirement_symbol = requirement.to_s.to_sym
|
189
|
+
|
190
|
+
unless self.send(element_class_symbol).respond_to?(requirement_symbol)
|
191
|
+
raise ArgumentError, "Element (#{element_name}) in screen (#{self.screen_name}) does not have the method (#{requirement_symbol})"
|
192
|
+
end
|
193
|
+
|
194
|
+
requirement_success = false
|
195
|
+
|
196
|
+
loops = 0
|
197
|
+
until requirement_success
|
198
|
+
if self.send(element_class_symbol).is_multiple?
|
199
|
+
self.send(element_class_symbol).load_elements
|
200
|
+
end
|
201
|
+
|
202
|
+
element_value = self.send(element_class_symbol).send(requirement)
|
203
|
+
requirement_success = (element_value == requirement_value)
|
204
|
+
|
205
|
+
AutomationObject::Logger::add("Waiting for element method #{requirement} got: #{element_value}, expecting: #{requirement_value}", [self.framework_location])
|
206
|
+
|
207
|
+
sleep(1) if loops > 0
|
208
|
+
|
209
|
+
if loops > 30
|
210
|
+
raise "Element (#{element_name}) in screen (#{self.screen_name}) breached max wait loops for #{requirement}"
|
211
|
+
end
|
212
|
+
|
213
|
+
loops += 1
|
214
|
+
end
|
215
|
+
}
|
216
|
+
end
|
217
|
+
|
218
|
+
def has_live_configuration?
|
219
|
+
return false unless self.configuration.class == Hash
|
220
|
+
return false unless self.configuration['live?'].class == Hash
|
221
|
+
|
222
|
+
configuration = self.configuration['live?']
|
223
|
+
|
224
|
+
elements_array = Array.new
|
225
|
+
elements_array.push(configuration['element']) if configuration['element'].class == Hash
|
226
|
+
elements_array += configuration['elements'] if configuration['elements'].class == Array
|
227
|
+
|
228
|
+
return false if elements_array.length == 0 #No elements to check
|
229
|
+
|
230
|
+
true
|
231
|
+
end
|
232
|
+
|
233
|
+
def live?
|
234
|
+
AutomationObject::Logger::add('Checking if screen is live?', [self.framework_location])
|
235
|
+
|
236
|
+
#Make sure live? configuration is setup correctly, return false if not
|
237
|
+
return false unless self.has_live_configuration?
|
238
|
+
configuration = self.configuration['live?']
|
239
|
+
|
240
|
+
self.hook(configuration['before']) if configuration['before'].class == Hash
|
241
|
+
|
242
|
+
elements_array = Array.new
|
243
|
+
elements_array.push(configuration['element']) if configuration['element'].class == Hash
|
244
|
+
elements_array += configuration['elements'] if configuration['elements'].class == Array
|
245
|
+
|
246
|
+
elements_array.each { |element_configuration|
|
247
|
+
next unless element_configuration.class == Hash
|
248
|
+
element_requirements = element_configuration.clone
|
249
|
+
|
250
|
+
#Add element_name since is name conflicts with the Element Class method name()
|
251
|
+
if element_requirements['element_name']
|
252
|
+
element_name = element_requirements['element_name']
|
253
|
+
element_requirements.delete('element_name')
|
254
|
+
else
|
255
|
+
element_name = element_requirements['name']
|
256
|
+
element_requirements.delete('name')
|
257
|
+
end
|
258
|
+
|
259
|
+
unless element_name
|
260
|
+
raise "Need to define element name in live? configuration for screen (#{self.screen_name})"
|
261
|
+
end
|
262
|
+
|
263
|
+
element_class_symbol = self.translate_string_to_class(element_name)
|
264
|
+
|
265
|
+
unless element_class_symbol
|
266
|
+
raise "Element class symbol was not defined internally in screen (#{self.screen_name}) for element (#{element_name})"
|
267
|
+
end
|
268
|
+
|
269
|
+
unless self.respond_to?(element_class_symbol)
|
270
|
+
raise "Element class was not defined correctly in screen class (#{self.screen_name}) for element (#{element_name})"
|
271
|
+
end
|
272
|
+
|
273
|
+
#Always put exists? at top if exists? is true
|
274
|
+
#only for AutomationObject::Element
|
275
|
+
|
276
|
+
if self.send(element_class_symbol).class.is_a?(AutomationObject::Element)
|
277
|
+
modified_requirements = Hash.new
|
278
|
+
exists = true
|
279
|
+
exists = element_requirements['exists?'] if element_requirements.has_key?('exists?')
|
280
|
+
|
281
|
+
modified_requirements['exists?'] = exists
|
282
|
+
element_requirements.each { |key, value|
|
283
|
+
next if key == 'exists?'
|
284
|
+
modified_requirements[key] = value
|
285
|
+
}
|
286
|
+
else
|
287
|
+
modified_requirements = element_requirements
|
288
|
+
end
|
289
|
+
|
290
|
+
modified_requirements.each { |requirement, value|
|
291
|
+
requirement_symbol = requirement.to_s.to_sym
|
292
|
+
|
293
|
+
unless self.send(element_class_symbol).respond_to?(requirement_symbol)
|
294
|
+
raise ArgumentError, "Element (#{element_name}) in screen (#{self.screen_name}) does not have the method (#{requirement_symbol})"
|
295
|
+
end
|
296
|
+
|
297
|
+
#If no element error thrown then return live? false
|
298
|
+
# instead of throwing it through the whole program
|
299
|
+
begin
|
300
|
+
success = (self.send(element_name).send(requirement_symbol) == value)
|
301
|
+
rescue Selenium::WebDriver::Error::NoSuchElementError
|
302
|
+
return false
|
303
|
+
end
|
304
|
+
|
305
|
+
unless success
|
306
|
+
self.reset_screen
|
307
|
+
return false
|
308
|
+
end
|
309
|
+
}
|
310
|
+
}
|
311
|
+
|
312
|
+
self.hook(configuration['after']) if configuration['after'].class == Hash
|
313
|
+
|
314
|
+
#Reset screen parts, except window handle
|
315
|
+
self.reset_screen(true)
|
316
|
+
true
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module AutomationObject
|
2
|
+
module ScreenModalHelpers
|
3
|
+
def add_modals(params, configuration)
|
4
|
+
return unless configuration.class == Hash
|
5
|
+
|
6
|
+
configuration.each { |modal_name, modal_configuration|
|
7
|
+
modal_class_symbol = self.translate_string_to_class(modal_name)
|
8
|
+
|
9
|
+
setter = "#{modal_class_symbol}="
|
10
|
+
self.class.send(:attr_accessor, modal_class_symbol) unless respond_to?(setter)
|
11
|
+
|
12
|
+
params[:blue_prints] = modal_configuration
|
13
|
+
send setter, Modal.new(modal_name, params)
|
14
|
+
|
15
|
+
#Add emit listeners and relay from this screen out
|
16
|
+
#Add Listeners
|
17
|
+
this = self
|
18
|
+
self.send(modal_class_symbol).on :change_screen do |args|
|
19
|
+
this.emit :change_screen, {
|
20
|
+
:screen_class_symbol => args[:screen_class_symbol],
|
21
|
+
:created_window_handle => args[:created_window_handle]
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
self.send(modal_class_symbol).on :close_window do |args|
|
26
|
+
this.emit :close_window, {
|
27
|
+
:screen_name => args[:screen_name],
|
28
|
+
:skip_close => args[:skip_close]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
#Todo: modify show modal to be on all possible element methods, also add stuff for hide modal
|
35
|
+
def route_to_modal(modal_requested)
|
36
|
+
AutomationObject::Logger::add('Trying to route to modal', [self.framework_location])
|
37
|
+
|
38
|
+
use_element = nil
|
39
|
+
#Loop through all the elements and try to find "show_modal"
|
40
|
+
self.configuration['elements'] = Hash.new unless self.configuration['elements'].class == Hash
|
41
|
+
self.configuration['elements'].each { |element_name, element_configuration|
|
42
|
+
next unless element_configuration.class == Hash
|
43
|
+
next unless element_configuration['click'].class == Hash
|
44
|
+
next unless element_configuration['click']['after'].class == Hash
|
45
|
+
next unless element_configuration['click']['after']['show_modal']
|
46
|
+
next unless element_configuration['click']['after']['show_modal'].to_s == modal_requested.to_s
|
47
|
+
|
48
|
+
use_element = element_name
|
49
|
+
}
|
50
|
+
|
51
|
+
unless use_element
|
52
|
+
raise "Unable to route to modal #{modal_requested} in screen #{self.screen_name}, no element in screen has show modal for the requested modal"
|
53
|
+
end
|
54
|
+
|
55
|
+
#Send the click request
|
56
|
+
self.send(use_element).click
|
57
|
+
end
|
58
|
+
|
59
|
+
def activate_modal(modal_requested)
|
60
|
+
self.active_modal = modal_requested
|
61
|
+
self.send(modal_requested).before_load #Run before_load event
|
62
|
+
end
|
63
|
+
|
64
|
+
def close_modal(modal_symbol)
|
65
|
+
unless self.active_modal == modal_symbol
|
66
|
+
raise "Expecting modal #{modal_symbol} to be active when requesting to close the modal."
|
67
|
+
end
|
68
|
+
|
69
|
+
modal_configuration = self.send(modal_symbol).configuration
|
70
|
+
|
71
|
+
unless modal_configuration.class == Hash
|
72
|
+
raise "Expecting modal #{modal_symbol} to have a Hash configuration, got: #{modal_configuration.class}"
|
73
|
+
end
|
74
|
+
|
75
|
+
unless modal_configuration['elements'].class == Hash
|
76
|
+
raise "Expecting modal #{modal_symbol} -> elements to have a Hash configuration, got: #{modal_configuration['elements'].class}"
|
77
|
+
end
|
78
|
+
|
79
|
+
modal_elements = modal_configuration['elements']
|
80
|
+
modal_elements.each { |modal_element, element_value|
|
81
|
+
next unless element_value.class == Hash
|
82
|
+
|
83
|
+
element_value.each { |property_key, property_value|
|
84
|
+
next unless property_value.class == Hash
|
85
|
+
next unless property_value['after'].class == Hash
|
86
|
+
|
87
|
+
property_value['after'].each { |hook_key, hook_value|
|
88
|
+
next unless hook_key == 'close_modal'
|
89
|
+
next unless hook_value == true
|
90
|
+
|
91
|
+
self.send(modal_symbol).send(modal_element).send(property_key)
|
92
|
+
return
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
raise "Unable to close modal #{modal_symbol}, no elements found that would close the modal"
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AutomationObject
|
2
|
+
module ScreenPromptHelpers
|
3
|
+
include AutomationObject::HookHelpers
|
4
|
+
|
5
|
+
def accept
|
6
|
+
AutomationObject::Logger::add('Accepting Alert Prompt', [self.framework_location])
|
7
|
+
|
8
|
+
self.do_hook_action('accept', 'before')
|
9
|
+
self.driver_object.accept_prompt
|
10
|
+
self.do_hook_action('accept', 'after')
|
11
|
+
end
|
12
|
+
|
13
|
+
def dismiss
|
14
|
+
AutomationObject::Logger::add('Dismissing Alert Prompt', [self.framework_location])
|
15
|
+
|
16
|
+
self.do_hook_action('dismiss', 'before')
|
17
|
+
self.driver_object.dismiss_prompt
|
18
|
+
self.do_hook_action('dismiss', 'after')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|