ruby_raider 3.0.0 → 3.1.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 (193) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/e2e_tests.yml +0 -17
  3. data/.github/workflows/system_tests.yml +0 -22
  4. data/README.md +8 -62
  5. data/lib/commands/scaffolding_commands.rb +22 -188
  6. data/lib/commands/utility_commands.rb +10 -44
  7. data/lib/generators/automation/templates/login.tt +1 -9
  8. data/lib/generators/automation/templates/page.tt +1 -7
  9. data/lib/generators/automation/templates/partials/initialize_selector.tt +1 -3
  10. data/lib/generators/automation/templates/partials/visit_method.tt +2 -6
  11. data/lib/generators/common_generator.rb +0 -6
  12. data/lib/generators/cucumber/cucumber_generator.rb +0 -24
  13. data/lib/generators/cucumber/templates/accessibility_steps.tt +2 -6
  14. data/lib/generators/cucumber/templates/cucumber.tt +0 -7
  15. data/lib/generators/cucumber/templates/env.tt +1 -3
  16. data/lib/generators/cucumber/templates/partials/appium_env.tt +1 -6
  17. data/lib/generators/cucumber/templates/partials/selenium_env.tt +0 -5
  18. data/lib/generators/cucumber/templates/partials/watir_env.tt +0 -5
  19. data/lib/generators/cucumber/templates/partials/web_steps.tt +4 -4
  20. data/lib/generators/cucumber/templates/world.tt +1 -3
  21. data/lib/generators/generator.rb +2 -46
  22. data/lib/generators/helper_generator.rb +4 -42
  23. data/lib/generators/infrastructure/templates/github.tt +2 -2
  24. data/lib/generators/infrastructure/templates/github_appium.tt +2 -6
  25. data/lib/generators/invoke_generators.rb +4 -25
  26. data/lib/generators/menu_generator.rb +10 -100
  27. data/lib/generators/rspec/rspec_generator.rb +0 -11
  28. data/lib/generators/rspec/templates/accessibility_spec.tt +2 -6
  29. data/lib/generators/rspec/templates/spec.tt +6 -8
  30. data/lib/generators/templates/common/gemfile.tt +0 -26
  31. data/lib/generators/templates/common/git_ignore.tt +0 -2
  32. data/lib/generators/templates/common/partials/mobile_config.tt +0 -4
  33. data/lib/generators/templates/common/partials/web_config.tt +0 -4
  34. data/lib/generators/templates/common/rakefile.tt +0 -9
  35. data/lib/generators/templates/common/read_me.tt +4 -10
  36. data/lib/generators/templates/helpers/allure_helper.tt +0 -10
  37. data/lib/generators/templates/helpers/browser_helper.tt +1 -1
  38. data/lib/generators/templates/helpers/partials/debug_diagnostics.tt +1 -3
  39. data/lib/generators/templates/helpers/partials/debug_start.tt +1 -3
  40. data/lib/generators/templates/helpers/partials/quit_driver.tt +1 -3
  41. data/lib/generators/templates/helpers/partials/screenshot.tt +1 -3
  42. data/lib/generators/templates/helpers/partials/selenium_driver.tt +1 -1
  43. data/lib/generators/templates/helpers/spec_helper.tt +2 -39
  44. data/lib/ruby_raider.rb +2 -50
  45. data/lib/scaffolding/project_detector.rb +30 -13
  46. data/lib/scaffolding/scaffolding.rb +0 -109
  47. data/lib/scaffolding/templates/component.tt +1 -4
  48. data/lib/scaffolding/templates/page_object.tt +0 -10
  49. data/lib/scaffolding/templates/spec.tt +2 -6
  50. data/lib/scaffolding/templates/steps.tt +0 -2
  51. data/lib/utilities/utilities.rb +26 -24
  52. data/lib/version +1 -1
  53. data/sig/commands/scaffolding_commands.rbs +0 -12
  54. data/sig/commands/utility_commands.rbs +0 -6
  55. data/sig/generators/cucumber/cucumber_generator.rbs +0 -4
  56. data/sig/generators/generator.rbs +0 -11
  57. data/sig/generators/helper_generator.rbs +1 -5
  58. data/sig/generators/invoke_generators.rbs +1 -2
  59. data/sig/generators/menu_generator.rbs +2 -6
  60. data/sig/generators/rspec/rspec_generator.rbs +0 -2
  61. data/sig/ruby_raider.rbs +1 -3
  62. data/sig/scaffolding/project_detector.rbs +0 -1
  63. data/sig/scaffolding/scaffolding.rbs +0 -23
  64. data/sig/utilities/utilities.rbs +0 -4
  65. data/spec/commands/raider_commands_spec.rb +0 -61
  66. data/spec/commands/scaffolding_commands_spec.rb +22 -0
  67. data/spec/integration/commands/browser_update_after_creation_spec.rb +123 -0
  68. data/spec/integration/commands/scaffolding_commands_spec.rb +0 -20
  69. data/spec/integration/commands/utility_commands_spec.rb +9 -9
  70. data/spec/integration/content/ci_content_spec.rb +6 -61
  71. data/spec/integration/content/common_content_spec.rb +0 -64
  72. data/spec/integration/content/config_content_spec.rb +1 -51
  73. data/spec/integration/content/content_helper.rb +2 -2
  74. data/spec/integration/content/gemfile_content_spec.rb +0 -71
  75. data/spec/integration/content/helper_content_spec.rb +4 -240
  76. data/spec/integration/content/page_content_spec.rb +0 -89
  77. data/spec/integration/content/syntax_validation_spec.rb +2 -2
  78. data/spec/integration/content/test_content_spec.rb +0 -119
  79. data/spec/integration/end_to_end_features_spec.rb +13 -411
  80. data/spec/integration/end_to_end_spec.rb +0 -96
  81. data/spec/integration/generators/axe_addon_spec.rb +2 -52
  82. data/spec/integration/generators/common_generator_spec.rb +1 -13
  83. data/spec/integration/generators/config_features_spec.rb +3 -81
  84. data/spec/integration/generators/debug_helper_spec.rb +0 -20
  85. data/spec/integration/generators/github_generator_spec.rb +5 -15
  86. data/spec/integration/generators/helpers_generator_spec.rb +0 -37
  87. data/spec/integration/scaffolding_e2e_spec.rb +540 -0
  88. data/spec/integration/settings_helper.rb +1 -3
  89. data/spec/integration/spec_helper.rb +6 -11
  90. data/spec/menus/menu_generator_spec.rb +4 -107
  91. data/spec/scaffolding/scaffold_project_detector_spec.rb +42 -26
  92. data/spec/scaffolding/scaffolding_features_spec.rb +0 -183
  93. data/spec/system/selenium_spec.rb +1 -4
  94. data/spec/system/support/system_test_helper.rb +0 -1
  95. data/spec/system/watir_spec.rb +1 -4
  96. data/spec/utilities/headless_config_spec.rb +82 -0
  97. data/spec/utilities/utilities_spec.rb +105 -0
  98. metadata +7 -97
  99. data/lib/adopter/adopt_menu.rb +0 -146
  100. data/lib/adopter/converters/base_converter.rb +0 -84
  101. data/lib/adopter/converters/identity_converter.rb +0 -53
  102. data/lib/adopter/migration_plan.rb +0 -74
  103. data/lib/adopter/migrator.rb +0 -96
  104. data/lib/adopter/plan_builder.rb +0 -275
  105. data/lib/adopter/project_analyzer.rb +0 -252
  106. data/lib/adopter/project_detector.rb +0 -157
  107. data/lib/generators/cucumber/templates/partials/capybara_env.tt +0 -38
  108. data/lib/generators/cucumber/templates/partials/capybara_world.tt +0 -6
  109. data/lib/generators/cucumber/templates/performance_feature.tt +0 -5
  110. data/lib/generators/cucumber/templates/performance_steps.tt +0 -17
  111. data/lib/generators/cucumber/templates/visual_feature.tt +0 -5
  112. data/lib/generators/cucumber/templates/visual_steps.tt +0 -19
  113. data/lib/generators/infrastructure/gitlab_generator.rb +0 -11
  114. data/lib/generators/infrastructure/templates/gitlab.tt +0 -46
  115. data/lib/generators/minitest/minitest_generator.rb +0 -35
  116. data/lib/generators/minitest/templates/accessibility_test.tt +0 -26
  117. data/lib/generators/minitest/templates/performance_test.tt +0 -18
  118. data/lib/generators/minitest/templates/test.tt +0 -64
  119. data/lib/generators/minitest/templates/visual_test.tt +0 -23
  120. data/lib/generators/rspec/templates/performance_spec.tt +0 -18
  121. data/lib/generators/rspec/templates/visual_spec.tt +0 -20
  122. data/lib/generators/templates/helpers/capybara_helper.tt +0 -32
  123. data/lib/generators/templates/helpers/performance_helper.tt +0 -57
  124. data/lib/generators/templates/helpers/visual_helper.tt +0 -58
  125. data/lib/llm/client.rb +0 -79
  126. data/lib/llm/config.rb +0 -57
  127. data/lib/llm/prompts.rb +0 -84
  128. data/lib/llm/provider.rb +0 -27
  129. data/lib/llm/providers/anthropic_provider.rb +0 -43
  130. data/lib/llm/providers/ollama_provider.rb +0 -56
  131. data/lib/llm/providers/openai_provider.rb +0 -42
  132. data/lib/llm/response_parser.rb +0 -67
  133. data/lib/plugin/plugin.rb +0 -111
  134. data/lib/plugin/plugin_exposer.rb +0 -55
  135. data/lib/scaffolding/crud_generator.rb +0 -94
  136. data/lib/scaffolding/dry_run_presenter.rb +0 -16
  137. data/lib/scaffolding/page_introspector.rb +0 -45
  138. data/lib/scaffolding/scaffold_menu.rb +0 -103
  139. data/lib/scaffolding/templates/page_from_url.tt +0 -75
  140. data/lib/scaffolding/templates/spec_from_page.tt +0 -31
  141. data/lib/scaffolding/templates/spec_from_url.tt +0 -46
  142. data/lib/scaffolding/url_analyzer.rb +0 -179
  143. data/sig/adopter/adopt_menu.rbs +0 -25
  144. data/sig/adopter/converters/base_converter.rbs +0 -23
  145. data/sig/adopter/converters/identity_converter.rbs +0 -16
  146. data/sig/adopter/migration_plan.rbs +0 -34
  147. data/sig/adopter/migrator.rbs +0 -21
  148. data/sig/adopter/plan_builder.rbs +0 -38
  149. data/sig/adopter/project_analyzer.rbs +0 -39
  150. data/sig/adopter/project_detector.rbs +0 -26
  151. data/sig/generators/infrastructure/gitlab_generator.rbs +0 -4
  152. data/sig/generators/minitest/minitest_generator.rbs +0 -8
  153. data/sig/llm/client.rbs +0 -15
  154. data/sig/llm/config.rbs +0 -20
  155. data/sig/llm/prompts.rbs +0 -8
  156. data/sig/llm/provider.rbs +0 -12
  157. data/sig/llm/providers/anthropic_provider.rbs +0 -16
  158. data/sig/llm/providers/ollama_provider.rbs +0 -18
  159. data/sig/llm/providers/openai_provider.rbs +0 -16
  160. data/sig/llm/response_parser.rbs +0 -13
  161. data/sig/plugin/plugin.rbs +0 -24
  162. data/sig/plugin/plugin_exposer.rbs +0 -20
  163. data/sig/scaffolding/crud_generator.rbs +0 -16
  164. data/sig/scaffolding/dry_run_presenter.rbs +0 -4
  165. data/sig/scaffolding/page_introspector.rbs +0 -14
  166. data/sig/scaffolding/scaffold_menu.rbs +0 -18
  167. data/sig/scaffolding/url_analyzer.rbs +0 -28
  168. data/spec/adopter/adopt_menu_spec.rb +0 -176
  169. data/spec/adopter/converters/identity_converter_spec.rb +0 -145
  170. data/spec/adopter/migration_plan_spec.rb +0 -113
  171. data/spec/adopter/migrator_spec.rb +0 -277
  172. data/spec/adopter/plan_builder_spec.rb +0 -298
  173. data/spec/adopter/project_analyzer_spec.rb +0 -337
  174. data/spec/adopter/project_detector_spec.rb +0 -295
  175. data/spec/generators/generator_spec.rb +0 -23
  176. data/spec/integration/content/reporter_content_spec.rb +0 -236
  177. data/spec/integration/content/skip_flags_content_spec.rb +0 -206
  178. data/spec/integration/generators/gitlab_generator_spec.rb +0 -38
  179. data/spec/integration/generators/lighthouse_addon_spec.rb +0 -132
  180. data/spec/integration/generators/minitest_generator_spec.rb +0 -64
  181. data/spec/integration/generators/reporter_spec.rb +0 -159
  182. data/spec/integration/generators/skip_flags_spec.rb +0 -134
  183. data/spec/integration/generators/visual_addon_spec.rb +0 -148
  184. data/spec/llm/client_spec.rb +0 -79
  185. data/spec/llm/config_spec.rb +0 -92
  186. data/spec/llm/prompts_spec.rb +0 -49
  187. data/spec/llm/response_parser_spec.rb +0 -92
  188. data/spec/menus/adopter_adopt_menu_spec.rb +0 -97
  189. data/spec/scaffolding/page_introspector_spec.rb +0 -82
  190. data/spec/scaffolding/url_analyzer_spec.rb +0 -110
  191. data/spec/system/adopt_matrix_spec.rb +0 -537
  192. data/spec/system/adopt_spec.rb +0 -225
  193. data/spec/system/capybara_spec.rb +0 -42
