ruby_raider 2.0.0 → 3.0.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 (224) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/e2e_tests.yml +58 -0
  3. data/.github/workflows/steep.yml +21 -0
  4. data/.gitignore +1 -1
  5. data/.reek.yml +46 -4
  6. data/.ruby-version +1 -1
  7. data/README.md +138 -77
  8. data/Steepfile +22 -0
  9. data/assets/ruby_raider_logo.svg +51 -0
  10. data/lib/adopter/adopt_menu.rb +11 -15
  11. data/lib/adopter/converters/base_converter.rb +1 -2
  12. data/lib/adopter/converters/identity_converter.rb +3 -6
  13. data/lib/adopter/migration_plan.rb +0 -1
  14. data/lib/adopter/plan_builder.rb +2 -5
  15. data/lib/adopter/project_analyzer.rb +1 -5
  16. data/lib/adopter/project_detector.rb +3 -5
  17. data/lib/commands/adopt_commands.rb +0 -1
  18. data/lib/commands/plugin_commands.rb +0 -2
  19. data/lib/commands/scaffolding_commands.rb +220 -37
  20. data/lib/commands/utility_commands.rb +82 -2
  21. data/lib/generators/automation/automation_generator.rb +0 -7
  22. data/lib/generators/automation/templates/partials/element.tt +1 -1
  23. data/lib/generators/automation/templates/partials/initialize_selector.tt +0 -7
  24. data/lib/generators/automation/templates/partials/url_methods.tt +0 -1
  25. data/lib/generators/common_generator.rb +12 -0
  26. data/lib/generators/cucumber/cucumber_generator.rb +36 -0
  27. data/lib/generators/cucumber/templates/accessibility_feature.tt +5 -0
  28. data/lib/generators/cucumber/templates/accessibility_steps.tt +21 -0
  29. data/lib/generators/cucumber/templates/cucumber.tt +8 -1
  30. data/lib/generators/cucumber/templates/feature.tt +0 -4
  31. data/lib/generators/cucumber/templates/partials/appium_env.tt +5 -0
  32. data/lib/generators/cucumber/templates/partials/capybara_env.tt +19 -1
  33. data/lib/generators/cucumber/templates/partials/driver_world.tt +1 -4
  34. data/lib/generators/cucumber/templates/partials/selenium_env.tt +22 -35
  35. data/lib/generators/cucumber/templates/partials/watir_env.tt +20 -1
  36. data/lib/generators/cucumber/templates/partials/web_steps.tt +6 -12
  37. data/lib/generators/cucumber/templates/performance_feature.tt +5 -0
  38. data/lib/generators/cucumber/templates/performance_steps.tt +17 -0
  39. data/lib/generators/cucumber/templates/visual_feature.tt +5 -0
  40. data/lib/generators/cucumber/templates/visual_steps.tt +19 -0
  41. data/lib/generators/generator.rb +38 -7
  42. data/lib/generators/helper_generator.rb +24 -7
  43. data/lib/generators/infrastructure/templates/github.tt +1 -1
  44. data/lib/generators/infrastructure/templates/github_appium.tt +2 -2
  45. data/lib/generators/infrastructure/templates/gitlab.tt +1 -1
  46. data/lib/generators/invoke_generators.rb +42 -9
  47. data/lib/generators/menu_generator.rb +120 -11
  48. data/lib/generators/minitest/minitest_generator.rb +16 -4
  49. data/lib/generators/minitest/templates/accessibility_test.tt +26 -0
  50. data/lib/generators/minitest/templates/performance_test.tt +18 -0
  51. data/lib/generators/minitest/templates/test.tt +5 -34
  52. data/lib/generators/minitest/templates/visual_test.tt +23 -0
  53. data/lib/generators/rspec/rspec_generator.rb +16 -4
  54. data/lib/generators/rspec/templates/accessibility_spec.tt +25 -0
  55. data/lib/generators/rspec/templates/performance_spec.tt +18 -0
  56. data/lib/generators/rspec/templates/spec.tt +5 -35
  57. data/lib/generators/rspec/templates/visual_spec.tt +20 -0
  58. data/lib/generators/template_renderer/partial_cache.rb +11 -1
  59. data/lib/generators/template_renderer/partial_resolver.rb +17 -10
  60. data/lib/generators/template_renderer.rb +17 -1
  61. data/lib/generators/templates/common/gemfile.tt +21 -6
  62. data/lib/generators/templates/common/git_ignore.tt +6 -1
  63. data/lib/generators/templates/common/partials/mobile_config.tt +5 -1
  64. data/lib/generators/templates/common/partials/web_config.tt +16 -7
  65. data/lib/generators/templates/common/rakefile.tt +36 -0
  66. data/lib/generators/templates/common/read_me.tt +41 -91
  67. data/lib/generators/templates/common/rspec.tt +3 -0
  68. data/lib/generators/templates/common/ruby_version.tt +1 -0
  69. data/lib/generators/templates/helpers/allure_helper.tt +11 -0
  70. data/lib/generators/templates/helpers/browser_helper.tt +12 -2
  71. data/lib/generators/templates/helpers/capybara_helper.tt +5 -1
  72. data/lib/generators/templates/helpers/debug_helper.tt +190 -0
  73. data/lib/generators/templates/helpers/driver_helper.tt +2 -10
  74. data/lib/generators/templates/helpers/partials/appium_driver.tt +0 -2
  75. data/lib/generators/templates/helpers/partials/debug_diagnostics.tt +7 -0
  76. data/lib/generators/templates/helpers/partials/debug_start.tt +7 -0
  77. data/lib/generators/templates/helpers/partials/driver_and_options.tt +1 -3
  78. data/lib/generators/templates/helpers/partials/selenium_driver.tt +8 -7
  79. data/lib/generators/templates/helpers/partials/video_start.tt +9 -0
  80. data/lib/generators/templates/helpers/partials/video_stop.tt +4 -0
  81. data/lib/generators/templates/helpers/performance_helper.tt +57 -0
  82. data/lib/generators/templates/helpers/spec_helper.tt +57 -8
  83. data/lib/generators/templates/helpers/test_helper.tt +69 -1
  84. data/lib/generators/templates/helpers/video_helper.tt +270 -0
  85. data/lib/generators/templates/helpers/visual_helper.tt +39 -46
  86. data/lib/llm/client.rb +79 -0
  87. data/lib/llm/config.rb +57 -0
  88. data/lib/llm/prompts.rb +84 -0
  89. data/lib/llm/provider.rb +27 -0
  90. data/lib/llm/providers/anthropic_provider.rb +43 -0
  91. data/lib/llm/providers/ollama_provider.rb +56 -0
  92. data/lib/llm/providers/openai_provider.rb +42 -0
  93. data/lib/llm/response_parser.rb +67 -0
  94. data/lib/plugin/plugin.rb +22 -20
  95. data/lib/plugin/plugin_exposer.rb +16 -38
  96. data/lib/ruby_raider.rb +47 -12
  97. data/lib/scaffolding/crud_generator.rb +94 -0
  98. data/lib/scaffolding/dry_run_presenter.rb +16 -0
  99. data/lib/scaffolding/name_normalizer.rb +63 -0
  100. data/lib/scaffolding/page_introspector.rb +45 -0
  101. data/lib/scaffolding/project_detector.rb +72 -0
  102. data/lib/scaffolding/scaffold_menu.rb +103 -0
  103. data/lib/scaffolding/scaffolding.rb +158 -11
  104. data/lib/scaffolding/templates/component.tt +30 -0
  105. data/lib/scaffolding/templates/feature.tt +4 -4
  106. data/lib/scaffolding/templates/helper.tt +15 -1
  107. data/lib/scaffolding/templates/page_from_url.tt +75 -0
  108. data/lib/scaffolding/templates/page_object.tt +50 -1
  109. data/lib/scaffolding/templates/spec.tt +33 -2
  110. data/lib/scaffolding/templates/spec_from_page.tt +31 -0
  111. data/lib/scaffolding/templates/spec_from_url.tt +46 -0
  112. data/lib/scaffolding/templates/steps.tt +17 -5
  113. data/lib/scaffolding/url_analyzer.rb +179 -0
  114. data/lib/utilities/desktop_downloader.rb +177 -0
  115. data/lib/utilities/logo.rb +83 -0
  116. data/lib/utilities/utilities.rb +53 -20
  117. data/lib/version +1 -1
  118. data/ruby_raider.gemspec +1 -0
  119. data/sig/adopter/adopt_menu.rbs +25 -0
  120. data/sig/adopter/converters/base_converter.rbs +23 -0
  121. data/sig/adopter/converters/identity_converter.rbs +16 -0
  122. data/sig/adopter/migration_plan.rbs +34 -0
  123. data/sig/adopter/migrator.rbs +21 -0
  124. data/sig/adopter/plan_builder.rbs +38 -0
  125. data/sig/adopter/project_analyzer.rbs +39 -0
  126. data/sig/adopter/project_detector.rbs +26 -0
  127. data/sig/commands/adopt_commands.rbs +8 -0
  128. data/sig/commands/loaded_commands.rbs +5 -0
  129. data/sig/commands/plugin_commands.rbs +9 -0
  130. data/sig/commands/scaffolding_commands.rbs +28 -0
  131. data/sig/commands/utility_commands.rbs +21 -0
  132. data/sig/generators/automation/automation_generator.rbs +20 -0
  133. data/sig/generators/common_generator.rbs +12 -0
  134. data/sig/generators/cucumber/cucumber_generator.rbs +16 -0
  135. data/sig/generators/generator.rbs +40 -0
  136. data/sig/generators/helper_generator.rbs +18 -0
  137. data/sig/generators/infrastructure/github_generator.rbs +5 -0
  138. data/sig/generators/infrastructure/gitlab_generator.rbs +4 -0
  139. data/sig/generators/invoke_generators.rbs +10 -0
  140. data/sig/generators/menu_generator.rbs +29 -0
  141. data/sig/generators/minitest/minitest_generator.rbs +8 -0
  142. data/sig/generators/rspec/rspec_generator.rbs +8 -0
  143. data/sig/generators/template_renderer/partial_cache.rbs +20 -0
  144. data/sig/generators/template_renderer/partial_resolver.rbs +20 -0
  145. data/sig/generators/template_renderer/template_error.rbs +19 -0
  146. data/sig/generators/template_renderer.rbs +10 -0
  147. data/sig/llm/client.rbs +15 -0
  148. data/sig/llm/config.rbs +20 -0
  149. data/sig/llm/prompts.rbs +8 -0
  150. data/sig/llm/provider.rbs +12 -0
  151. data/sig/llm/providers/anthropic_provider.rbs +16 -0
  152. data/sig/llm/providers/ollama_provider.rbs +18 -0
  153. data/sig/llm/providers/openai_provider.rbs +16 -0
  154. data/sig/llm/response_parser.rbs +13 -0
  155. data/sig/plugin/plugin.rbs +24 -0
  156. data/sig/plugin/plugin_exposer.rbs +20 -0
  157. data/sig/ruby_raider.rbs +15 -0
  158. data/sig/scaffolding/crud_generator.rbs +16 -0
  159. data/sig/scaffolding/dry_run_presenter.rbs +4 -0
  160. data/sig/scaffolding/name_normalizer.rbs +17 -0
  161. data/sig/scaffolding/page_introspector.rbs +14 -0
  162. data/sig/scaffolding/project_detector.rbs +14 -0
  163. data/sig/scaffolding/scaffold_menu.rbs +18 -0
  164. data/sig/scaffolding/scaffolding.rbs +55 -0
  165. data/sig/scaffolding/url_analyzer.rbs +28 -0
  166. data/sig/utilities/desktop_downloader.rbs +23 -0
  167. data/sig/utilities/logger.rbs +13 -0
  168. data/sig/utilities/logo.rbs +16 -0
  169. data/sig/utilities/utilities.rbs +30 -0
  170. data/sig/vendor/thor.rbs +34 -0
  171. data/sig/vendor/tty_prompt.rbs +15 -0
  172. data/spec/adopter/adopt_menu_spec.rb +12 -12
  173. data/spec/adopter/migration_plan_spec.rb +1 -1
  174. data/spec/adopter/migrator_spec.rb +2 -2
  175. data/spec/adopter/project_detector_spec.rb +1 -1
  176. data/spec/commands/raider_commands_spec.rb +129 -0
  177. data/spec/generators/generator_spec.rb +23 -0
  178. data/spec/integration/commands/scaffolding_commands_spec.rb +1 -1
  179. data/spec/integration/commands/utility_commands_spec.rb +23 -3
  180. data/spec/integration/content/ci_content_spec.rb +119 -0
  181. data/spec/integration/content/common_content_spec.rb +288 -0
  182. data/spec/integration/content/config_content_spec.rb +175 -0
  183. data/spec/integration/content/content_helper.rb +32 -0
  184. data/spec/integration/content/gemfile_content_spec.rb +209 -0
  185. data/spec/integration/content/helper_content_spec.rb +485 -0
  186. data/spec/integration/content/page_content_spec.rb +259 -0
  187. data/spec/integration/content/reporter_content_spec.rb +236 -0
  188. data/spec/integration/content/skip_flags_content_spec.rb +206 -0
  189. data/spec/integration/content/syntax_validation_spec.rb +30 -0
  190. data/spec/integration/content/test_content_spec.rb +266 -0
  191. data/spec/integration/end_to_end_features_spec.rb +690 -0
  192. data/spec/integration/end_to_end_spec.rb +52 -16
  193. data/spec/integration/generators/automation_generator_spec.rb +0 -12
  194. data/spec/integration/generators/axe_addon_spec.rb +150 -0
  195. data/spec/integration/generators/common_generator_spec.rb +12 -13
  196. data/spec/integration/generators/config_features_spec.rb +155 -0
  197. data/spec/integration/generators/debug_helper_spec.rb +68 -0
  198. data/spec/integration/generators/helpers_generator_spec.rb +0 -12
  199. data/spec/integration/generators/lighthouse_addon_spec.rb +132 -0
  200. data/spec/integration/generators/minitest_generator_spec.rb +0 -6
  201. data/spec/integration/generators/reporter_spec.rb +159 -0
  202. data/spec/integration/generators/skip_flags_spec.rb +134 -0
  203. data/spec/integration/generators/visual_addon_spec.rb +148 -0
  204. data/spec/integration/settings_helper.rb +0 -3
  205. data/spec/integration/spec_helper.rb +30 -13
  206. data/spec/llm/client_spec.rb +79 -0
  207. data/spec/llm/config_spec.rb +92 -0
  208. data/spec/llm/prompts_spec.rb +49 -0
  209. data/spec/llm/response_parser_spec.rb +92 -0
  210. data/spec/menus/adopter_adopt_menu_spec.rb +97 -0
  211. data/spec/menus/menu_generator_spec.rb +263 -0
  212. data/spec/scaffolding/name_normalizer_spec.rb +113 -0
  213. data/spec/scaffolding/page_introspector_spec.rb +82 -0
  214. data/spec/scaffolding/scaffold_project_detector_spec.rb +104 -0
  215. data/spec/scaffolding/scaffolding_features_spec.rb +311 -0
  216. data/spec/scaffolding/url_analyzer_spec.rb +110 -0
  217. data/spec/system/adopt_matrix_spec.rb +537 -0
  218. data/spec/system/adopt_spec.rb +225 -0
  219. data/spec/system/support/system_test_helper.rb +0 -2
  220. data/spec/utilities/desktop_downloader_spec.rb +92 -0
  221. metadata +150 -5
  222. data/lib/generators/automation/templates/visual_options.tt +0 -16
  223. data/lib/generators/templates/helpers/partials/axe_driver.tt +0 -10
  224. data/lib/generators/templates/helpers/visual_spec_helper.tt +0 -35
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'thor'
4
+ require 'yaml'
5
+ require_relative 'name_normalizer'
6
+ require_relative 'project_detector'
4
7
 
