automation_object 0.7.6 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/lib/automation_object/blue_print.rb +1 -0
  3. data/lib/automation_object/blue_print/composite/{automatic_onload_modal.rb → automatic_modal_change.rb} +3 -4
  4. data/lib/automation_object/blue_print/composite/base.rb +1 -0
  5. data/lib/automation_object/blue_print/composite/custom_method.rb +2 -3
  6. data/lib/automation_object/blue_print/composite/element.rb +2 -3
  7. data/lib/automation_object/blue_print/composite/element_array.rb +2 -3
  8. data/lib/automation_object/blue_print/composite/element_hash.rb +2 -3
  9. data/lib/automation_object/blue_print/composite/helpers/container_helper.rb +75 -0
  10. data/lib/automation_object/blue_print/composite/helpers/element_helper.rb +30 -1
  11. data/lib/automation_object/blue_print/composite/helpers/multiple_elements_helper.rb +1 -0
  12. data/lib/automation_object/blue_print/composite/hook.rb +18 -6
  13. data/lib/automation_object/blue_print/composite/hook_action.rb +3 -4
  14. data/lib/automation_object/blue_print/composite/hook_element_requirements.rb +3 -4
  15. data/lib/automation_object/blue_print/composite/modal.rb +12 -9
  16. data/lib/automation_object/blue_print/composite/screen.rb +17 -14
  17. data/lib/automation_object/blue_print/composite/top.rb +3 -2
  18. data/lib/automation_object/blue_print/composite/view.rb +8 -7
  19. data/lib/automation_object/blue_print/hash_adapter.rb +1 -0
  20. data/lib/automation_object/blue_print/hash_adapter/{automatic_onload_modal.rb → automatic_modal_change.rb} +3 -2
  21. data/lib/automation_object/blue_print/hash_adapter/composite.rb +1 -0
  22. data/lib/automation_object/blue_print/hash_adapter/custom_method.rb +1 -0
  23. data/lib/automation_object/blue_print/hash_adapter/element.rb +2 -0
  24. data/lib/automation_object/blue_print/hash_adapter/element_array.rb +1 -0
  25. data/lib/automation_object/blue_print/hash_adapter/element_hash.rb +1 -0
  26. data/lib/automation_object/blue_print/hash_adapter/helpers/element_helper.rb +8 -2
  27. data/lib/automation_object/blue_print/hash_adapter/helpers/multiple_elements_helper.rb +1 -0
  28. data/lib/automation_object/blue_print/hash_adapter/helpers/validation_error.rb +2 -1
  29. data/lib/automation_object/blue_print/hash_adapter/helpers/validation_helper.rb +1 -0
  30. data/lib/automation_object/blue_print/hash_adapter/helpers/validators/validate.rb +1 -0
  31. data/lib/automation_object/blue_print/hash_adapter/helpers/validators/validate_allowed_keys.rb +1 -0
  32. data/lib/automation_object/blue_print/hash_adapter/helpers/validators/validate_element_presence_of.rb +1 -0
  33. data/lib/automation_object/blue_print/hash_adapter/helpers/validators/validate_instance_of.rb +1 -0
  34. data/lib/automation_object/blue_print/hash_adapter/helpers/validators/validate_modal_presence_of.rb +1 -0
  35. data/lib/automation_object/blue_print/hash_adapter/helpers/validators/validate_presence_of.rb +1 -0
  36. data/lib/automation_object/blue_print/hash_adapter/helpers/validators/validate_screen_presence_of.rb +1 -0
  37. data/lib/automation_object/blue_print/hash_adapter/helpers/validators/validate_view_presence_of.rb +1 -0
  38. data/lib/automation_object/blue_print/hash_adapter/hook.rb +2 -1
  39. data/lib/automation_object/blue_print/hash_adapter/hook_action.rb +4 -3
  40. data/lib/automation_object/blue_print/hash_adapter/hook_element_requirements.rb +2 -1
  41. data/lib/automation_object/blue_print/hash_adapter/modal.rb +2 -1
  42. data/lib/automation_object/blue_print/hash_adapter/screen.rb +14 -13
  43. data/lib/automation_object/blue_print/hash_adapter/top.rb +3 -2
  44. data/lib/automation_object/blue_print/hash_adapter/view.rb +12 -11
  45. data/lib/automation_object/blue_print/yaml_adapter.rb +1 -0
  46. data/lib/automation_object/driver.rb +1 -0
  47. data/lib/automation_object/driver/appium_adapter/driver.rb +2 -1
  48. data/lib/automation_object/driver/appium_adapter/element.rb +1 -0
  49. data/lib/automation_object/driver/base.rb +1 -0
  50. data/lib/automation_object/driver/common_selenium/driver.rb +1 -0
  51. data/lib/automation_object/driver/common_selenium/element.rb +1 -0
  52. data/lib/automation_object/driver/common_selenium/element_geometry.rb +1 -0
  53. data/lib/automation_object/driver/driver.rb +1 -0
  54. data/lib/automation_object/driver/element.rb +1 -0
  55. data/lib/automation_object/driver/nokogiri_adapter/driver.rb +5 -8
  56. data/lib/automation_object/driver/nokogiri_adapter/element.rb +9 -14
  57. data/lib/automation_object/driver/nokogiri_adapter/error.rb +1 -0
  58. data/lib/automation_object/driver/nokogiri_adapter/form.rb +1 -0
  59. data/lib/automation_object/driver/nokogiri_adapter/request.rb +1 -0
  60. data/lib/automation_object/driver/nokogiri_adapter/session.rb +1 -0
  61. data/lib/automation_object/driver/nokogiri_adapter/window.rb +1 -0
  62. data/lib/automation_object/driver/selenium_adapter/driver.rb +1 -0
  63. data/lib/automation_object/driver/selenium_adapter/element.rb +1 -0
  64. data/lib/automation_object/dsl.rb +4 -2
  65. data/lib/automation_object/dsl/_base.rb +11 -1
  66. data/lib/automation_object/dsl/_error.rb +71 -0
  67. data/lib/automation_object/dsl/_proxy.rb +1 -0
  68. data/lib/automation_object/dsl/element.rb +2 -2
  69. data/lib/automation_object/dsl/element_array.rb +2 -2
  70. data/lib/automation_object/dsl/element_hash.rb +2 -2
  71. data/lib/automation_object/dsl/modal.rb +47 -2
  72. data/lib/automation_object/dsl/screen.rb +67 -3
  73. data/lib/automation_object/dsl/top.rb +19 -0
  74. data/lib/automation_object/framework.rb +18 -1
  75. data/lib/automation_object/helpers/composite.rb +3 -1
  76. data/lib/automation_object/helpers/composite_hook.rb +1 -0
  77. data/lib/automation_object/helpers/file.rb +1 -0
  78. data/lib/automation_object/helpers/hash.rb +1 -0
  79. data/lib/automation_object/helpers/kernel.rb +1 -0
  80. data/lib/automation_object/helpers/reflection.rb +1 -0
  81. data/lib/automation_object/helpers/string.rb +1 -0
  82. data/lib/automation_object/proxy/mutex_proxy.rb +1 -0
  83. data/lib/automation_object/proxy/proxy.rb +1 -0
  84. data/lib/automation_object/proxy/throttle_proxy.rb +2 -1
  85. data/lib/automation_object/state.rb +5 -1
  86. data/lib/automation_object/state/_base.rb +2 -1
  87. data/lib/automation_object/state/_common_element.rb +5 -0
  88. data/lib/automation_object/state/_error.rb +1 -0
  89. data/lib/automation_object/state/automatic_modal_change.rb +13 -0
  90. data/lib/automation_object/state/automatic_screen_changes.rb +13 -0
  91. data/lib/automation_object/state/element.rb +2 -1
  92. data/lib/automation_object/state/element_array.rb +2 -1
  93. data/lib/automation_object/state/element_hash.rb +2 -1
  94. data/lib/automation_object/state/element_proxy.rb +1 -0
  95. data/lib/automation_object/state/helpers/automatic_routing.rb +96 -0
  96. data/lib/automation_object/state/helpers/container_helper.rb +46 -0
  97. data/lib/automation_object/state/hook.rb +1 -0
  98. data/lib/automation_object/state/hook_action.rb +1 -0
  99. data/lib/automation_object/state/hook_actions/action_loop.rb +1 -0
  100. data/lib/automation_object/state/hook_actions/change_screen.rb +1 -0
  101. data/lib/automation_object/state/hook_actions/change_to_previous_screen.rb +1 -0
  102. data/lib/automation_object/state/hook_actions/close_modal.rb +1 -0
  103. data/lib/automation_object/state/hook_actions/close_screen.rb +1 -0
  104. data/lib/automation_object/state/hook_actions/element_requirement.rb +1 -0
  105. data/lib/automation_object/state/hook_actions/new_screen.rb +1 -0
  106. data/lib/automation_object/state/hook_actions/possible_screen_changes.rb +1 -0
  107. data/lib/automation_object/state/hook_actions/reset_screen.rb +1 -0
  108. data/lib/automation_object/state/hook_actions/show_modal.rb +1 -0
  109. data/lib/automation_object/state/hook_actions/sleep.rb +1 -0
  110. data/lib/automation_object/state/hook_actions/wait_for_elements.rb +1 -0
  111. data/lib/automation_object/state/modal.rb +5 -14
  112. data/lib/automation_object/state/screen.rb +33 -19
  113. data/lib/automation_object/state/top.rb +17 -2
  114. data/lib/automation_object/step_definitions.rb +3 -4
  115. data/lib/automation_object/step_definitions/element.rb +22 -23
  116. data/lib/automation_object/step_definitions/element_array.rb +26 -27
  117. data/lib/automation_object/step_definitions/element_hash.rb +26 -27
  118. data/lib/automation_object/step_definitions/modal.rb +31 -0
  119. data/lib/automation_object/step_definitions/screen.rb +22 -10
  120. data/lib/automation_object/step_definitions/support/cache.rb +5 -2
  121. data/lib/automation_object/step_definitions/support/element_array.rb +1 -1
  122. data/lib/automation_object/step_definitions/support/parse.rb +1 -1
  123. data/lib/automation_object/version.rb +2 -1
  124. metadata +59 -39
  125. data/lib/automation_object/step_definitions/support/minitest.rb +0 -10
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative '_base'
3
4
  require_relative '_proxy'