@@ -13,22 +13,10 @@ class Scaffolding < Thor::Group
13
13
 
14
14
  attr_writer :uses
15
15
 
16
- OVERRIDE_DIR = '.ruby_raider/templates'
17
-
18
16
  def self.source_root
19
17
  "#{File.dirname(__FILE__)}/templates"
20
18
  end
21
19
 
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
20
  # --- Generation methods ---
33
21
 
34
22
  def generate_page
@@ -60,68 +48,6 @@ class Scaffolding < Thor::Group
60
48
  default_path('config/config.yml', '.yml'))
61
49
  end
62
50
 
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
-
82
- def delete_page
83
- remove_file(default_path("page_objects/pages/#{normalized_name}.rb", '_page.rb'))
84
- end
85
-
86
- def delete_feature
87
- remove_file(default_path("features/#{normalized_name}.feature", '.feature'))
88
- end
89
-
90
- def delete_spec
91
- remove_file(default_path("spec/#{normalized_name}_page_spec.rb", '_spec.rb'))
92
- end
93
-
94
- def delete_helper
95
- remove_file(default_path("helpers/#{normalized_name}_helper.rb", '_helper.rb'))
96
- end
97
-
98
- def delete_steps
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'))
104
- end
105
-
106
- def delete_config
107
- remove_file(default_path('config/config.yml', '.yml'))
108
- end
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
51
  # --- Template helpers (available in .tt files) ---