5
8
  class Scaffolding < Thor::Group
6
9
  include Thor::Actions
@@ -8,28 +11,48 @@ class Scaffolding < Thor::Group
8
11
  argument :name, optional: true
9
12
  argument :path, optional: true
10
13
 
14
+ attr_writer :uses
15
+
16
+ OVERRIDE_DIR = '.ruby_raider/templates'
17
+
11
18
  def self.source_root
12
19
  "#{File.dirname(__FILE__)}/templates"
13
20
  end
14
21
 
22
+ # Check for user template override before using default
23
+ def template(source, *args, &block)
24
+ override = File.join(OVERRIDE_DIR, File.basename(source))
25
+ if File.exist?(override)
26
+ super(File.expand_path(override), *args, &block)
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ # --- Generation methods ---
33
+
15
34
  def generate_page
16
- template('page_object.tt', default_path("page_objects/pages/#{name}.rb", '_page.rb'))
35
+ template('page_object.tt', default_path("page_objects/pages/#{normalized_name}.rb", '_page.rb'))
17
36
  end
18
37
 
19
38
  def generate_feature
20
- template('feature.tt', default_path("features/#{name}.feature", '.feature'))
39
+ template('feature.tt', default_path("features/#{normalized_name}.feature", '.feature'))
21
40
  end
