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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/lib/automation_object/blue_print.rb +106 -0
  3. data/lib/automation_object/blue_print_validation/base_validation.rb +44 -0
  4. data/lib/automation_object/blue_print_validation/common_methods.rb +106 -0
  5. data/lib/automation_object/blue_print_validation/element_validation.rb +198 -0
  6. data/lib/automation_object/blue_print_validation/formatted_errors.rb +41 -0
  7. data/lib/automation_object/blue_print_validation/hook_validation.rb +393 -0
  8. data/lib/automation_object/blue_print_validation/key_value_constants.rb +75 -0
  9. data/lib/automation_object/blue_print_validation/modal_validation.rb +37 -0
  10. data/lib/automation_object/blue_print_validation/screen_modal_common_methods.rb +119 -0
  11. data/lib/automation_object/blue_print_validation/screen_validation.rb +21 -0
  12. data/lib/automation_object/blue_print_validation/validation_object.rb +32 -0
  13. data/lib/automation_object/driver/anonymous.rb +27 -0
  14. data/lib/automation_object/driver/driver.rb +281 -0
  15. data/lib/automation_object/driver/element.rb +243 -0
  16. data/lib/automation_object/element/element.rb +145 -0
  17. data/lib/automation_object/element/element_array.rb +12 -0
  18. data/lib/automation_object/element/element_cell.rb +126 -0
  19. data/lib/automation_object/element/element_group.rb +33 -0
  20. data/lib/automation_object/element/element_hash.rb +25 -0
  21. data/lib/automation_object/element/element_helpers.rb +29 -0
  22. data/lib/automation_object/element/element_methods.rb +134 -0
  23. data/lib/automation_object/element/elements_helpers.rb +204 -0
  24. data/lib/automation_object/framework/events.rb +8 -0
  25. data/lib/automation_object/framework/helpers.rb +101 -0
  26. data/lib/automation_object/framework/print_objects.rb +67 -0
  27. data/lib/automation_object/framework/screen_monitor.rb +55 -0
  28. data/lib/automation_object/framework/screen_routing.rb +310 -0
  29. data/lib/automation_object/framework/window_helpers.rb +181 -0
  30. data/lib/automation_object/framework.rb +408 -0
  31. data/lib/automation_object/hash.rb +6 -0
  32. data/lib/automation_object/hook_helpers.rb +27 -0
  33. data/lib/automation_object/logger.rb +179 -0
  34. data/lib/automation_object/object.rb +22 -0
  35. data/lib/automation_object/screen/modal.rb +8 -0
  36. data/lib/automation_object/screen/screen.rb +209 -0
  37. data/lib/automation_object/screen/screen_hook_helpers.rb +319 -0
  38. data/lib/automation_object/screen/screen_modal_helpers.rb +101 -0
  39. data/lib/automation_object/screen/screen_prompt_helpers.rb +21 -0
  40. data/lib/automation_object/screen/screen_window_helpers.rb +149 -0
  41. data/lib/automation_object/version.rb +3 -0
  42. data/lib/automation_object.rb +80 -0
  43. metadata +279 -0