126
52
 
127
53
  def class_name
@@ -164,10 +90,6 @@ class Scaffolding < Thor::Group
164
90
  automation_type == 'selenium'
165
91
  end
166
92
 
167
- def capybara?
168
- automation_type == 'capybara'
169
- end
170
-
171
93
  def watir?
172
94
  automation_type == 'watir'
173
95
  end
@@ -176,39 +98,8 @@ class Scaffolding < Thor::Group
176
98
  Array(@uses).reject(&:empty?)
177
99
  end
178
100
 
179
- attr_reader :introspected, :url_data
180
-
181
- def ai_scenarios
182
- @ai_scenarios || {}
183
- end
184
-
185
101
  def default_path(standard_path, file_type)
186
102
  path ? "#{path}/#{normalized_name}#{file_type}" : standard_path
187
103
  end
188
104
 
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
213
- end
214
105
  end
@@ -3,10 +3,7 @@
3
3
  require_relative '../abstract/component'
4
4
 
5
5
  class <%= class_name %> < Component
6
- <%- if capybara? -%>
7
-
8
- # Example: find('.selector').text
9
- <%- elsif selenium? -%>
6
+ <%- if selenium? -%>
10
7
 
11
8
  def content
12
9
  component.text
@@ -16,10 +16,6 @@ require_relative '<%= dep %>'
16
16
  <%- end -%>