22
41
 
23
42
  def generate_spec
24
- template('spec.tt', default_path("spec/#{name}_page_spec.rb", '_spec.rb'))
43
+ template('spec.tt', default_path("spec/#{normalized_name}_page_spec.rb", '_spec.rb'))
25
44
  end
26
45
 
27
46
  def generate_helper
28
- template('helper.tt', default_path("helpers/#{name}_helper.rb", '_helper.rb'))
47
+ template('helper.tt', default_path("helpers/#{normalized_name}_helper.rb", '_helper.rb'))
29
48
  end
30
49
 
31
50
  def generate_steps
32
- template('steps.tt', default_path("features/step_definitions/#{name}_steps.rb", '_steps.rb'))
51
+ template('steps.tt', default_path("features/step_definitions/#{normalized_name}_steps.rb", '_steps.rb'))
52
+ end
53
+
54
+ def generate_component
55
+ template('component.tt', default_path("page_objects/components/#{normalized_name}.rb", '.rb'))
33
56
  end
34
57
 
35
58
  def generate_config
@@ -37,31 +60,155 @@ class Scaffolding < Thor::Group
37
60
  default_path('config/config.yml', '.yml'))
38
61
  end
39
62
 
63
+ def generate_spec_from_page(source_file, ai: false) # rubocop:disable Naming/MethodParameterName
64
+ require_relative 'page_introspector'
65
+ @introspected = PageIntrospector.new(source_file)
66
+ enrich_with_ai_scenarios if ai
67
+ template('spec_from_page.tt', "spec/#{normalized_name}_spec.rb")
68
+ end
69
+
70
+ def generate_page_from_url(analysis)
71
+ @url_data = analysis
72
+ template('page_from_url.tt', "page_objects/pages/#{normalized_name}.rb")
73
+ end
74
+
75
+ def generate_spec_from_url(analysis)
76
+ @url_data = analysis
77
+ template('spec_from_url.tt', "spec/#{normalized_name}_spec.rb")
78
+ end
79
+
80
+ # --- Deletion methods ---
81
+
40
82
  def delete_page