5
+ require_relative '_error'
4
6
 
5
7
  require_relative 'modal'
6
8
  require_relative 'element'
@@ -20,11 +22,10 @@ module AutomationObject
20
22
  # Proxy for Screen
21
23
  class ScreenProxy < Proxy
22
24
  # @param [AutomationObject::BluePrint::Composite::Screen] blue_prints
23
- # @param [AutomationObject::State::Top] top state
25
+ # @param [AutomationObject::State::Top] state
24
26
  # @param [Symbol] name
25
27
  def initialize(blue_prints, state, name)
26
- screen_state = state.screens[name]
27
- super Screen, blue_prints, screen_state, name
28
+ super Screen, blue_prints, state, name
28
29
  end
29
30
 
30
31
  # @param [Symbol] method
@@ -39,10 +40,73 @@ module AutomationObject
39
40
  super
40
41
  end
41
42
 
43
+ # Is the screen active
42
44
  # @return [Boolean]
43
45
  def active?
44
46
  @state.active?
45
47
  end
48
+
49
+ # Close screen
50
+ # @return [void]
51
+ def close
52
+ @state.close
53
+ end
54
+
55
+ # Go to this screen
56
+ # Will try to automatically reach it, will throw error if it cannot
57
+ # @raise [AutomationObject::Dsl::Error::AutoReachScreenError]
58
+ # @return [void]
59
+ def go
60
+ raise AutomationObject::Dsl::Error::AutoReachScreenError, @name unless @state.go
61
+ end
62
+
63
+ # Retrieve modal from composite
64
+ # @param name [String, Symbol] name of modal
65
+ # @raise [AutomationObject::Dsl::Error::ModalDoesNotExistError]
66
+ # @return [AutomationObject::Dsl::ModalProxy]
67
+ def modal(name)
68
+ name = name.to_sym
69
+ raise AutomationObject::Dsl::Error::ModalDoesNotExistError, name unless @subject.to_h.include?(name)
70
+
71
+ @state.utilize
72
+ @subject.send(name)
73
+ end
74
+
75
+ # Retrieve element from composite
76
+ # @param name [String, Symbol] name of element
77
+ # @raise [AutomationObject::Dsl::Error::ElementDoesNotExistError]
78
+ # @return [AutomationObject::Dsl::ElementProxy]
79
+ def element(name)
80
+ name = name.to_sym
81
+ raise AutomationObject::Dsl::Error::ElementDoesNotExistError, name unless @subject.to_h.include?(name)
82
+
83
+ @state.utilize
84
+ @subject.send(name)
85
+ end
86
+
87
+ # Retrieve element array from composite
88
+ # @param name [String, Symbol] name of element array
89
+ # @raise [AutomationObject::Dsl::Error::ElementArrayDoesNotExistError]
90
+ # @return [AutomationObject::Dsl::ElementArrayProxy]
91
+ def element_array(name)
92
+ name = name.to_sym
93
+ raise AutomationObject::Dsl::Error::ElementArrayDoesNotExistError, name unless @subject.to_h.include?(name)
94
+
95
+ @state.utilize
96
+ @subject.send(name)
97
+ end
98
+
99
+ # Retrieve element hash from composite
100
+ # @param name [String, Symbol] name of element hash
101
+ # @raise [AutomationObject::Dsl::Error::ElementHashDoesNotExistError]
102
+ # @return [AutomationObject::Dsl::ElementHashProxy]
103
+ def element_hash(name)
104
+ name = name.to_sym
105
+ raise AutomationObject::Dsl::Error::ElementHashDoesNotExistError, name unless @subject.to_h.include?(name)
106
+
107
+ @state.utilize
108
+ @subject.send(name)
109
+ end
46
110
  end