17
17
 
18
18
  <%= ' ' * module_parts.size %> # Actions
19
- <%- if capybara? -%>
20
-
21
- <%= ' ' * module_parts.size %> # Example: fill_in 'field_id', with: value
22
- <%- else -%>
23
19
 
24
20
  <%= ' ' * module_parts.size %> private
25
21
 
@@ -29,7 +25,6 @@ require_relative '<%= dep %>'
29
25
  <%- elsif watir? -%>
30
26
  <%= ' ' * module_parts.size %> # Example: browser.text_field(id: 'element_id')
31
27
  <%- end -%>
32
- <%- end -%>
33
28
  <%= ' ' * module_parts.size %>end
34
29
  <% module_parts.each_with_index do |_mod, i| -%>
35
30
  <%= ' ' * (module_parts.size - i - 1) %>end
@@ -43,10 +38,6 @@ class <%= page_class_name %> < Page
43
38
  <%- end -%>
44
39
 
45
40
  # Actions
46
- <%- if capybara? -%>
47
-
48
- # Example: fill_in 'field_id', with: value
49
- <%- else -%>
50
41
 
51
42
  private
52
43
 
@@ -56,6 +47,5 @@ class <%= page_class_name %> < Page
56
47
  <%- elsif watir? -%>
57
48
  # Example: browser.text_field(id: 'element_id')
58
49
  <%- end -%>
59
- <%- end -%>
60
50
  end
61
51
  <% end -%>
@@ -10,18 +10,14 @@ describe '<%= page_class_name %>' do
10
10
  let(:page) { <%= page_class_name %>.new(driver) }
11
11
  <%- elsif watir? -%>
12
12
  let(:page) { <%= page_class_name %>.new(browser) }
13
- <%- elsif capybara? -%>
14
- let(:page) { <%= page_class_name %>.new }
15
13
  <%- end -%>
16
14
  <%- uses_list.each do |dep| -%>