41
- remove_file(default_path("page_objects/pages/#{name}.rb", '_page.rb'))
83
+ remove_file(default_path("page_objects/pages/#{normalized_name}.rb", '_page.rb'))
42
84
  end
43
85
 
44
86
  def delete_feature
45
- remove_file(default_path("features/#{name}.feature", '.feature'))
87
+ remove_file(default_path("features/#{normalized_name}.feature", '.feature'))
46
88
  end
47
89
 
48
90
  def delete_spec
49
- remove_file(default_path("spec/#{name}_page_spec.rb", '_spec.rb'))
91
+ remove_file(default_path("spec/#{normalized_name}_page_spec.rb", '_spec.rb'))
50
92
  end
51
93
 
52
94
  def delete_helper
53
- remove_file(default_path("helpers/#{name}_helper.rb", '_helper.rb'))
95
+ remove_file(default_path("helpers/#{normalized_name}_helper.rb", '_helper.rb'))
54
96
  end
55
97
 
56
98
  def delete_steps
57
- remove_file(default_path("features/step_definitions/#{name}_steps.rb", '_steps.rb'))
99
+ remove_file(default_path("features/step_definitions/#{normalized_name}_steps.rb", '_steps.rb'))
100
+ end
101
+
102
+ def delete_component
103
+ remove_file(default_path("page_objects/components/#{normalized_name}.rb", '.rb'))
58
104
  end