47
111
  end
48
112
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative '_base'
3
4
  require_relative '_proxy'
5
+ require_relative '_error'
4
6
 
5
7
  require_relative 'screen'
6
8
 
@@ -24,6 +26,23 @@ module AutomationObject
24
26
  def active?
25
27
  true
26
28
  end
29
+
30
+ # Retrieve screen from composite
31
+ # @param name [String, Symbol] name of screen
32
+ # @raise [AutomationObject::Dsl::Error::ScreenDoesNotExistError]
33
+ # @return [AutomationObject::Dsl::ScreenProxy]
34
+ def screen(name)
35
+ name = name.to_sym
36
+ raise AutomationObject::Dsl::Error::ScreenDoesNotExistError, name unless @subject.to_h.include?(name)
37
+
38
+ @subject.send(name)
39
+ end
40
+
41
+ # Current Screen
42
+ # @return [AutomationObject::Dsl::ScreenProxy]
43
+ def current_screen
44
+ @subject.send(@state.current_screen)
45
+ end
27
46
  end
28
47
  end
29
48
  end
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'proxy/proxy'
3
4
  require_relative 'blue_print'
4
5
  require_relative 'driver'
5
6
  require_relative 'dsl'
6
7
  require_relative 'state'
7
8
 
9
+ require_relative 'dsl/_error'
10
+
8
11
  module AutomationObject