17
- let(:<%= dep %>) { <%= NameNormalizer.to_page_class(dep) %>.new<%= selenium? ? '(driver)' : watir? ? '(browser)' : '' %> }
15
+ let(:<%= dep %>) { <%= NameNormalizer.to_page_class(dep) %>.new<%= selenium? ? '(driver)' : '(browser)' %> }
18
16
  <%- end -%>
19
17
  <%- if project_config['url'] -%>
20
18
 
21
19
  before do
22
- <%- if capybara? -%>
23
- visit '<%= normalized_name %>'
24
- <%- elsif selenium? -%>
20
+ <%- if selenium? -%>
25
21
  driver.navigate.to "\#{project_config['url']}/<%= normalized_name %>"
26
22
  <%- elsif watir? -%>
27
23
  browser.goto "\#{project_config['url']}/<%= normalized_name %>"
@@ -10,8 +10,6 @@ Given('I am on the <%= normalized_name.tr("_", " ") %> page') do
10
10
  @page = <%= page_class_name %>.new(driver)
11
11
  <%- elsif watir? -%>
12
12
  @page = <%= page_class_name %>.new(browser)
13
- <%- elsif capybara? -%>
14
- visit '<%= normalized_name %>'
15
13
  <%- end -%>
16
14
  end
17
15
 
@@ -7,7 +7,7 @@ module Utilities
7
7
 
8
8
  class << self
9
9
  def browser=(browser)
10
- set('browser', browser)
10
+ set('browser', browser.to_s.delete_prefix(':'))
11
11
  end
12
12
 
13
13
  def page_path=(path)
@@ -44,40 +44,36 @@ module Utilities
44
44
  end
45
45
 
46
46
  def browser_options=(opts)
47
- set('browser_options', Array(opts).flatten)
47
+ reload_config
48
+ browser_name = @config['browser'] || 'chrome'
49
+ @config['browser_arguments'] ||= {}
50
+ @config['browser_arguments'][browser_name] = Array(opts).flatten
51
+ overwrite_yaml
48
52
  end
49
53
 
50
54
  def delete_browser_options
51
- config.delete('browser_options')
55
+ reload_config
56
+ browser_name = @config['browser'] || 'chrome'
57
+ @config['browser_arguments']&.delete(browser_name)
52
58
  overwrite_yaml
53
59
  end
54
60
 
55
- def llm_provider=(provider)
56
- set('llm_provider', provider)
57
- end
58
-
59
- def llm_api_key=(key)
60
- set('llm_api_key', key)
61
- end
62
-
63
- def llm_model=(model)
64
- set('llm_model', model)
65
- end
66
-
67
- def llm_url=(url)
68
- set('llm_url', url)
61
+ def headless=(enabled)
62
+ set('headless', enabled)
69
63
  end
70
64
 
71
65
  def debug=(enabled)
72
- config['debug'] ||= {}
73
- config['debug']['enabled'] = enabled
66
+ reload_config
67
+ @config['debug'] ||= {}
68
+ @config['debug']['enabled'] = enabled
74
69
  overwrite_yaml
75
70
  end
76
71
 
77
72
  # Set multiple config keys in a single YAML write.
78
73
  # Usage: Utilities.batch_update(browser: 'chrome', timeout: 30)
79
74
  def batch_update(**settings)
80
- settings.each { |key, value| config[key.to_s] = value }
75
+ reload_config
76
+ settings.each { |key, value| @config[key.to_s] = value }
81
77
  overwrite_yaml
82
78
  end
83
79
 
@@ -93,18 +89,24 @@ module Utilities
93
89
 
94
90
  private
95
91
 
96
- # Single-key setter: updates in-memory config and writes once
92
+ # Single-key setter: reloads from disk, updates, and writes back
97
93
  def set(key, value)
98
- config[key] = value
94
+ reload_config
95
+ @config[key] = value
99
96
  overwrite_yaml
100
97
  end
101
98
 
102
99
  def overwrite_yaml
103
- File.open(@path, 'w') { |file| YAML.dump(config, file) }
100
+ File.open(@path, 'w') { |file| YAML.dump(@config, file) }
101
+ end
102
+
103
+ # Always reload from disk so external changes (e.g. desktop app) are picked up
104
+ def reload_config
105
+ @config = File.exist?(@path) ? YAML.load_file(@path) : {}
104
106
  end
105
107
 
106
108
  def config
107
- @config ||= File.exist?(@path) ? YAML.load_file(@path) : nil
109
+ @config || reload_config
108
110
  end
109
111
  end
110
112
  end
data/lib/version CHANGED
@@ -1 +1 @@
1
- 3.0.0
1
+ 3.1.0
@@ -7,22 +7,10 @@ class ScaffoldingCommands < Thor
7
7
  def steps: (String name) -> void
8
8
  def component: (String name) -> void
9
9
  def scaffold: (*String names) -> void