59
105
 
60
106
  def delete_config
61
107
  remove_file(default_path('config/config.yml', '.yml'))
62
108
  end
63
109
 
110
+ # --- Path planning (for dry-run) ---
111
+
112
+ def self.planned_path(name, type, custom_path = nil)
113
+ n = NameNormalizer.normalize(name)
114
+ case type.to_s
115
+ when 'page' then custom_path ? "#{custom_path}/#{n}_page.rb" : "page_objects/pages/#{n}.rb"
116
+ when 'spec' then custom_path ? "#{custom_path}/#{n}_spec.rb" : "spec/#{n}_page_spec.rb"
117
+ when 'feature' then custom_path ? "#{custom_path}/#{n}.feature" : "features/#{n}.feature"
118
+ when 'steps' then custom_path ? "#{custom_path}/#{n}_steps.rb" : "features/step_definitions/#{n}_steps.rb"
119
+ when 'helper' then custom_path ? "#{custom_path}/#{n}_helper.rb" : "helpers/#{n}_helper.rb"
120
+ when 'component' then custom_path ? "#{custom_path}/#{n}.rb" : "page_objects/components/#{n}.rb"
121
+ when 'model' then "models/data/#{n}.yml"
122
+ end
123
+ end
124
+
125
+ # --- Template helpers (available in .tt files) ---
126
+
127
+ def class_name
128
+ NameNormalizer.to_class_name(name)
129
+ end
130
+
131
+ def page_class_name
132
+ NameNormalizer.to_page_class(name)
133
+ end
134
+
135
+ def normalized_name
136
+ NameNormalizer.normalize(name)
137
+ end
138
+
139
+ def nested?
140
+ NameNormalizer.nested?(name)
141
+ end
142
+
143
+ def module_parts
144
+ NameNormalizer.module_parts(name)
145
+ end
146
+
147
+ def leaf_name
148
+ NameNormalizer.leaf_name(name)
149
+ end
150
+
151
+ def automation_type
152
+ ScaffoldProjectDetector.detect_automation
153
+ end
154
+
155
+ def framework_type
156
+ ScaffoldProjectDetector.detect_framework
157
+ end
158
+
159
+ def project_config
160
+ ScaffoldProjectDetector.config
161
+ end
162
+
163
+ def selenium?
164
+ automation_type == 'selenium'
165
+ end
166
+
167
+ def capybara?
168
+ automation_type == 'capybara'
169
+ end
170
+
171
+ def watir?
172
+ automation_type == 'watir'
173
+ end
174
+
175
+ def uses_list
176
+ Array(@uses).reject(&:empty?)
177
+ end
178
+
179
+ attr_reader :introspected, :url_data
180
+
181
+ def ai_scenarios
182
+ @ai_scenarios || {}
183
+ end
184
+
64
185
  def default_path(standard_path, file_type)