9
12
  # Framework class, the core
10
13
  # A Proxy class that will become the DSL Framework
@@ -35,6 +38,20 @@ module AutomationObject
35
38
  AutomationObject::Framework.singleton = self
36
39
  end
37
40
 
41
+ # Retrieve screen from composite
42
+ # @param name [String, Symbol] name of screen
43
+ # @raise [AutomationObject::Dsl::Error::ScreenDoesNotExistError]
44
+ # @return [AutomationObject::Dsl::ScreenProxy]
45
+ def screen(name)
46
+ @subject.screen(name)
47
+ end
48
+
49
+ # Current Screen
50
+ # @return [AutomationObject::Dsl::ScreenProxy]
51
+ def current_screen
52
+ @subject.current_screen
53
+ end
54
+
38
55
  # BluePrints (UI configurations) wrapped in an composite
39
56
  # Composite provides a common interface for all adapters
40
57
  # @param value [String, Hash] String to YAML files or Hash configuration
@@ -82,7 +99,7 @@ module AutomationObject
82
99
  attr_accessor :singleton
83
100
 
84
101
  # Singleton method if using Cucumber
85
- # @return [Framework] singleton of self
102
+ # @return [AutomationObject::Framework] singleton of self
86
103
  def get
87
104
  singleton
88
105
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'reflection'
3
4
  require_relative 'composite_hook'