10
- def destroy: (*String names) -> void
11
- def from_url: (String url) -> void
12
10
 
13
11
  private
14
12
 
15
13
  def load_config_path: (String type) -> String?
16
- def delete_scaffolding: (String name, String type) -> void
17
14
  def generate_scaffolding: (String name, String type, String? path, ?uses: Array[String]?) -> void
18
- def dry_run_preview: (String name, String type) -> void
19
15
  def generate_default_scaffold: (String name) -> void
20
- def generate_selected_components: (String name, Array[String] components) -> void
21
- def generate_crud: (String name) -> void
22
- def generate_spec_from_page: (String name, String source_file, ?ai: bool) -> void
23
- def generate_model_data: (String name) -> void
24
- def model_template: (String name) -> String
25
- def destroy_scaffold: (String name, ?Array[String]? components) -> void
26
- def detect_scaffold_types: () -> Array[String]
27
- def interactive_scaffold: () -> void
28
16
  end
@@ -12,10 +12,4 @@ class UtilityCommands < Thor
12
12
  def debug: (String toggle) -> void
13
13
  def start_appium: () -> void
14
14
  def desktop: () -> void
15
- def llm: (?String? provider) -> void
16
-
17
- private
18
-
19
- def configure_llm: (String provider) -> void
20
- def show_llm_status: () -> void
21
15
  end
@@ -6,11 +6,7 @@ class CucumberGenerator < Generator
6
6
  def generate_env_file: () -> void
7
7
  def generate_world: () -> void
8
8
  def generate_cucumber_file: () -> void
9
- def generate_visual_feature: () -> void
10
- def generate_visual_steps: () -> void
11
9
  def generate_accessibility_feature: () -> void
12
10
  def generate_accessibility_steps: () -> void
13
- def generate_performance_feature: () -> void
14
- def generate_performance_steps: () -> void
15
11
  def template_name: () -> String
16
12
  end
@@ -15,24 +15,13 @@ class Generator < Thor::Group
15
15
  def ios?: () -> bool
16
16
  def android?: () -> bool
17
17
  def rspec?: () -> bool
18
- def minitest?: () -> bool
19
18
  def selenium?: () -> bool
20
- def capybara?: () -> bool
21
19
  def watir?: () -> bool
22
20
  def web?: () -> bool
23
21
  def selenium_based?: () -> bool
24
22
 
25
23
  # Add-on predicates
26
24
  def axe_addon?: () -> bool
27
- def visual_addon?: () -> bool
28
- def lighthouse_addon?: () -> bool
29
-
30
- # Skip/reporter predicates
31
- def skip_allure?: () -> bool
32
- def skip_video?: () -> bool
33
- def allure_reporter?: () -> bool
34
- def junit_reporter?: () -> bool
35
- def json_reporter?: () -> bool
36
25
 
37
26
  private
38
27
 
@@ -5,14 +5,10 @@ class HelpersGenerator < Generator
5
5
  private
6
6
 
7
7
  def generate_allure_helper: () -> void
8
- def generate_video_helper: () -> void
8
+
9
9
  def generate_browser_helper: () -> void
10
10
  def generate_spec_helper: () -> void
11
11
  def generate_driver_helper: () -> void
12
- def generate_capybara_helper: () -> void
13
12
  def generate_appium_helper: () -> void
14
- def generate_test_helper: () -> void
15
13
  def generate_debug_helper: () -> void
16
- def generate_visual_helper: () -> void
17
- def generate_performance_helper: () -> void
18
14
  end
@@ -3,8 +3,7 @@ module InvokeGenerators
3
3
  def self?.generate_framework: (?Hash[Symbol, untyped] structure) -> void
4
4
  def self?.add_generator: (Array[String] generators, *String gens) -> void
5
5
  def self?.invoke_generator: (?Hash[Symbol, untyped] structure) -> void
6
- def self?.collect_skip_flags: (Hash[Symbol, untyped] structure) -> Array[String]
7
- def self?.reporter_flags: (String? reporter) -> Array[String]
6
+ def self?.collect_flags: (Hash[Symbol, untyped] structure) -> Array[String]
8
7
  def self?.mobile_automation?: (String automation) -> bool
9
8
  def self?.to_bool: (String? string) -> bool?
10
9
  end
@@ -16,14 +16,10 @@ class MenuGenerator
16
16
  def offer_desktop_download: () -> void
17
17
  def select_test_framework: (String automation) -> void
18
18
  def create_framework_options: (Hash[Symbol, untyped] params) -> untyped