65
- path ? "#{path}/#{name}#{file_type}" : standard_path
186
+ path ? "#{path}/#{normalized_name}#{file_type}" : standard_path
187
+ end
188
+
189
+ private
190
+
191
+ def enrich_with_ai_scenarios
192
+ require_relative '../llm/client'
193
+ require_relative '../llm/prompts'
194
+ require_relative '../llm/response_parser'
195
+
196
+ return unless Llm::Client.available?
197
+
198
+ response = Llm::Client.complete(
199
+ Llm::Prompts.generate_test_scenarios(
200
+ @introspected.class_name,
201
+ @introspected.methods,
202
+ automation_type,
203
+ framework_type
204
+ ),
205
+ system_prompt: Llm::Prompts.system_prompt
206
+ )
207
+ scenarios = Llm::ResponseParser.extract_scenarios(response)
208
+ return unless scenarios
209
+
210
+ @ai_scenarios = scenarios.each_with_object({}) do |s, hash|
211
+ hash[s[:method]] = s
212
+ end
66
213
  end
67
214
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../abstract/component'
4
+
5
+ class <%= class_name %> < Component
6
+ <%- if capybara? -%>
7
+
8
+ # Example: find('.selector').text
9
+ <%- elsif selenium? -%>
10
+
11
+ def content
12
+ component.text
13
+ end
14
+
15
+ private
16
+
17
+ # Elements
18
+ # Example: driver.find_element(css: '.selector')
19
+ <%- elsif watir? -%>
20
+
21
+ def content
22
+ component.text
23
+ end
24
+
25
+ private
26
+
27
+ # Elements
28
+ # Example: browser.element(css: '.selector')
29
+ <%- end -%>
30
+ end
@@ -1,6 +1,6 @@
1
- Feature: <%= name.capitalize %>
1
+ Feature: <%= class_name %>
2
2
 
3
3
  Scenario: Scenario name
4
- Given I am
5
- When I do
6
- Then I see
4
+ Given I am on the <%= normalized_name.tr('_', ' ') %> page
5
+ When I perform an action
6
+ Then I see the expected result
@@ -1,3 +1,17 @@
1
- module <%= name.split('_').map {|word| word.capitalize }.join + 'Helper' %>
1
+ # frozen_string_literal: true
2
+
3
+ <% if nested? -%>
4
+ <% module_parts.each_with_index do |mod, i| -%>
5
+ <%= ' ' * i %>module <%= mod %>
6
+ <% end -%>
7
+ <%= ' ' * module_parts.size %>module <%= NameNormalizer.to_class_name(leaf_name) %>Helper
8
+ <%= ' ' * module_parts.size %> # Add your helper code here
9
+ <%= ' ' * module_parts.size %>end
10
+ <% module_parts.each_with_index do |_mod, i| -%>
11
+ <%= ' ' * (module_parts.size - i - 1) %>end
12
+ <% end -%>
13
+ <% else -%>
14
+ module <%= class_name %>Helper
2
15
  # Add your helper code here
3
16
  end
17
+ <% end -%>
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../abstract/page'
4
+
5
+ class <%= page_class_name %> < Page
6
+ def url(_page)
7
+ '<%= url_data[:url_path] %>'
8
+ end
9
+
10
+ # Actions
11
+ <%- form_elements = url_data[:elements].select { |e| %i[input textarea select].include?(e[:type]) } -%>
12
+ <%- button_elements = url_data[:elements].select { |e| %i[button submit].include?(e[:type]) } -%>
13
+ <%- unless form_elements.empty? -%>
14
+
15
+ <%- if capybara? -%>
16
+ def fill_form(<%= form_elements.map { |e| e[:name] }.join(', ') %>)
17
+ <%- form_elements.each do |el| -%>
18
+ <%- if el[:locator][:type] == :id -%>
19
+ fill_in '<%= el[:locator][:value] %>', with: <%= el[:name] %>
20
+ <%- elsif el[:locator][:type] == :name -%>
21
+ fill_in '<%= el[:locator][:value] %>', with: <%= el[:name] %>
22
+ <%- else -%>
23
+ find('<%= el[:locator][:value] %>').set(<%= el[:name] %>)
24
+ <%- end -%>
25
+ <%- end -%>
26
+ end
27
+ <%- else -%>
28
+ def fill_form(<%= form_elements.map { |e| e[:name] }.join(', ') %>)
29
+ <%- form_elements.each do |el| -%>
30
+ <%= el[:name] %>_field.<%= selenium? ? 'send_keys' : 'set' %> <%= el[:name] %>
31
+ <%- end -%>
32
+ end
33
+ <%- end -%>
34
+ <%- end -%>
35
+ <%- unless button_elements.empty? -%>
36
+
37
+ <%- button_elements.each do |el| -%>
38
+ <%- if capybara? -%>
39
+ def click_<%= el[:name] %>
40
+ click_button '<%= el[:text] || el[:name] %>'
41
+ end
42
+ <%- else -%>
43
+ def click_<%= el[:name] %>
44
+ <%= el[:name] %>_button.click
45
+ end
46
+ <%- end -%>
47
+ <%- end -%>
48
+ <%- end -%>
49
+ <%- unless capybara? -%>
50
+
51
+ private
52
+
53
+ # Elements
54
+ <%- form_elements.each do |el| -%>
55
+
56
+ def <%= el[:name] %>_field
57
+ <%- if selenium? -%>
58
+ driver.find_element(<%= el[:locator][:type] %>: '<%= el[:locator][:value] %>')
59
+ <%- elsif watir? -%>
60
+ browser.<%= el[:type] == :select ? 'select' : 'text_field' %>(<%= el[:locator][:type] %>: '<%= el[:locator][:value] %>')
61
+ <%- end -%>
62
+ end
63
+ <%- end -%>
64
+ <%- button_elements.each do |el| -%>
65
+
66
+ def <%= el[:name] %>_button
67
+ <%- if selenium? -%>
68
+ driver.find_element(<%= el[:locator][:type] %>: '<%= el[:locator][:value] %>')
69
+ <%- elsif watir? -%>
70
+ browser.button(<%= el[:locator][:type] %>: '<%= el[:locator][:value] %>')
71
+ <%- end -%>
72
+ end
73
+ <%- end -%>
74
+ <%- end -%>
75
+ end
@@ -1,12 +1,61 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../abstract/page'
4
+ <%- uses_list.each do |dep| -%>
5
+ require_relative '<%= dep %>'
6
+ <%- end -%>
7
+ <% if nested? -%>
8
+ <% module_parts.each_with_index do |mod, i| -%>
9
+ <%= ' ' * i %>module <%= mod %>
10
+ <% end -%>
11
+ <%= ' ' * module_parts.size %>class <%= NameNormalizer.to_class_name(leaf_name) %>Page < Page
12
+ <%- if project_config['url'] -%>
13
+ <%= ' ' * module_parts.size %> def url(_page)
14
+ <%= ' ' * module_parts.size %> '<%= normalized_name %>'
15
+ <%= ' ' * module_parts.size %> end
16
+ <%- end -%>
4
17
 