4
5
 
@@ -14,7 +15,8 @@ module AutomationObject
14
15
  # @param name [Symbol] name of the object
15
16
  # @param parent [Object, nil] parent composite object
16
17
  # @param location [String] string location for error/debugging purposes
17
- def initialize(_name = :top, parent = nil, location = 'top')
18
+ def initialize(name = :top, parent = nil, location = 'top')
19
+ self.name = name
18
20
  self.parent = parent
19
21
  self.location = location
20
22
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module AutomationObject
3
4
  # Hooks for composites
4
5
  module CompositeHook
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Extend file class
3
4
  # Collect files in directory recursively and return Array
4
5
  class File
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Hash class method additions
3
4
  class Hash
4
5
  def deep_merge(second)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Kernel method additions
3
4
  module Kernel
4
5
  def suppress_warnings
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module AutomationObject
3
4
  # Helper module for adding attributes/alias to classes dynamically
4
5
  # Reflection/MetaProgramming
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # String class method additions
3
4
  class String
4
5
  # Test whether a string is a valid url or not
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'proxy'
3
4
 
4
5
  module AutomationObject
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module AutomationObject
3
4
  module Proxy
4
5
  # CompositeBase Proxy class for getting between another
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'proxy'
3
4
 
4
5
  module AutomationObject
@@ -45,7 +46,7 @@ module AutomationObject
45
46
  total_time_taken = Time.new.to_f - start_time
46
47
 
47
48
  sleep_time = throttle_methods[method_symbol] - total_time_taken
48
- sleep(sleep_time) if sleep_time.positive?
49
+ sleep(sleep_time) if sleep_time > 0
49
50
  end
50
51
  end
51
52
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'state/top'
3
4
 
4
5
  module AutomationObject
@@ -13,7 +14,10 @@ module AutomationObject
13
14
  # @param blue_prints [AutomationObject::BluePrint::Composite::Top] Top composite interface
14
15
  # # @return [AutomationObject::State::Top] Top instance
15
16
  def create(driver, blue_prints)
16
- Top.new(driver, blue_prints)
17
+ top = Top.new(driver, blue_prints)
18
+ top.start
19
+
20
+ top
17
21
  end
18
22
  end
19
23
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative '../helpers/composite'
3
4
 
4
5
  module AutomationObject
@@ -46,7 +47,7 @@ module AutomationObject
46
47
 
47
48
  children_hash[child_key] = args.fetch(:interface).new(driver,
48
49
  child_blue_prints,
49
- name, self, child_location)
50
+ child_key, self, child_location)
50
51
  end
51
52
 
52
53
  children_hash
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'hook'
3
4
 
4
5
  module AutomationObject
@@ -39,6 +40,10 @@ module AutomationObject
39
40
 
40
41
  @method_hooks
41
42
  end
43
+
44
+ def method_to_container(name)
45
+ blue_prints.method_to_container(name)
46
+ end
42
47
  end
43
48
  end
44
49
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module AutomationObject
3
4
  module State
4
5
  # Cannot navigate back error
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '_base'
4
+
5
+ module AutomationObject
6
+ module State
7
+ class AutomaticModalChange < Base
8
+ def activate; end
9
+
10
+ def deactivate; end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '_base'
4
+
5
+ module AutomationObject
6
+ module State
7
+ class AutomaticScreenChanges < Base
8
+ def activate; end
9
+
10
+ def deactivate; end
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative '_base'
3
4
  require_relative '_common_element'
4
5
 
@@ -12,7 +13,7 @@ module AutomationObject
12
13
 
13
14
  # @return [AutomationObject::State::ElementProxy] Selenium proxy
14
15
  def utilize
15
- # return self.cache if self.cache
16
+ return cache if cache
16
17
 
17
18
  element = driver.find_element(*blue_prints.selector_params)