@@ -0,0 +1,126 @@
1
+ module AutomationObject
2
+ class ElementCell
3
+ include EventEmitter
4
+
5
+ attr_accessor :framework_object, :screen_object, :driver_object, :configuration, :screen_name, :element_name,
6
+ :sub_elements, :element_object
7
+
8
+ def initialize(params)
9
+ #Set params to properties
10
+ self.framework_object = params[:framework_object] || raise(ArgumentError, 'framework_object is required in params')
11
+ self.screen_object = params[:screen_object] || raise(ArgumentError, 'screen_object is required in params')
12
+ self.driver_object = params[:driver_object] || raise(ArgumentError, 'driver_object is required in params')
13
+ #Clone configuration, this will allow edit/deletes on different levels
14
+ self.configuration = params[:blue_prints].clone || raise(ArgumentError, 'configuration is required in params')
15
+
16
+ self.screen_name = params[:screen_name] || raise(ArgumentError, 'screen_name is required in params')
17
+ self.element_name = params[:element_name] || raise(ArgumentError, 'element_name is required in params')
18
+
19
+ #Validate properties
20
+ raise ArgumentError, 'framework_object should be an Framework Object' unless self.framework_object.is_a? Framework
21
+ raise ArgumentError, 'screen_object should be an Screen Object' unless self.screen_object.is_a? Screen
22
+ raise ArgumentError, 'configuration should be a Hash Object' unless self.configuration.is_a? Hash
23
+ raise ArgumentError, 'screen_name should be a String Object' unless self.screen_name.is_a? String
24
+ raise ArgumentError, 'element_name should be a String Object' unless self.element_name.is_a? String
25
+
26
+ self.sub_elements = Array.new
27
+
28
+ #Add Sub-Elements
29
+ return unless self.configuration['sub_elements'].is_a?(Hash)
30
+
31
+ self.configuration['sub_elements'].each { |sub_element_name, sub_element_configuration|
32
+ next unless sub_element_configuration.is_a?(Hash)
33
+ modified_element_configuration = self.combine_selector_path(self.configuration, sub_element_configuration)
34
+
35
+ element_class_name = self.translate_string_to_class(sub_element_name)
36
+ setter = "#{element_class_name}="
37
+ self.class.send(:attr_accessor, element_class_name) unless self.respond_to?(setter)
38
+
39
+ sub_element_object_options = {
40
+ :framework_object => self.framework_object,
41
+ :screen_object => self.screen_object,
42
+ :driver_object => self.driver_object,
43
+ :blue_prints => modified_element_configuration,
44
+ :screen_name => self.screen_name,
45
+ :element_name => element_name
46
+ }
47
+
48
+ send setter, AutomationObject::Element.new(sub_element_object_options)
49
+
50
+ this = self
51
+ self.send(element_class_name).on :hook do |args|
52
+ this.emit :hook, args
53
+ end
54
+
55
+ self.sub_elements.push(sub_element_name)
56
+ }
57
+
58
+ #Add Element Object
59
+ sub_element_object_options = {
60
+ :framework_object => self.framework_object,
61
+ :screen_object => self.screen_object,
62
+ :driver_object => self.driver_object,
63
+ :blue_prints => self.configuration,
64
+ :screen_name => self.screen_name,
65
+ :element_name => self.element_name,
66
+ :element_object => params[:element_object]
67
+ }
68
+
69
+ self.element_object = AutomationObject::Element.new(sub_element_object_options)
70
+ this = self
71
+ self.element_object.on :hook do |args|
72
+ this.emit :hook, args
73
+ end
74
+ end
75
+
76
+ def combine_selector_path(cell_configuration, sub_element_configuration)
77
+ modified_configuration = sub_element_configuration.clone
78
+ if cell_configuration['xpath']
79
+ sub_element_configuration.has_key?('xpath').should == true
80
+ modified_configuration['xpath'] = cell_configuration['xpath'] + sub_element_configuration['xpath']
81
+ elsif cell_configuration['css']
82
+ sub_element_configuration.has_key?('css').should == true
83
+ modified_configuration['css'] = cell_configuration['css'] + ' ' + sub_element_configuration['css']
84
+ else
85
+ raise 'Expecting either css or xpath for selector in element cell configuration'
86
+ end
87
+
88
+ return modified_configuration
89
+ end
90
+
91
+ def respond_to?(method_symbol, include_private = false)
92
+ #Translate method in possible internal storage attribute
93
+ class_symbol = self.translate_string_to_class(method_symbol)
94
+ instance_symbol = class_symbol.to_s.gsub(/^@/, '')
95
+ instance_symbol = "@#{instance_symbol}".to_sym
96
+
97
+ self.instance_variables.each { |instance_variable|
98
+ return true if instance_variable == instance_symbol
99
+ }
100
+
101
+ #If not then do the super on the method_symbol
102
+ return true if super.respond_to?(method_symbol, include_private)
103
+
104
+ #If not try element object
105
+ return self.element_object.respond_to?(method_symbol, include_private)
106
+ end
107
+
108
+ def element_respond_to?(method_symbol, include_private = false)
109
+ return self.element_object.respond_to?(method_symbol, include_private)
110
+ end
111
+
112
+ def method_missing(method_requested, *args, &block)
113
+ class_symbol = self.translate_string_to_class(method_requested)
114
+
115
+ if self.element_respond_to?(method_requested)
116
+ return self.element_object.send(method_requested, *args, &block)
117
+ end
118
+
119
+ if self.respond_to?(class_symbol)
120
+ return self.send(class_symbol, *args, &block)
121
+ end
122
+
123
+ raise "Element (#{method_requested}) is not defined in ElementCell object"
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,33 @@
1
+ module AutomationObject
2
+ class ElementGroup < Array
3
+ include AutomationObject::ElementsHelpers
4
+
5
+ def load_elements
6
+ elements_array = self.get_elements
7
+ elements_array.each_with_index { |element_object, index|
8
+ element_cell_configuration = self.get_individual_configuration(index, self.configuration)
9
+
10
+ group_cell_options = {
11
+ :framework_object => self.framework_object,
12
+ :screen_object => self.screen_object,
13
+ :driver_object => self.driver_object,
14
+ :blue_prints => element_cell_configuration,
15
+ :screen_name => self.screen_name,
16
+ :element_name => (self.element_name + "(#{index})"),
17
+ :element_object => element_object
18
+ }
19
+
20
+ element_cell_object = AutomationObject::ElementCell.new(group_cell_options)
21
+
22
+ self.push(element_cell_object)
23
+
24
+ this = self
25
+ element_cell_object.on :hook do |args|
26
+ this.emit :hook, args
27
+ end
28
+ }
29
+
30
+ self.elements_loaded = true
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ module AutomationObject
2
+ class ElementHash < Hash
3
+ include AutomationObject::ElementsHelpers
4
+
5
+ def load_elements
6
+ modified_elements_array = self.load_elements_global
7
+
8
+ modified_elements_array.each { |modified_element|
9
+ element_key = self.get_element_key(modified_element)
10
+ #Change element name so that it includes the hash index instead of the array index
11
+ modified_element.element_name = (self.element_name + "(#{element_key})")
12
+ self[element_key] = modified_element
13
+ }
14
+ end
15
+
16
+ def get_element_key(element_object)
17
+ element_method = self.configuration['define_elements_by'].to_sym
18
+ unless element_object.respond_to?(element_method)
19
+ raise ArgumentError, "Element object does not have method (#{element_method}), for ElementHash (#{self.element_name}) in Screen (#{self.screen_name})"
20
+ end
21
+
22
+ element_object.send(self.configuration['define_elements_by'])
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ module AutomationObject
2
+ module ElementHelpers
3
+ def get_selector_params(configuration)
4
+ params = Hash.new
5
+ if configuration['xpath']
6
+ params[:selector_method] = :xpath
7
+ params[:selector] = configuration['xpath']
8
+ elsif configuration['css']
9
+ params[:selector_method] = :css
10
+ params[:selector] = configuration['css']
11
+ else
12
+ raise(ArgumentError, 'xPath and CSS are the only element selectors available')
13
+ end
14
+
15
+ params
16
+ end
17
+
18
+ def is_multiple?
19
+ return true if self.configuration['multiple'] == true
20
+ return false
21
+ end
22
+
23
+ def in_iframe?
24
+ return false unless configuration.is_a?(Hash)
25
+ return false unless configuration.has_key?('in_iframe')
26
+ return true if configuration['in_iframe']
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,134 @@
1
+ #Provides wrapper for mutex safe executions on a single driver
2
+ #Without results in pain in the ass errors involving IO interruptions with driver
3
+ module AutomationObject
4
+ class ElementMethods
5
+ include AutomationObject::ElementHelpers
6
+
7
+ attr_accessor :parent_element_object, :driver_object,
8
+ :framework_object,
9
+ :element_object, :configuration,
10
+ :screen_name, :element_name
11
+
12
+ def initialize(parent_element_object)
13
+ self.parent_element_object = parent_element_object
14
+ self.framework_object = self.parent_element_object.framework_object
15
+
16
+ self.screen_name = self.parent_element_object.screen_name
17
+ self.element_name = self.parent_element_object.element_name
18
+
19
+ self.driver_object = self.parent_element_object.driver_object
20
+ self.element_object = parent_element_object.element_object if parent_element_object.element_object
21
+ self.configuration = self.parent_element_object.configuration
22
+ end
23
+
24
+ def respond_to?(method_symbol, include_private = false)
25
+ return true if super
26
+
27
+ #Check custom_methods configuration, return true if it does have the key
28
+ if self.configuration['custom_methods'].class == Hash
29
+ if self.configuration['custom_methods'].has_key?(method_symbol.to_s)
30
+ return true
31
+ end
32
+ end
33
+
34
+ #Now we need to check the element
35
+ element_object = self.get_element
36
+ return element_object.respond_to?(method_symbol, include_private)
37
+ end
38
+
39
+ def method_missing(method_symbol, *arguments, &block)
40
+ unless element_object.respond_to?(method_symbol)
41
+ configuration = self.configuration
42
+ if configuration['custom_methods'].class == Hash
43
+ if configuration['custom_methods'].has_key?(method_symbol.to_s)
44
+ method_eval_configuration = configuration['custom_methods'][method_symbol.to_s]
45
+ return self.custom_evaluation(method_symbol.to_s, method_eval_configuration)
46
+ end
47
+ end
48
+ end
49
+
50
+ element_object = self.get_element
51
+ element_object.send(method_symbol, *arguments, &block)
52
+ end
53
+
54
+ def get_element
55
+ #Return element_object if already set
56
+ return self.element_object if self.element_object
57
+ #Get Element
58
+ self.find_element
59
+ self.element_object
60
+ end
61
+
62
+ def find_element
63
+ #Find element if not already set and set it to self
64
+ selector_params = self.get_selector_params(self.configuration)
65
+ #ap selector_params
66
+ self.element_object = self.driver_object.find_element(selector_params[:selector_method], selector_params[:selector])
67
+ end
68
+
69
+ def reset_element
70
+ if self.element_object
71
+ AutomationObject::Logger::add('Resetting element', [self.parent_element_object.framework_location])
72
+ end
73
+ self.element_object = nil
74
+ end
75
+
76
+ def exists?
77
+ selector_params = self.get_selector_params(self.configuration)
78
+ element_exists = self.driver_object.exists?(selector_params[:selector_method], selector_params[:selector])
79
+
80
+ self.reset_element unless element_exists
81
+ return element_exists
82
+ end
83
+
84
+ def custom_evaluation(custom_method_name, method_eval_configuration)
85
+ return nil if method_eval_configuration.class != Hash
86
+
87
+ unless method_eval_configuration['element_method']
88
+ raise ArgumentError, "element_method key is needed for the custom method #{custom_method_name}"
89
+ end
90
+
91
+ unless method_eval_configuration['evaluate']
92
+ raise ArgumentError, "evaluate key is needed for the custom method #{custom_method_name}"
93
+ end
94
+
95
+ element_method = method_eval_configuration['element_method'].to_sym
96
+
97
+ element_object = self.get_element
98
+ if self.respond_to?(element_method)
99
+ evaluation_value = self.send(element_method)
100
+ else
101
+ evaluation_value = element_object.send(element_method)
102
+ end
103
+
104
+ evaluation_script = "evaluation_value.#{method_eval_configuration['evaluate']}"
105
+
106
+ AutomationObject::Logger::add("Running custom evaluation method #{custom_method_name}", [self.parent_element_object.framework_location])
107
+
108
+ return eval(evaluation_script)
109
+ end
110
+
111
+ def drag_to_element(secondary_element)
112
+ if self.parent_element_object.driver_object.device_is_android?
113
+ raise 'This has not been implemented for Android services yet'
114
+ end
115
+
116
+ #Do this internally to avoid thread locking
117
+ secondary_element = self.parent_element_object.screen_object.send(secondary_element)
118
+
119
+ unless self.parent_element_object.framework_object.is_mobile?
120
+ return self.driver_object.drag_and_drop(self.get_element, secondary_element.get_element)
121
+ end
122
+
123
+ primary_center = self.get_element_center
124
+ secondary_center = secondary_element.get_element_center
125
+
126
+ location_string = "{x:#{primary_center[:x]}, y:#{primary_center[:y]}}, {x:#{secondary_center[:x]}, y:#{secondary_center[:y]}}"
127
+ ios_command = "UIATarget.localTarget().dragFromToForDuration(#{location_string}, 0.7);"
128
+
129
+ AutomationObject::Logger::add("Running drag command on element to element #{secondary_element}", [self.parent_element_object.framework_location])
130
+
131
+ self.driver_object.execute_script(ios_command)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,204 @@
1
+ module AutomationObject
2
+ module ElementsHelpers
3
+ include EventEmitter
4
+ include AutomationObject::ElementHelpers
5
+
6
+ attr_accessor :framework_object, :screen_object, :driver_object,
7
+ :configuration,
8
+ :screen_name, :element_name,
9
+ :elements_loaded #Boolean
10
+
11
+ #Same initialize in both Array and Hash Classes
12
+ def initialize(params)
13
+ self.elements_loaded = false #Set to false as default
14
+
15
+ #Set params to properties
16
+ self.framework_object = params[:framework_object] || raise(ArgumentError, 'framework_object is required in params')
17
+ self.screen_object = params[:screen_object] || raise(ArgumentError, 'screen_object is required in params')
18
+ self.driver_object = params[:driver_object] || raise(ArgumentError, 'driver_object is required in params')
19
+ #Clone configuration, this will allow edit/deletes on different levels
20
+ self.configuration = params[:blue_prints].clone || raise(ArgumentError, 'configuration is required in params')
21
+
22
+ self.screen_name = params[:screen_name] || raise(ArgumentError, 'screen_name is required in params')
23
+ self.element_name = params[:element_name] || raise(ArgumentError, 'element_name is required in params')
24
+
25
+ #Validate properties
26
+ raise ArgumentError, 'framework_object should be an Framework Object' unless self.framework_object.is_a? Framework
27
+ raise ArgumentError, 'screen_object should be an Screen Object' unless self.screen_object.is_a? Screen
28
+ raise ArgumentError, 'configuration should be a Hash Object' unless self.configuration.is_a? Hash
29
+ raise ArgumentError, 'screen_name should be a String Object' unless self.screen_name.is_a? String
30
+ raise ArgumentError, 'element_name should be a String Object' unless self.element_name.is_a? String
31
+ end
32
+
33
+ def get_elements
34
+ #Deal with iFrames
35
+ if self.framework_object.is_browser?
36
+ if self.in_iframe?
37
+ self.screen_object.switch_to_iframe(self.element_name)
38
+ end
39
+ end
40
+
41
+ selector_params = self.get_selector_params(self.configuration)
42
+
43
+ if self.configuration['multiple_ios_fix'] and self.framework_object.is_mobile?
44
+ unless self.driver_object.device_is_android?
45
+ return self.get_elements_temp_ios_fix
46
+ end
47
+ end
48
+
49
+ elements_array = self.driver_object.find_elements(selector_params[:selector_method], selector_params[:selector])
50
+
51
+ return elements_array unless elements_array.is_a?(Array)
52
+ return elements_array if elements_array.length == 0
53
+
54
+ if self.configuration['remove_duplicates']
55
+ elements_array = self.remove_duplicates(elements_array, self.configuration['remove_duplicates'])
56
+ end
57
+
58
+ return elements_array if elements_array.length == 0
59
+
60
+ if self.configuration['custom_range']
61
+ elements_array = self.get_custom_range_elements(elements_array, self.configuration['custom_range'])
62
+ end
63
+
64
+ return elements_array
65
+ end
66
+
67
+ #Dump array into Hash so that we can skip already existing keys that return Hash values Array
68
+ def remove_duplicates(elements_array, element_method)
69
+ element_method = element_method.to_sym
70
+ elements_hash = Hash.new
71
+
72
+ elements_array.each { |element|
73
+ unless element.respond_to?(element_method)
74
+ raise "Expecting element to respond to method #{element_method} defined in remove_duplicates for #{self.screen_name}->#{self.element_name}"
75
+ end
76
+
77
+ element_value = element.send(element_method)
78
+
79
+ next if elements_hash.has_key?(element_value)
80
+ elements_hash[element.send(element_method)] = element
81
+ }
82
+
83
+ #Return the values array
84
+ return elements_hash.values
85
+ end
86
+
87
+ def get_custom_range_elements(elements_array, range_hash)
88
+ unless range_hash.is_a?(Hash)
89
+ raise "Expecting custom_range to be a Hash, got #{range_hash.class}. Defined in #{self.screen_name}->#{self.element_name}"
90
+ end
91
+
92
+ start_index = 0
93
+ if range_hash['start'].is_a?(Numeric)
94
+ start_index = range_hash['start'].to_i
95
+ end
96
+
97
+ end_index = 0
98
+ if range_hash['end'].is_a?(Numeric)
99
+ end_index = range_hash['end'].to_i
100
+ end
101
+
102
+ new_elements_array = Array.new
103
+ elements_array.each_with_index { |element, index|
104
+ element_index = index + 1 #Since elements start at 1
105
+ next if element_index < start_index
106
+
107
+ if end_index != 0
108
+ break if element_index > end_index
109
+ end
110
+
111
+ new_elements_array.push(element)
112
+ }
113
+
114
+ return new_elements_array
115
+ end
116
+
117
+ #Todo: remove when Appium is fixed for iOS Apps
118
+ #Multiple elements in iOS App is killing the whole thing
119
+ #Get around the problem by appending [index] to each using find_element til failure
120
+ def get_elements_temp_ios_fix
121
+ selector_params = self.get_selector_params(self.configuration)
122
+ #Get rid of any shit at the end, //blah/element[1] becomes //blah/element only for numeric indexes, going to add a numeric index
123
+
124
+ elements_array = Array.new
125
+
126
+ index = 1
127
+ find_element_failure = false
128
+ until find_element_failure
129
+ selector_params[:selector] = selector_params[:selector].gsub(/\[\d+\]$/, '')
130
+ selector_params[:selector] = selector_params[:selector] + "[#{index}]"
131
+
132
+ begin
133
+ if self.driver_object.exists?(selector_params[:selector_method], selector_params[:selector])
134
+ elements_array.push(self.driver_object.find_element(selector_params[:selector_method], selector_params[:selector]))
135
+ else
136
+ find_element_failure = true
137
+ break
138
+ end
139
+ rescue
140
+ find_element_failure = true
141
+ break
142
+ end
143
+
144
+ index += 1
145
+ end
146
+
147
+ return elements_array
148
+ end
149
+
150
+ #Cannot override module method, call this in Hash/Array and do specifics in
151
+ # load_elements of those classes
152
+ def load_elements_global
153
+ elements_array = self.get_elements
154
+
155
+ modified_elements_array = Array.new
156
+ elements_array.each_with_index do |element_object, index|
157
+ #Get params for individual element, given the index
158
+ element_configuration = self.get_individual_configuration(index, self.configuration)
159
+
160
+ element_object_options = {
161
+ :framework_object => self.framework_object,
162
+ :screen_object => self.screen_object,
163
+ :driver_object => self.driver_object,
164
+ :blue_prints => element_configuration,
165
+ :screen_name => self.screen_name,
166
+ :element_name => (self.element_name + "(#{index})"),
167
+ :element_object => element_object
168
+ }
169
+
170
+ new_element = AutomationObject::Element.new(element_object_options)
171
+
172
+ this = self
173
+ new_element.on :hook do |args|
174
+ this.emit :hook, args
175
+ end
176
+
177
+ modified_elements_array.push(new_element)
178
+ end
179
+
180
+ self.elements_loaded = true
181
+ return modified_elements_array
182
+ end
183
+
184
+ def get_individual_configuration(index, configuration)
185
+ element_configuration = configuration.clone
186
+ element_index = index + 1 #Elements start at one instead of zero, so add one
187
+
188
+ if element_configuration['xpath']
189
+ element_configuration['xpath'] = '(' + element_configuration['xpath'].to_s + ')' + "[position() = #{element_index}]"
190
+ elsif element_configuration['css']
191
+ element_configuration['css'] = element_configuration['css'].to_s + ":nth-of-type(#{element_index})"
192
+ else
193
+ raise(ArgumentError, 'xPath and CSS are the only element selectors available')
194
+ end
195
+
196
+ return element_configuration
197
+ end
198
+
199
+ def reset_elements
200
+ self.clear #Same method for both Hashes and Arrays
201
+ self.elements_loaded = false
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,8 @@
1
+ module AutomationObject
2
+ module FrameworkEvents
3
+ def screen_change_emit(screen_class_symbol)
4
+ screen_name = self.translate_class_to_string(screen_class_symbol)
5
+ self.emit(:screen_change, screen_name)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,101 @@
1
+ module AutomationObject
2
+ module FrameworkHelpers
3
+ attr_accessor :is_mobile, :is_browser, :supports_contexts
4
+
5
+ def is_mobile?
6
+ if self.is_mobile == nil
7
+ self.is_mobile = self.supports_contexts?
8
+ end
9
+
10
+ return self.is_mobile
11
+ end
12
+
13
+ def is_browser?
14
+ unless self.is_browser == nil
15
+ return self.is_browser
16
+ end
17
+
18
+ #If Selenium the yeah we are using a browser
19
+ if self.supports_window_handles?
20
+ self.is_browser = true
21
+ return self.is_browser
22
+ end
23
+
24
+ #Now we need to check Appium's contexts to see if WEBVIEW is in available_contexts
25
+ available_contexts = self.driver_object.available_contexts
26
+ self.supports_contexts = true
27
+
28
+ available_contexts.each { |context|
29
+ if context.match(/^WEBVIEW_\d+$/)
30
+ self.is_browser = true
31
+ return self.is_browser
32
+ end
33
+ }
34
+
35
+ self.is_browser = false
36
+ return self.is_browser
37
+ end
38
+
39
+ #Selenium's use of window_handles
40
+ def supports_window_handles?
41
+ begin
42
+ self.driver_object.window_handles
43
+ return true
44
+ rescue NoMethodError, Selenium::WebDriver::Error::UnknownError
45
+ return false
46
+ end
47
+ end
48
+
49
+ #Appium's use of window_handles
50
+ def supports_contexts?
51
+ return self.supports_contexts if self.supports_contexts != nil
52
+
53
+ begin
54
+ self.driver_object.available_contexts
55
+ self.supports_contexts = true
56
+ return true
57
+ rescue NoMethodError
58
+ return false
59
+ end
60
+ end
61
+
62
+ def current_screen
63
+ current_screen_object = Object.new
64
+ current_screen_object.class.module_eval { attr_accessor :framework_object }
65
+ current_screen_object.framework_object = self
66
+
67
+ def current_screen_object.method_missing(method_symbol, *args, &block)
68
+ return self.framework_object.send(self.framework_object.get_current_screen).send(method_symbol, *args, &block)
69
+ end
70
+
71
+ current_screen_object
72
+ end
73
+
74
+ def get_current_screen
75
+ return self.translate_class_to_string(self.current_screen_class).to_sym
76
+ end
77
+
78
+ def kill_monitor_threads
79
+ begin
80
+ self.screen_monitor_thread.each_value { |thread|
81
+ Thread.kill(thread) if thread
82
+ }
83
+ rescue
84
+ # ignored
85
+ end
86
+ end
87
+
88
+ def quit
89
+ AutomationObject::Logger::add('Quitting the framework')
90
+ self.kill_monitor_threads
91
+
92
+ if self.driver_object.respond_to?(:quit)
93
+ self.driver_object.quit if self.driver_object.respond_to?(:quit)
94
+ elsif self.driver_object.respond_to?(:driver_quit)
95
+ self.driver_object.driver_quit if self.driver_object.respond_to?(:driver_quit)
96
+ else
97
+ raise 'Unable to find provided driver quit method'
98
+ end
99
+ end
100
+ end
101
+ end