5
- class <%= name.split('_').map {|word| word.capitalize }.join %> < Page
18
+ <%= ' ' * module_parts.size %> # Actions
19
+ <%- if capybara? -%>
20
+
21
+ <%= ' ' * module_parts.size %> # Example: fill_in 'field_id', with: value
22
+ <%- else -%>
23
+
24
+ <%= ' ' * module_parts.size %> private
25
+
26
+ <%= ' ' * module_parts.size %> # Elements
27
+ <%- if selenium? -%>
28
+ <%= ' ' * module_parts.size %> # Example: driver.find_element(id: 'element_id')
29
+ <%- elsif watir? -%>
30
+ <%= ' ' * module_parts.size %> # Example: browser.text_field(id: 'element_id')
31
+ <%- end -%>
32
+ <%- end -%>
33
+ <%= ' ' * module_parts.size %>end
34
+ <% module_parts.each_with_index do |_mod, i| -%>
35
+ <%= ' ' * (module_parts.size - i - 1) %>end
36
+ <% end -%>
37
+ <% else -%>
38
+ class <%= page_class_name %> < Page
39
+ <%- if project_config['url'] -%>
40
+ def url(_page)
41
+ '<%= normalized_name %>'
42
+ end
43
+ <%- end -%>
6
44
 
7
45
  # Actions
46
+ <%- if capybara? -%>
47
+
48
+ # Example: fill_in 'field_id', with: value
49
+ <%- else -%>
8
50
 
9
51
  private
10
52
 
11
53
  # Elements
54
+ <%- if selenium? -%>
55
+ # Example: driver.find_element(id: 'element_id')
56
+ <%- elsif watir? -%>
57
+ # Example: browser.text_field(id: 'element_id')
58
+ <%- end -%>
59
+ <%- end -%>
12
60
  end
61
+ <% end -%>
@@ -1,4 +1,35 @@
1
- require_relative '../page_objects/pages/<%= name %>'
1
+ # frozen_string_literal: true
2
2
 