19
- def select_reporter: (String framework, String automation_type, ?String? ci_platform) -> void
20
- def select_accessibility: (String framework, String automation_type, ?String? ci_platform, ?String? reporter) -> void
21
- def select_visual: (String framework, String automation_type, ?String? ci_platform, ?String? reporter, ?bool accessibility) -> void
22
- def select_performance: (String framework, String automation_type, ?String? ci_platform, ?String? reporter, ?bool accessibility, ?bool visual) -> void
19
+ def select_accessibility: (String framework, String automation_type) -> void
23
20
  def mobile_automation?: (String automation_type) -> bool
24
- def create_framework: (String framework, String automation_type, ?String? ci_platform, ?String? reporter, ?bool accessibility, ?bool visual, ?bool performance) -> void
21
+ def create_framework: (String framework, String automation_type, ?accessibility: bool) -> void
25
22
  def yes_no_menu_choices: () -> Hash[Symbol, Proc]
26
23
  def select_automation_framework: (untyped menu) -> void
27
24
  def automation_options: (untyped menu) -> void
28
- def select_ci_platform: (String framework, String automation) -> void
29
25
  end
@@ -2,7 +2,5 @@
2
2
  class RspecGenerator < Generator
3
3
  def generate_login_spec: () -> void
4
4
  def generate_pdp_spec: () -> void
5
- def generate_visual_spec: () -> void
6
5
  def generate_accessibility_spec: () -> void
7
- def generate_performance_spec: () -> void
8
6
  end
data/sig/ruby_raider.rbs CHANGED
@@ -1,15 +1,13 @@
1
1
  # Type definitions for main RubyRaider entry point
2
2
  module RubyRaider
3
3
  class Raider < Thor
4
- def self.plugin_commands?: () -> bool
5
4
  def current_version: () -> String
6
5
 
7
6
  def new: (String project_name) -> void
8
7
  def version: () -> void
9
- def adopt: () -> void
10
8
 
11
9
  private
12
10
 
13
- def merge_skip_flags: (Hash[Symbol, untyped] params) -> void
11
+ def merge_flags: (Hash[Symbol, untyped] params) -> void
14
12
  end
15
13
  end
@@ -8,7 +8,6 @@ module ScaffoldProjectDetector
8
8
  def self?.detect_framework: (?String? gemfile) -> String
9
9
  def self?.read_gemfile: () -> String
10
10
  def self?.selenium?: () -> bool
11
- def self?.capybara?: () -> bool
12
11
  def self?.watir?: () -> bool
13
12
  def self?.config: () -> Hash[String, untyped]
14
13
  end
@@ -2,12 +2,9 @@
2
2
  class Scaffolding < Thor::Group
3
3
  include Thor::Actions
4
4
 
5
- OVERRIDE_DIR: String
6
-
7
5
  attr_writer uses: Array[String]
8
6
 
9
7
  def self.source_root: () -> String
10
- def self.planned_path: (String name, String type, ?String? custom_path) -> String?
11
8
 
12
9
  # Generation methods
13
10
  def generate_page: () -> void
@@ -17,18 +14,6 @@ class Scaffolding < Thor::Group
17
14
  def generate_steps: () -> void
18
15
  def generate_component: () -> void
19
16
  def generate_config: () -> void
20
- def generate_spec_from_page: (String source_file, ?ai: bool) -> void
21
- def generate_page_from_url: (Hash[Symbol, untyped] analysis) -> void
22
- def generate_spec_from_url: (Hash[Symbol, untyped] analysis) -> void
23
-
24
- # Deletion methods
25
- def delete_page: () -> void
26
- def delete_feature: () -> void
27
- def delete_spec: () -> void
28
- def delete_helper: () -> void
29
- def delete_steps: () -> void
30
- def delete_component: () -> void
31
- def delete_config: () -> void
32
17
 
33
18
  # Template helpers
34
19
  def class_name: () -> String?
@@ -41,15 +26,7 @@ class Scaffolding < Thor::Group
41
26
  def framework_type: () -> String
42
27
  def project_config: () -> Hash[String, untyped]
43
28
  def selenium?: () -> bool
44
- def capybara?: () -> bool
45
29
  def watir?: () -> bool
46
30
  def uses_list: () -> Array[String]
47
- def introspected: () -> PageIntrospector?
48
- def url_data: () -> Hash[Symbol, untyped]?
49
- def ai_scenarios: () -> Hash[Symbol, untyped]
50
31
  def default_path: (String standard_path, String file_type) -> String
51
-
52
- private
53
-
54
- def enrich_with_ai_scenarios: () -> void
55
32
  end
@@ -13,10 +13,6 @@ module Utilities
13
13
  def self?.platform=: (String platform) -> void
14
14
  def self?.browser_options=: (Array[String] opts) -> void
15
15
  def self?.delete_browser_options: () -> void