18
19
  @active = true
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative '_base'
3
4
  require_relative '_common_element'
4
5
 
@@ -12,7 +13,7 @@ module AutomationObject
12
13
 
13
14
  # @return [Array<AutomationObject::State::ElementProxy>] Selenium proxy
14
15
  def utilize
15
- # return self.cache if self.cache
16
+ return cache if cache
16
17
 
17
18
  elements = driver.find_elements(*blue_prints.selector_params)
18
19
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative '_base'
3
4
  require_relative '_common_element'
4
5
 
@@ -12,7 +13,7 @@ module AutomationObject
12
13
 
13
14
  # @return [Hash<String, AutomationObject::State::ElementProxy>] Selenium proxy
14
15
  def utilize
15
- # return self.cache if self.cache
16
+ return cache if cache
16
17
 
17
18
  elements = driver.find_elements(*blue_prints.selector_params)
18
19
  self.cache = {}
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative '../proxy/proxy'
3
4
 
4
5
  module AutomationObject
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AutomationObject
4
+ module State
5
+ class AutomaticRouting
6
+ MAX_RECURSION_DEPTH = 10
7
+
8
+ # @param top_state [AutomationObject::State::Top]
9
+ # @param target [Symbol]
10
+ def initialize(top_state, target)
11
+ @top = top_state
12
+ @target = target
13
+ end
14
+
15
+ # @return [Boolean] success or not
16
+ def route
17
+ paths = {}
18
+ @top.active_screens.each do |screen_name, screen|
19
+ paths[screen_name] = recursive_search(screen)
20
+ end
21
+
22
+ flattened_paths = flat_hash(paths).keys.sort_by(&:length)
23
+ flattened_paths.each do |flattened_path|
24
+ next unless flattened_path.last == @target
25
+ return follow_route(flattened_path)
26
+ end
27
+
28
+ false
29
+ end
30
+
31
+ private
32
+
33
+ def follow_route(flattened_path)
34
+ flattened_path.each_with_index do |container_name, index|
35
+ parent_name = index > 0 ? flattened_path[index - 1] : nil
36
+ next_container_name = index < flattened_path.length ? flattened_path[index + 1] : nil
37
+
38
+ container = container_by_key(container_name, parent_name)
39
+ container.utilize
40
+
41
+ return true unless next_container_name
42
+
43
+ element = container.element_to_container(next_container_name)
44
+ element_method = element.method_to_container(next_container_name)
45
+
46
+ element_proxy = element.utilize
47
+
48
+ case element
49
+ when ElementArray
50
+ element_proxy.sample.send(element_method) # grab random
51
+ when ElementHash
52
+ element_proxy[element_proxy.keys.sample].send(element_method)
53
+ else
54
+ element_proxy.send(element_method)
55
+ end
56
+ end
57
+
58
+ false
59
+ end
60
+
61
+ def flat_hash(h, f = [], g = {})
62
+ return g.update(f => h) unless h.is_a? Hash
63
+ h.each { |k, r| flat_hash(r, f + [k], g) }
64
+ g
65
+ end
66
+
67
+ # @param container [AutomationObject::State::Screen, AutomationObject::State::Modal]
68
+ # @param depth [Integer]
69
+ def recursive_search(container, depth = 0)
70
+ return nil if depth >= MAX_RECURSION_DEPTH
71
+
72
+ next_level = {}
73
+ container.changes.each do |next_container_name|
74
+ next if next_container_name == container.name
75
+
76
+ if next_container_name == @target
77
+ next_level[next_container_name] = nil
78
+ return next_level
79
+ end
80
+
81
+ next_level[next_container_name] = recursive_search(container_by_key(next_container_name, container.name), depth + 1)
82
+ end
83
+
84
+ next_level
85
+ end
86
+
87
+ # @param container_name [Symbol]
88
+ # @param parent_name [Symbol]
89
+ # @return [AutomationObject::State::Screen, AutomationObject::State::Modal]
90
+ def container_by_key(container_name, parent_name)
91
+ return @top.screens[container_name] if @top.screens[container_name]
92
+ @top.screens[parent_name].modals[container_name]
93
+ end
94
+ end
95
+ end
96
+ end