3
- describe '<%= name.split('_').map {|word| word.capitalize }.join %>' do
3
+ require_relative '../page_objects/pages/<%= normalized_name %>'
4
+ <%- uses_list.each do |dep| -%>
5
+ require_relative '../page_objects/pages/<%= dep %>'
6
+ <%- end -%>
7
+
8
+ describe '<%= page_class_name %>' do
9
+ <%- if selenium? -%>
10
+ let(:page) { <%= page_class_name %>.new(driver) }
11
+ <%- elsif watir? -%>
12
+ let(:page) { <%= page_class_name %>.new(browser) }
13
+ <%- elsif capybara? -%>
14
+ let(:page) { <%= page_class_name %>.new }
15
+ <%- end -%>
16
+ <%- uses_list.each do |dep| -%>
17
+ let(:<%= dep %>) { <%= NameNormalizer.to_page_class(dep) %>.new<%= selenium? ? '(driver)' : watir? ? '(browser)' : '' %> }
18
+ <%- end -%>
19
+ <%- if project_config['url'] -%>
20
+
21
+ before do
22
+ <%- if capybara? -%>
23
+ visit '<%= normalized_name %>'
24
+ <%- elsif selenium? -%>
25
+ driver.navigate.to "\#{project_config['url']}/<%= normalized_name %>"
26
+ <%- elsif watir? -%>
27
+ browser.goto "\#{project_config['url']}/<%= normalized_name %>"
28
+ <%- end -%>
29
+ end
30
+ <%- end -%>
31
+
32
+ it 'loads successfully' do
33
+ pending 'implement test'
34
+ end
4
35
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../page_objects/pages/<%= normalized_name %>'
4
+
5
+ describe '<%= introspected.class_name %>' do
6
+ <%- if selenium? -%>
7
+ let(:page) { <%= introspected.class_name %>.new(driver) }
8
+ <%- elsif watir? -%>
9
+ let(:page) { <%= introspected.class_name %>.new(browser) }
10
+ <%- elsif capybara? -%>
11
+ let(:page) { <%= introspected.class_name %>.new }
12
+ <%- end -%>
13
+ <%- introspected.methods.each do |method| -%>
14
+ <%- scenario = ai_scenarios[method[:name]] -%>
15
+
16
+ describe '#<%= method[:name] %>' do
17
+ it '<%= scenario ? scenario[:description] : method[:name].tr("_", " ") %>' do
18
+ <%- if method[:params].empty? -%>
19
+ page.<%= method[:name] %>
20
+ <%- else -%>
21
+ page.<%= method[:name] %>(<%= method[:params].map { |p| "'#{p}'" }.join(', ') %>)
22
+ <%- end -%>
23
+ <%- if scenario && scenario[:assertion_hint] -%>
24
+ pending '<%= scenario[:assertion_hint] %>'
25
+ <%- else -%>
26
+ pending 'add assertions'
27
+ <%- end -%>
28
+ end
29
+ end
30
+ <%- end -%>
31
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../page_objects/pages/<%= normalized_name %>'
4
+
5
+ describe '<%= page_class_name %>' do
6
+ <%- if selenium? -%>
7
+ let(:page) { <%= page_class_name %>.new(driver) }
8
+ <%- elsif watir? -%>
9
+ let(:page) { <%= page_class_name %>.new(browser) }
10
+ <%- elsif capybara? -%>
11
+ let(:page) { <%= page_class_name %>.new }
12
+ <%- end -%>
13
+
14
+ before do
15
+ <%- if capybara? -%>
16
+ visit '<%= url_data[:url_path] %>'
17
+ <%- elsif selenium? -%>
18
+ driver.navigate.to '<%= url_data[:url] %>'
19
+ <%- elsif watir? -%>
20
+ browser.goto '<%= url_data[:url] %>'
21
+ <%- end -%>
22
+ end
23
+ <%- form_elements = url_data[:elements].select { |e| %i[input textarea select].include?(e[:type]) } -%>
24
+ <%- unless form_elements.empty? -%>
25
+
26
+ describe '#fill_form' do
27
+ it 'fills in the form fields' do
28
+ page.fill_form(<%= form_elements.map { |e| "'test_#{e[:name]}'" }.join(', ') %>)
29
+ pending 'add assertions'
30
+ end
31
+ end
32
+ <%- end -%>
33
+ <%- url_data[:elements].select { |e| %i[button submit].include?(e[:type]) }.each do |el| -%>
34
+
35
+ describe '#click_<%= el[:name] %>' do
36
+ it 'clicks the <%= el[:name].tr("_", " ") %> button' do
37
+ page.click_<%= el[:name] %>
38
+ pending 'add assertions'
39
+ end
40
+ end
41
+ <%- end -%>
42
+
43
+ it 'loads the page' do
44
+ pending 'add assertions'
45
+ end
46
+ end
@@ -1,12 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../page_objects/pages/<%= name %>'
3
+ require_relative '../../page_objects/pages/<%= normalized_name %>'
4
+ <%- uses_list.each do |dep| -%>
5
+ require_relative '../../page_objects/pages/<%= dep %>'
6
+ <%- end -%>
4
7
 
5
- Given ('') do
8
+ Given('I am on the <%= normalized_name.tr("_", " ") %> page') do
9
+ <%- if selenium? -%>
10
+ @page = <%= page_class_name %>.new(driver)
11
+ <%- elsif watir? -%>
12
+ @page = <%= page_class_name %>.new(browser)
13
+ <%- elsif capybara? -%>
14
+ visit '<%= normalized_name %>'
15
+ <%- end -%>
6
16
  end
7
17
 
8
- When ('') do
18
+ When('I perform an action') do
19
+ pending 'implement step'
9
20
  end
10
21
 
11
- Then ('') do
12
- end
22
+ Then('I see the expected result') do
23
+ pending 'implement step'
24
+ end