ruby_raider 3.0.1 → 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 (189) 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 +1 -192
  6. data/lib/commands/utility_commands.rb +0 -43
  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/partials/debug_diagnostics.tt +1 -3
  38. data/lib/generators/templates/helpers/partials/debug_start.tt +1 -3
  39. data/lib/generators/templates/helpers/partials/quit_driver.tt +1 -3
  40. data/lib/generators/templates/helpers/partials/screenshot.tt +1 -3
  41. data/lib/generators/templates/helpers/spec_helper.tt +2 -39
  42. data/lib/ruby_raider.rb +2 -50
  43. data/lib/scaffolding/project_detector.rb +2 -9
  44. data/lib/scaffolding/scaffolding.rb +0 -109
  45. data/lib/scaffolding/templates/component.tt +1 -4
  46. data/lib/scaffolding/templates/page_object.tt +0 -10
  47. data/lib/scaffolding/templates/spec.tt +2 -6
  48. data/lib/scaffolding/templates/steps.tt +0 -2
  49. data/lib/utilities/utilities.rb +23 -29
  50. data/lib/version +1 -1
  51. data/sig/commands/scaffolding_commands.rbs +0 -12
  52. data/sig/commands/utility_commands.rbs +0 -6
  53. data/sig/generators/cucumber/cucumber_generator.rbs +0 -4
  54. data/sig/generators/generator.rbs +0 -11
  55. data/sig/generators/helper_generator.rbs +1 -5
  56. data/sig/generators/invoke_generators.rbs +1 -2
  57. data/sig/generators/menu_generator.rbs +2 -6
  58. data/sig/generators/rspec/rspec_generator.rbs +0 -2
  59. data/sig/ruby_raider.rbs +1 -3
  60. data/sig/scaffolding/project_detector.rbs +0 -1
  61. data/sig/scaffolding/scaffolding.rbs +0 -23
  62. data/sig/utilities/utilities.rbs +0 -4
  63. data/spec/commands/raider_commands_spec.rb +0 -61
  64. data/spec/integration/commands/browser_update_after_creation_spec.rb +123 -0
  65. data/spec/integration/commands/scaffolding_commands_spec.rb +0 -20
  66. data/spec/integration/commands/utility_commands_spec.rb +5 -5
  67. data/spec/integration/content/ci_content_spec.rb +6 -61
  68. data/spec/integration/content/common_content_spec.rb +0 -64
  69. data/spec/integration/content/config_content_spec.rb +1 -51
  70. data/spec/integration/content/content_helper.rb +2 -2
  71. data/spec/integration/content/gemfile_content_spec.rb +0 -71
  72. data/spec/integration/content/helper_content_spec.rb +4 -240
  73. data/spec/integration/content/page_content_spec.rb +0 -89
  74. data/spec/integration/content/syntax_validation_spec.rb +2 -2
  75. data/spec/integration/content/test_content_spec.rb +0 -119
  76. data/spec/integration/end_to_end_features_spec.rb +13 -411
  77. data/spec/integration/end_to_end_spec.rb +0 -96
  78. data/spec/integration/generators/axe_addon_spec.rb +2 -52
  79. data/spec/integration/generators/common_generator_spec.rb +1 -13
  80. data/spec/integration/generators/config_features_spec.rb +3 -81
  81. data/spec/integration/generators/debug_helper_spec.rb +0 -20
  82. data/spec/integration/generators/github_generator_spec.rb +5 -15
  83. data/spec/integration/generators/helpers_generator_spec.rb +0 -37
  84. data/spec/integration/scaffolding_e2e_spec.rb +2 -237
  85. data/spec/integration/settings_helper.rb +1 -3
  86. data/spec/integration/spec_helper.rb +6 -11
  87. data/spec/menus/menu_generator_spec.rb +4 -107
  88. data/spec/scaffolding/scaffold_project_detector_spec.rb +4 -26
  89. data/spec/scaffolding/scaffolding_features_spec.rb +0 -183
  90. data/spec/system/selenium_spec.rb +1 -4
  91. data/spec/system/support/system_test_helper.rb +0 -1
  92. data/spec/system/watir_spec.rb +1 -4
  93. data/spec/utilities/headless_config_spec.rb +0 -7
  94. metadata +3 -97
  95. data/lib/adopter/adopt_menu.rb +0 -146
  96. data/lib/adopter/converters/base_converter.rb +0 -84
  97. data/lib/adopter/converters/identity_converter.rb +0 -53
  98. data/lib/adopter/migration_plan.rb +0 -74
  99. data/lib/adopter/migrator.rb +0 -96
  100. data/lib/adopter/plan_builder.rb +0 -275
  101. data/lib/adopter/project_analyzer.rb +0 -252
  102. data/lib/adopter/project_detector.rb +0 -157
  103. data/lib/generators/cucumber/templates/partials/capybara_env.tt +0 -38
  104. data/lib/generators/cucumber/templates/partials/capybara_world.tt +0 -6
  105. data/lib/generators/cucumber/templates/performance_feature.tt +0 -5
  106. data/lib/generators/cucumber/templates/performance_steps.tt +0 -17
  107. data/lib/generators/cucumber/templates/visual_feature.tt +0 -5
  108. data/lib/generators/cucumber/templates/visual_steps.tt +0 -19
  109. data/lib/generators/infrastructure/gitlab_generator.rb +0 -11
  110. data/lib/generators/infrastructure/templates/gitlab.tt +0 -46
  111. data/lib/generators/minitest/minitest_generator.rb +0 -35
  112. data/lib/generators/minitest/templates/accessibility_test.tt +0 -26
  113. data/lib/generators/minitest/templates/performance_test.tt +0 -18
  114. data/lib/generators/minitest/templates/test.tt +0 -64
  115. data/lib/generators/minitest/templates/visual_test.tt +0 -23
  116. data/lib/generators/rspec/templates/performance_spec.tt +0 -18
  117. data/lib/generators/rspec/templates/visual_spec.tt +0 -20
  118. data/lib/generators/templates/helpers/capybara_helper.tt +0 -32
  119. data/lib/generators/templates/helpers/performance_helper.tt +0 -57
  120. data/lib/generators/templates/helpers/visual_helper.tt +0 -58
  121. data/lib/llm/client.rb +0 -79
  122. data/lib/llm/config.rb +0 -57
  123. data/lib/llm/prompts.rb +0 -84
  124. data/lib/llm/provider.rb +0 -27
  125. data/lib/llm/providers/anthropic_provider.rb +0 -43
  126. data/lib/llm/providers/ollama_provider.rb +0 -56
  127. data/lib/llm/providers/openai_provider.rb +0 -42
  128. data/lib/llm/response_parser.rb +0 -67
  129. data/lib/plugin/plugin.rb +0 -111
  130. data/lib/plugin/plugin_exposer.rb +0 -55
  131. data/lib/scaffolding/crud_generator.rb +0 -94
  132. data/lib/scaffolding/dry_run_presenter.rb +0 -16
  133. data/lib/scaffolding/page_introspector.rb +0 -45
  134. data/lib/scaffolding/scaffold_menu.rb +0 -103
  135. data/lib/scaffolding/templates/page_from_url.tt +0 -75
  136. data/lib/scaffolding/templates/spec_from_page.tt +0 -31
  137. data/lib/scaffolding/templates/spec_from_url.tt +0 -46
  138. data/lib/scaffolding/url_analyzer.rb +0 -179
  139. data/sig/adopter/adopt_menu.rbs +0 -25
  140. data/sig/adopter/converters/base_converter.rbs +0 -23
  141. data/sig/adopter/converters/identity_converter.rbs +0 -16
  142. data/sig/adopter/migration_plan.rbs +0 -34
  143. data/sig/adopter/migrator.rbs +0 -21
  144. data/sig/adopter/plan_builder.rbs +0 -38
  145. data/sig/adopter/project_analyzer.rbs +0 -39
  146. data/sig/adopter/project_detector.rbs +0 -26
  147. data/sig/generators/infrastructure/gitlab_generator.rbs +0 -4
  148. data/sig/generators/minitest/minitest_generator.rbs +0 -8
  149. data/sig/llm/client.rbs +0 -15
  150. data/sig/llm/config.rbs +0 -20
  151. data/sig/llm/prompts.rbs +0 -8
  152. data/sig/llm/provider.rbs +0 -12
  153. data/sig/llm/providers/anthropic_provider.rbs +0 -16
  154. data/sig/llm/providers/ollama_provider.rbs +0 -18
  155. data/sig/llm/providers/openai_provider.rbs +0 -16
  156. data/sig/llm/response_parser.rbs +0 -13
  157. data/sig/plugin/plugin.rbs +0 -24
  158. data/sig/plugin/plugin_exposer.rbs +0 -20
  159. data/sig/scaffolding/crud_generator.rbs +0 -16
  160. data/sig/scaffolding/dry_run_presenter.rbs +0 -4
  161. data/sig/scaffolding/page_introspector.rbs +0 -14
  162. data/sig/scaffolding/scaffold_menu.rbs +0 -18
  163. data/sig/scaffolding/url_analyzer.rbs +0 -28
  164. data/spec/adopter/adopt_menu_spec.rb +0 -176
  165. data/spec/adopter/converters/identity_converter_spec.rb +0 -145
  166. data/spec/adopter/migration_plan_spec.rb +0 -113
  167. data/spec/adopter/migrator_spec.rb +0 -277
  168. data/spec/adopter/plan_builder_spec.rb +0 -298
  169. data/spec/adopter/project_analyzer_spec.rb +0 -337
  170. data/spec/adopter/project_detector_spec.rb +0 -295
  171. data/spec/generators/generator_spec.rb +0 -23
  172. data/spec/integration/content/reporter_content_spec.rb +0 -236
  173. data/spec/integration/content/skip_flags_content_spec.rb +0 -206
  174. data/spec/integration/generators/gitlab_generator_spec.rb +0 -38
  175. data/spec/integration/generators/lighthouse_addon_spec.rb +0 -132
  176. data/spec/integration/generators/minitest_generator_spec.rb +0 -64
  177. data/spec/integration/generators/reporter_spec.rb +0 -159
  178. data/spec/integration/generators/skip_flags_spec.rb +0 -134
  179. data/spec/integration/generators/visual_addon_spec.rb +0 -148
  180. data/spec/llm/client_spec.rb +0 -79
  181. data/spec/llm/config_spec.rb +0 -92
  182. data/spec/llm/prompts_spec.rb +0 -49
  183. data/spec/llm/response_parser_spec.rb +0 -92
  184. data/spec/menus/adopter_adopt_menu_spec.rb +0 -97
  185. data/spec/scaffolding/page_introspector_spec.rb +0 -82
  186. data/spec/scaffolding/url_analyzer_spec.rb +0 -110
  187. data/spec/system/adopt_matrix_spec.rb +0 -537
  188. data/spec/system/adopt_spec.rb +0 -225
  189. data/spec/system/capybara_spec.rb +0 -42
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tty-prompt'
4
- require_relative 'project_detector'
5
-
6
- class ScaffoldMenu
7
- COMPONENTS = {
8
- 'Page object' => :page,
9
- 'Spec (RSpec)' => :spec,
10
- 'Feature (Cucumber)' => :feature,
11
- 'Steps (Cucumber)' => :steps,
12
- 'Helper' => :helper,
13
- 'Component' => :component,
14
- 'Model data' => :model
15
- }.freeze
16
-
17
- def initialize
18
- @prompt = TTY::Prompt.new
19
- end
20
-
21
- def run
22
- names = ask_names
23
- components = ask_components
24
- uses = ask_relationships
25
- preview_and_confirm(names, components, uses)
26
- end
27
-
28
- # Programmatic entry point for raider_desktop
29
- def self.build_options(names:, components:, uses: [])
30
- { names: Array(names), components: Array(components), uses: Array(uses) }
31
- end
32
-
33
- private
34
-
35
- def ask_names
36
- input = @prompt.ask('Enter scaffold name(s), comma-separated:') do |q|
37
- q.required true
38
- end
39
- input.split(',').map(&:strip).reject(&:empty?)
40
- end
41
-
42
- def ask_components
43
- project = ScaffoldProjectDetector.detect
44
- defaults = default_components(project)
45
-
46
- @prompt.multi_select('Select components to generate:', default: defaults) do |menu|
47
- COMPONENTS.each do |label, value|
48
- menu.choice label, value
49
- end
50
- end
51
- end
52
-
53
- def ask_relationships
54
- return [] unless @prompt.yes?('Add page dependencies (--uses)?', default: false)
55
-
56
- pages = Dir.glob('page_objects/pages/*.rb').map { |f| File.basename(f, '.rb') }
57
- return [] if pages.empty?
58
-
59
- @prompt.multi_select('Select dependent pages:', pages)
60
- end
61
-
62
- def preview_and_confirm(names, components, uses)
63
- files = planned_files(names, components)
64
-
65
- @prompt.say("\nWill create:")
66
- files.each { |f| @prompt.say(" #{f}") }
67
- @prompt.say('')
68
-
69
- return nil unless @prompt.yes?('Proceed?')
70
-
71
- { names:, components:, uses: }
72
- end
73
-
74
- def planned_files(names, components)
75
- names.flat_map do |name|
76
- components.map { |comp| file_for(name, comp) }
77
- end
78
- end
79
-
80
- def file_for(name, component)
81
- case component
82
- when :page then "page_objects/pages/#{name}.rb"
83
- when :spec then "spec/#{name}_page_spec.rb"
84
- when :feature then "features/#{name}.feature"
85
- when :steps then "features/step_definitions/#{name}_steps.rb"
86
- when :helper then "helpers/#{name}_helper.rb"
87
- when :component then "page_objects/components/#{name}.rb"
88
- when :model then "models/data/#{name}.yml"
89
- end
90
- end
91
-
92
- def default_components(project)
93
- defaults = [:page]
94
- if project[:has_features]
95
- defaults += %i[feature steps]
96
- elsif project[:has_test]
97
- defaults << :spec
98
- else
99
- defaults << :spec
100
- end
101
- defaults.map { |d| COMPONENTS.key(d) }.compact
102
- end
103
- end
@@ -1,75 +0,0 @@
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,31 +0,0 @@
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
@@ -1,46 +0,0 @@
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,179 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'uri'
4
- require 'net/http'
5
-
6
- class UrlAnalyzer
7
- INTERACTIVE_TAGS = %w[input select textarea button].freeze
8
-
9
- attr_reader :url, :page_name, :elements
10
-
11
- def initialize(url, name_override: nil, ai: false) # rubocop:disable Naming/MethodParameterName
12
- @url = url
13
- @uri = URI.parse(url)
14
- @page_name = name_override || derive_page_name
15
- @elements = []
16
- @ai = ai
17
- end
18
-
19
- def analyze
20
- html = fetch_html
21
- if @ai
22
- ai_elements = analyze_with_llm(html)
23
- @elements = ai_elements if ai_elements
24
- end
25
- parse_elements(html) if @elements.empty?
26
- self
27
- end
28
-
29
- def to_h
30
- { page_name: @page_name, url: @url, url_path: @uri.path, elements: @elements }
31
- end
32
-
33
- private
34
-
35
- def fetch_html
36
- response = Net::HTTP.get_response(@uri)
37
- response.body
38
- rescue StandardError => e
39
- raise "Failed to fetch #{@url}: #{e.message}"
40
- end
41
-
42
- def parse_elements(html)
43
- # Simple regex-based HTML parsing (no external dependency needed)
44
- parse_inputs(html)
45
- parse_selects(html)
46
- parse_textareas(html)
47
- parse_buttons(html)
48
- parse_links(html)
49
- end
50
-
51
- def parse_inputs(html)
52
- html.scan(/<input\s+([^>]*)>/i).each do |match|
53
- attrs = parse_attributes(match[0])
54
- next if %w[hidden submit].include?(attrs['type'])
55
-
56
- @elements << build_element(
57
- name: attrs['name'] || attrs['id'] || attrs['placeholder'] || 'input',
58
- type: :input,
59
- input_type: attrs['type'] || 'text',
60
- locator: best_locator(attrs)
61
- )
62
- end
63
- end
64
-
65
- def parse_selects(html)
66
- html.scan(/<select\s+([^>]*)>/i).each do |match|
67
- attrs = parse_attributes(match[0])
68
- @elements << build_element(
69
- name: attrs['name'] || attrs['id'] || 'select',
70
- type: :select,
71
- locator: best_locator(attrs)
72
- )
73
- end
74
- end
75
-
76
- def parse_textareas(html)
77
- html.scan(/<textarea\s+([^>]*)>/i).each do |match|
78
- attrs = parse_attributes(match[0])
79
- @elements << build_element(
80
- name: attrs['name'] || attrs['id'] || 'textarea',
81
- type: :textarea,
82
- locator: best_locator(attrs)
83
- )
84
- end
85
- end
86
-
87
- def parse_buttons(html)
88
- html.scan(%r{<button\s+([^>]*)>([^<]*)</button>}i).each do |match|
89
- attrs = parse_attributes(match[0])
90
- text = match[1].strip
91
- @elements << build_element(
92
- name: attrs['id'] || attrs['name'] || text.downcase.gsub(/\s+/, '_') || 'button',
93
- type: :button,
94
- text:,
95
- locator: best_locator(attrs, text:)
96
- )
97
- end
98
-
99
- html.scan(/<input\s+([^>]*type=["']submit["'][^>]*)>/i).each do |match|
100
- attrs = parse_attributes(match[0])
101
- @elements << build_element(
102
- name: attrs['id'] || attrs['name'] || attrs['value']&.downcase&.gsub(/\s+/, '_') || 'submit',
103
- type: :submit,
104
- text: attrs['value'] || 'Submit',
105
- locator: best_locator(attrs)
106
- )
107
- end
108
- end
109
-
110
- def parse_links(html)
111
- html.scan(%r{<a\s+([^>]*)>([^<]*)</a>}i).first(5)&.each do |match|
112
- attrs = parse_attributes(match[0])
113
- text = match[1].strip
114
- next if text.empty?
115
-
116
- @elements << build_element(
117
- name: text.downcase.gsub(/\s+/, '_'),
118
- type: :link,
119
- text:,
120
- locator: best_locator(attrs, text:)
121
- )
122
- end
123
- end
124
-
125
- def parse_attributes(attr_string)
126
- attrs = {}
127
- attr_string.scan(/([\w-]+)=["']([^"']*)["']/).each do |key, value|
128
- attrs[key] = value
129
- end
130
- attrs
131
- end
132
-
133
- def best_locator(attrs, text: nil)
134
- if attrs['id']
135
- { type: :id, value: attrs['id'] }
136
- elsif attrs['name']
137
- { type: :name, value: attrs['name'] }
138
- elsif attrs['class'] && !attrs['class'].empty?
139
- { type: :css, value: ".#{attrs['class'].split.first}" }
140
- elsif text && !text.empty?
141
- { type: :xpath, value: "//#{infer_tag(attrs)}[contains(text(), '#{text}')]" }
142
- else
143
- { type: :css, value: attrs.first&.last || 'unknown' }
144
- end
145
- end
146
-
147
- def infer_tag(attrs)
148
- return 'button' if attrs['type'] == 'button' || attrs['type'] == 'submit'
149
- return 'a' if attrs['href']
150
-
151
- '*'
152
- end
153
-
154
- def build_element(name:, type:, locator:, **extra)
155
- clean_name = name.to_s.gsub(/[^a-z0-9_]/i, '_').gsub(/_+/, '_').downcase.delete_prefix('_').delete_suffix('_')
156
- { name: clean_name, type:, locator: }.merge(extra)
157
- end
158
-
159
- def analyze_with_llm(html)
160
- require_relative '../llm/client'
161
- require_relative '../llm/prompts'
162
- require_relative '../llm/response_parser'
163
-
164
- return nil unless Llm::Client.available?
165
-
166
- response = Llm::Client.complete(
167
- Llm::Prompts.analyze_page(html, @url),
168
- system_prompt: Llm::Prompts.system_prompt
169
- )
170
- Llm::ResponseParser.extract_elements(response)
171
- end
172
-
173
- def derive_page_name
174
- path = @uri.path.to_s.gsub(%r{^/|/$}, '')
175
- return 'home' if path.empty?
176
-
177
- path.split('/').last.gsub(/[^a-z0-9]/i, '_').downcase
178
- end
179
- end
@@ -1,25 +0,0 @@
1
- # Type definitions for Adopter::AdoptMenu
2
- module Adopter
3
- class AdoptMenu
4
- WEB_AUTOMATIONS: Array[String]
5
- TEST_FRAMEWORKS: Array[String]
6
- CI_PLATFORMS: Array[String]
7
-
8
- def initialize: () -> void
9
- def run: () -> void
10
-
11
- def self.adopt: (Hash[Symbol, untyped] params) -> Hash[Symbol, untyped]
12
- def self.validate_params!: (Hash[Symbol, untyped] params) -> void
13
-
14
- private
15
-
16
- def ask_source_path: () -> String
17
- def preview_detection: (String source_path) -> Hash[Symbol, untyped]
18
- def ask_target_automation: (String? detected) -> String
19
- def ask_target_framework: (String? detected) -> String
20
- def ask_output_path: () -> String?
21
- def ask_ci_platform: (String? detected) -> String?
22
- def execute_adoption: (Hash[Symbol, untyped] params) -> void
23
- def print_results: (MigrationPlan plan, Hash[Symbol, untyped] results) -> void
24
- end
25
- end
@@ -1,23 +0,0 @@
1
- # Type definitions for Adopter::Converters::BaseConverter
2
- module Adopter
3
- module Converters
4
- class BaseConverter
5
- RAIDER_BASE_CLASSES: Array[String]
6
-
7
- def convert_page: (String content, untyped _page_info) -> String
8
- def convert_test: (String content, untyped _test_info) -> String
9
-
10
- private
11
-
12
- def ensure_frozen_string_literal: (String content) -> String
13
- def update_base_class: (String content, String target_base) -> String
14
- def raider_compatible_base?: (String base_class) -> bool
15
- def update_require_paths: (String content, String target_automation) -> String
16
- def update_page_requires: (String content) -> String
17
- def update_helper_requires: (String content, String target_automation) -> String
18
- def remove_driver_arg: (String content) -> String
19
- def swap_driver_arg: (String content, String target_arg) -> String
20
- def driver_arg_for: (String target_automation) -> String?
21
- end
22
- end
23
- end
@@ -1,16 +0,0 @@
1
- # Type definitions for Adopter::Converters::IdentityConverter
2
- module Adopter
3
- module Converters
4
- class IdentityConverter < BaseConverter
5
- def initialize: (String target_automation) -> void
6
- def convert_page: (String content, untyped _page_info) -> String
7
- def convert_test: (String content, untyped _test_info) -> String
8
- def convert_step: (String content) -> String
9
-
10
- private
11
-
12
- def add_page_require: (String content) -> String
13
- def update_page_instantiation: (String content) -> String
14
- end
15
- end
16
- end
@@ -1,34 +0,0 @@
1
- # Type definitions for Adopter::MigrationPlan and ConvertedFile
2
- module Adopter
3
- class MigrationPlan
4
- attr_reader source_path: String
5
- attr_reader output_path: String
6
- attr_reader target_automation: String
7
- attr_reader target_framework: String
8
- attr_reader ci_platform: String?
9
- attr_reader skeleton_structure: Hash[Symbol, untyped]
10
- attr_reader converted_pages: Array[ConvertedFile]
11
- attr_reader converted_tests: Array[ConvertedFile]
12
- attr_reader converted_features: Array[ConvertedFile]
13
- attr_reader converted_steps: Array[ConvertedFile]
14
- attr_reader gemfile_additions: Array[String]
15
- attr_reader config_overrides: Hash[String, untyped]
16
- attr_reader warnings: Array[String]
17
- attr_reader manual_actions: Array[String]
18
-
19
- def initialize: (?Hash[Symbol, untyped]? attrs) -> void
20
- def to_h: () -> Hash[Symbol, untyped]
21
- def to_json: (*untyped args) -> String
22
- def summary: () -> Hash[Symbol, untyped]
23
- end
24
-
25
- class ConvertedFile
26
- attr_accessor output_path: String
27
- attr_accessor content: String
28
- attr_accessor source_file: String?
29
- attr_accessor conversion_notes: String?
30
-
31
- def initialize: (?output_path: String, ?content: String, ?source_file: String?, ?conversion_notes: String?) -> void
32
- def to_h: () -> Hash[Symbol, untyped]
33
- end
34
- end
@@ -1,21 +0,0 @@
1
- # Type definitions for Adopter::Migrator
2
- module Adopter
3
- class Migrator
4
- attr_reader plan: MigrationPlan
5
- attr_reader results: Hash[Symbol, untyped]
6
-
7
- def initialize: (MigrationPlan plan) -> void
8
- def execute: () -> Hash[Symbol, untyped]
9
-
10
- private
11
-
12
- def generate_skeleton: () -> void
13
- def write_converted_pages: () -> void
14
- def write_converted_tests: () -> void
15
- def write_converted_features: () -> void
16
- def write_converted_steps: () -> void
17
- def write_file: (ConvertedFile converted_file) -> void
18
- def merge_gemfile: () -> void
19
- def apply_config_overrides: () -> void
20
- end
21
- end
@@ -1,38 +0,0 @@
1
- # Type definitions for Adopter::PlanBuilder
2
- module Adopter
3
- class PlanBuilder
4
- def initialize: (Hash[Symbol, untyped] analysis, Hash[Symbol, untyped] params) -> void
5
- def build: () -> MigrationPlan
6
-
7
- private
8
-
9
- def build_skeleton_structure: () -> Hash[Symbol, untyped]
10
- def plan_page_conversions: () -> Array[ConvertedFile]
11
- def plan_test_conversions: () -> Array[ConvertedFile]
12
- def plan_feature_conversions: () -> Array[ConvertedFile]
13
- def plan_step_conversions: () -> Array[ConvertedFile]
14
- def convert_page: (String content, Hash[Symbol, untyped] page) -> String
15
- def convert_page_dsl: (String content, Hash[Symbol, untyped] page, Symbol source_dsl, String target) -> String
16
- def find_page_converter: (Symbol source_dsl, String target) -> (^(String, Hash[Symbol, untyped]) -> String)?
17
- def page_converters: () -> Hash[Symbol, ^(String, Hash[Symbol, untyped]) -> String]
18
- def convert_test: (String content, Hash[Symbol, untyped] test) -> String
19
- def convert_test_framework: (String content, Hash[Symbol, untyped] test, Symbol source_framework, String target) -> String
20
- def find_test_converter: (Symbol source_framework, String target) -> (^(String, Hash[Symbol, untyped]) -> String)?
21
- def test_converters: () -> Hash[Symbol, ^(String, Hash[Symbol, untyped]) -> String]
22
- def identity_converter: () -> Converters::IdentityConverter
23
- def restructure_page: (String content) -> String
24
- def restructure_test: (String content) -> String
25
- def convert_step_page_references: (String content) -> String
26
- def raider_page_path: (String class_name) -> String
27
- def raider_test_path: (Hash[Symbol, untyped] test) -> String
28
- def raider_feature_path: (String source_path) -> String
29
- def raider_step_path: (String source_path) -> String
30
- def extract_config_overrides: () -> Hash[String, untyped]
31
- def same_automation_dsl?: (Symbol source_dsl, String target) -> bool
32
- def normalize_dsl: (Symbol dsl) -> String
33
- def target_cucumber?: () -> bool
34
- def page_conversion_notes: () -> String
35
- def test_conversion_notes: (Symbol source_type) -> String
36
- def add_warning: (String message) -> void
37
- end
38
- end
@@ -1,39 +0,0 @@
1
- # Type definitions for Adopter::ProjectAnalyzer
2
- module Adopter
3
- class MobileProjectError < StandardError
4
- end
5
-
6
- class ProjectAnalyzer
7
- KNOWN_FRAMEWORK_GEMS: Array[String]
8
- PAGE_DSL_PATTERNS: Hash[Symbol, Regexp]
9
- PAGE_CLASS_PATTERNS: Array[Regexp]
10
- TEST_FILE_PATTERNS: Hash[Symbol, Hash[Symbol, untyped]]
11
- HELPER_ROLES: Hash[Symbol, Regexp]
12
-
13
- def initialize: (String source_path, ?Hash[Symbol, untyped]? overrides) -> void
14
- def analyze: () -> Hash[Symbol, untyped]
15
-
16
- private
17
-
18
- def validate_web_only!: (Hash[Symbol, untyped] detection) -> void
19
- def discover_pages: () -> Array[Hash[Symbol, untyped]]
20
- def discover_tests: () -> Array[Hash[Symbol, untyped]]
21
- def discover_helpers: () -> Array[Hash[Symbol, untyped]]
22
- def discover_features: () -> Array[Hash[Symbol, untyped]]
23
- def discover_step_definitions: () -> Array[Hash[Symbol, untyped]]
24
- def discover_custom_gems: () -> Array[String]
25
- def detect_page_dsl: () -> Symbol
26
- def detect_page_dir: () -> String?
27
- def ruby_files_in: (String dir) -> Array[String]
28
- def relative_path: (String absolute) -> String
29
- def page_like?: (String content) -> bool
30
- def extract_class_name: (String content) -> String?
31
- def extract_base_class: (String content) -> String?
32
- def extract_public_methods: (String content) -> Array[String]
33
- def extract_test_methods: (String content, Symbol type) -> Array[String]
34
- def extract_modules: (String content) -> Array[String]
35
- def detect_helper_role: (String content) -> Symbol
36
- def count_scenarios: (String content) -> Integer
37
- def count_steps: (String content) -> Integer
38
- end
39
- end
@@ -1,26 +0,0 @@
1
- # Type definitions for Adopter::ProjectDetector
2
- module Adopter
3
- module ProjectDetector
4
- GEM_AUTOMATION_MAP: Hash[String, String]
5
- GEM_FRAMEWORK_MAP: Hash[String, String]
6
- BROWSERS: Array[String]
7
-
8
- def self?.detect: (String path) -> Hash[Symbol, String?]
9
- def self?.detect_automation: (String path) -> String?
10
- def self?.detect_framework: (String path) -> String?
11
- def self?.detect_page_path: (String path) -> String?
12
- def self?.detect_spec_path: (String path) -> String?
13
- def self?.detect_feature_path: (String path) -> String?
14
- def self?.detect_helper_path: (String path) -> String?
15
- def self?.detect_browser: (String path) -> String?
16
- def self?.detect_url: (String path) -> String?
17
- def self?.detect_ci_platform: (String path) -> String?
18
- def self?.parse_gemfile: (String path) -> Array[String]
19
-
20
- private
21
-
22
- def self?.detect_automation_from_requires: (String path) -> String?
23
- def self?.find_existing_dir: (String path, Array[String] candidates) -> String?
24
- def self?.helper_and_config_files: (String path) -> Array[String]
25
- end
26
- end
@@ -1,4 +0,0 @@
1
- # Type definitions for GitlabGenerator
2
- class GitlabGenerator < Generator
3
- def generate_gitlab_file: () -> void
4
- end
@@ -1,8 +0,0 @@
1
- # Type definitions for MinitestGenerator
2
- class MinitestGenerator < Generator
3
- def generate_login_test: () -> void
4
- def generate_pdp_test: () -> void
5
- def generate_visual_test: () -> void
6
- def generate_accessibility_test: () -> void
7
- def generate_performance_test: () -> void
8
- end