16
- def self?.llm_provider=: (String provider) -> void
17
- def self?.llm_api_key=: (String key) -> void
18
- def self?.llm_model=: (String model) -> void
19
- def self?.llm_url=: (String url) -> void
20
16
  def self?.debug=: (bool enabled) -> void
21
17
  def self?.batch_update: (**untyped settings) -> void
22
18
  def self?.run: (?String? opts) -> void
@@ -45,10 +45,6 @@ RSpec.describe RubyRaider::Raider do
45
45
  expect(described_class.map['v']).to eq('version')
46
46
  end
47
47
 
48
- it 'maps a to adopt' do
49
- expect(described_class.map['a']).to eq('adopt')
50
- end
51
-
52
48
  it 'maps g to generate' do
53
49
  expect(described_class.map['g']).to eq('generate')
54
50
  end
@@ -56,19 +52,11 @@ RSpec.describe RubyRaider::Raider do
56
52
  it 'maps u to utility' do
57
53
  expect(described_class.map['u']).to eq('utility')
58
54
  end
59
-
60
- it 'maps pm to plugin_manager' do
61
- expect(described_class.map['pm']).to eq('plugin_manager')
62
- end
63
55
  end
64
56
 
65
57
  describe 'registered subcommands' do
66
58
  let(:subcommands) { described_class.subcommands }
67
59
 
68
- it 'includes adopt' do
69
- expect(subcommands).to include('adopt')
70
- end
71
-
72
60
  it 'includes generate' do
73
61
  expect(subcommands).to include('generate')
74
62
  end
@@ -76,54 +64,5 @@ RSpec.describe RubyRaider::Raider do
76
64
  it 'includes utility' do
77
65
  expect(subcommands).to include('utility')
78
66
  end
79
-
80
- it 'includes plugin_manager' do
81
- expect(subcommands).to include('plugin_manager')
82
- end
83
- end
84
- end
85
-
86
- RSpec.describe AdoptCommands do
87
- let(:source_dir) { 'tmp_cmd_adopt_source' }
88
- let(:output_dir) { 'tmp_cmd_adopt_output' }
89
-
90
- before do
91
- FileUtils.mkdir_p(source_dir)
92
- File.write("#{source_dir}/Gemfile", "gem 'rspec'\ngem 'selenium-webdriver'\n")
93
- FileUtils.mkdir_p("#{source_dir}/spec")
94
- end
95
-
96
- after do
97
- FileUtils.rm_rf(source_dir)
98
- FileUtils.rm_rf(output_dir)
99
- end
100
-
101
- describe 'project command with parameters' do
102
- it 'calls AdoptMenu.adopt with parsed params' do
103
- result = { plan: double(warnings: [], output_path: output_dir), results: { pages: 0, tests: 0, features: 0, steps: 0, errors: [] } } # rubocop:disable RSpec/VerifiedDoubles
104
- allow(Adopter::AdoptMenu).to receive(:adopt).and_return(result)
105
-
106
- expect do
107
- described_class.new.invoke(:project, nil, [source_dir, '-p',
108
- "output_path:#{output_dir}",
109
- 'target_automation:selenium',
110
- 'target_framework:rspec'])
111
- end.to output(/Adoption complete/).to_stdout
112
-
113
- expect(Adopter::AdoptMenu).to have_received(:adopt).with(
114
- hash_including(source_path: source_dir, target_automation: 'selenium', target_framework: 'rspec')
115
- )
116
- end
117
- end
118
-
119
- describe 'project command without parameters' do
120
- it 'calls AdoptMenu#run' do
121
- menu = instance_double(Adopter::AdoptMenu, run: nil)
122
- allow(Adopter::AdoptMenu).to receive(:new).and_return(menu)
123
-
124
- described_class.new.invoke(:project, nil, [source_dir])
125
-
126
- expect(menu).to have_received(:run)
127
- end
128
67
  end
129
68
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ RSpec.describe 'ScaffoldingCommands' do
6
+ describe 'dependencies' do
7
+ it 'loads without relying on transitive requires for Pathname' do
8
+ # Loads the file in a clean Ruby process where nothing else has required 'pathname'.
9
+ # This catches the exact bug where Pathname is used but never explicitly required,
10
+ # which works in test suites (rspec loads pathname transitively) but crashes at runtime.
11
+ script = <<~RUBY
12
+ require_relative '../../lib/commands/scaffolding_commands'
13
+ puts 'OK'
14
+ RUBY
15
+
16
+ stdout, stderr, status = Open3.capture3('ruby', '-e', script, chdir: __dir__)
17
+ expect(status.success?).to be(true),
18
+ "ScaffoldingCommands failed to load in isolation:\n#{stderr}"
19
+ expect(stdout.strip).to eq('OK')
20
+ end
21
+ end
22
+ end