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
@@ -0,0 +1,4 @@
1
+ # Type definitions for DryRunPresenter
2
+ module DryRunPresenter
3
+ def self?.preview: (Array[String] planned_files) -> Array[String]
4
+ end
@@ -0,0 +1,17 @@
1
+ # Type definitions for NameNormalizer
2
+ module NameNormalizer
3
+ SUFFIXES: Array[String]
4
+
5
+ def self?.normalize: (String input) -> String
6
+ def self?.to_class_name: (String input, String suffix) -> String
7
+ def self?.to_page_class: (String input) -> String
8
+ def self?.to_file_name: (String input) -> String
9
+ def self?.nested?: (String input) -> bool
10
+ def self?.module_parts: (String input) -> Array[String]
11
+ def self?.leaf_name: (String input) -> String
12
+
13
+ private
14
+
15
+ def self?.camel_to_snake: (String str) -> String
16
+ def self?.strip_suffixes: (String name) -> String
17
+ end
@@ -0,0 +1,14 @@
1
+ # Type definitions for PageIntrospector
2
+ class PageIntrospector
3
+ SKIP_METHODS: Array[String]
4
+
5
+ attr_reader class_name: String
6
+ attr_reader methods: Array[Hash[Symbol, untyped]]
7
+
8
+ def initialize: (String file_path) -> void
9
+
10
+ private
11
+
12
+ def extract_class_name: () -> String
13
+ def extract_public_methods: () -> Array[Hash[Symbol, untyped]]
14
+ end
@@ -0,0 +1,14 @@
1
+ # Type definitions for ScaffoldProjectDetector
2
+ module ScaffoldProjectDetector
3
+ AUTOMATION_GEMS: Hash[String, String]
4
+ FRAMEWORK_GEMS: Hash[String, String]
5
+
6
+ def self?.detect: () -> Hash[Symbol, String | bool | nil]
7
+ def self?.detect_automation: (?String? gemfile) -> String
8
+ def self?.detect_framework: (?String? gemfile) -> String
9
+ def self?.read_gemfile: () -> String
10
+ def self?.selenium?: () -> bool
11
+ def self?.capybara?: () -> bool
12
+ def self?.watir?: () -> bool
13
+ def self?.config: () -> Hash[String, untyped]
14
+ end
@@ -0,0 +1,18 @@
1
+ # Type definitions for ScaffoldMenu
2
+ class ScaffoldMenu
3
+ COMPONENTS: Hash[String, Symbol]
4
+
5
+ def initialize: () -> void
6
+ def run: () -> Hash[Symbol, untyped]?
7
+ def self.build_options: (names: Array[String] | String, components: Array[Symbol] | Symbol, ?uses: Array[String] | String) -> Hash[Symbol, untyped]
8
+
9
+ private
10
+
11
+ def ask_names: () -> Array[String]
12
+ def ask_components: () -> Array[Symbol]
13
+ def ask_relationships: () -> Array[String]
14
+ def preview_and_confirm: (Array[String] names, Array[Symbol] components, Array[String] uses) -> Hash[Symbol, untyped]?
15
+ def planned_files: (Array[String] names, Array[Symbol] components) -> Array[String]
16
+ def file_for: (String name, Symbol component) -> String?
17
+ def default_components: (Hash[Symbol, untyped] project) -> Array[String]
18
+ end
@@ -0,0 +1,55 @@
1
+ # Type definitions for Scaffolding
2
+ class Scaffolding < Thor::Group
3
+ include Thor::Actions
4
+
5
+ OVERRIDE_DIR: String
6
+
7
+ attr_writer uses: Array[String]
8
+
9
+ def self.source_root: () -> String
10
+ def self.planned_path: (String name, String type, ?String? custom_path) -> String?
11
+
12
+ # Generation methods
13
+ def generate_page: () -> void
14
+ def generate_feature: () -> void
15
+ def generate_spec: () -> void
16
+ def generate_helper: () -> void
17
+ def generate_steps: () -> void
18
+ def generate_component: () -> void
19
+ 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
+
33
+ # Template helpers
34
+ def class_name: () -> String?
35
+ def page_class_name: () -> String
36
+ def normalized_name: () -> String
37
+ def nested?: () -> bool
38
+ def module_parts: () -> Array[String]
39
+ def leaf_name: () -> String
40
+ def automation_type: () -> String
41
+ def framework_type: () -> String
42
+ def project_config: () -> Hash[String, untyped]
43
+ def selenium?: () -> bool
44
+ def capybara?: () -> bool
45
+ def watir?: () -> bool
46
+ def uses_list: () -> Array[String]
47
+ def introspected: () -> PageIntrospector?
48
+ def url_data: () -> Hash[Symbol, untyped]?
49
+ def ai_scenarios: () -> Hash[Symbol, untyped]
50
+ def default_path: (String standard_path, String file_type) -> String
51
+
52
+ private
53
+
54
+ def enrich_with_ai_scenarios: () -> void
55
+ end
@@ -0,0 +1,28 @@
1
+ # Type definitions for UrlAnalyzer
2
+ class UrlAnalyzer
3
+ INTERACTIVE_TAGS: Array[String]
4
+
5
+ attr_reader url: String
6
+ attr_reader page_name: String
7
+ attr_reader elements: Array[Hash[Symbol, untyped]]
8
+
9
+ def initialize: (String url, ?name_override: String?, ?ai: bool) -> void
10
+ def analyze: () -> UrlAnalyzer
11
+ def to_h: () -> Hash[Symbol, untyped]
12
+
13
+ private
14
+
15
+ def fetch_html: () -> String
16
+ def parse_elements: (String html) -> void
17
+ def parse_inputs: (String html) -> void
18
+ def parse_selects: (String html) -> void
19
+ def parse_textareas: (String html) -> void
20
+ def parse_buttons: (String html) -> void
21
+ def parse_links: (String html) -> void
22
+ def parse_attributes: (String attr_string) -> Hash[String, String]
23
+ def best_locator: (Hash[String, String] attrs, ?text: String?) -> Hash[Symbol, Symbol | String]
24
+ def infer_tag: (Hash[String, String] attrs) -> String
25
+ def build_element: (name: String, type: Symbol, locator: Hash[Symbol, Symbol | String], **untyped extra) -> Hash[Symbol, untyped]
26
+ def analyze_with_llm: (String html) -> Array[Hash[Symbol, untyped]]?
27
+ def derive_page_name: () -> String
28
+ end
@@ -0,0 +1,23 @@
1
+ # Type definitions for DesktopDownloader
2
+ module DesktopDownloader
3
+ REPO: String
4
+ API_URL: String
5
+ PLATFORM_PATTERNS: Hash[String, Regexp]
6
+
7
+ def self?.download: (?String? destination_dir) -> String?
8
+ def self?.latest_version: () -> String?
9
+ def self?.download_url: () -> String?
10
+ def self?.clear_cache: () -> void
11
+ def self?.platform: () -> String
12
+ def self?.platform_display_name: () -> String
13
+
14
+ private
15
+
16
+ def self?.find_asset: () -> Hash[Symbol, untyped]?
17
+ def self?.fetch_latest_release: () -> Hash[String, untyped]?
18
+ def self?.download_file: (String url, String destination) -> void
19
+ def self?.follow_redirects: (URI::Generic uri, String destination, ?Integer limit) -> void
20
+ def self?.write_response: (Net::HTTPResponse response, String destination) -> void
21
+ def self?.print_progress: (Integer downloaded, Integer total) -> void
22
+ def self?.default_download_dir: () -> String
23
+ end
@@ -0,0 +1,13 @@
1
+ # Type definitions for RubyRaider::Logger
2
+ module RubyRaider
3
+ module Logger
4
+ extend Forwardable
5
+
6
+ def self?.logger: () -> ::Logger
7
+ def self?.fatal: (*untyped args) -> void
8
+ def self?.error: (*untyped args) -> void
9
+ def self?.warn: (*untyped args) -> void
10
+ def self?.info: (*untyped args) -> void
11
+ def self?.debug: (*untyped args) -> void
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ # Type definitions for Logo
2
+ module RubyRaider
3
+ module Logo
4
+ PALETTE: Hash[Integer, String]
5
+ GEM: Array[Array[Integer]]
6
+ GLYPHS: Hash[String, Array[Array[Integer]]]
7
+ TEXT_COLOR: Integer
8
+
9
+ def self.display: () -> void
10
+
11
+ private
12
+
13
+ def self.halfblock: (Integer top, Integer bot) -> String
14
+ def self.build_text: (String str) -> Array[Array[Integer]]
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ # Type definitions for Utilities
2
+ module Utilities
3
+ @path: String
4
+
5
+ def self?.browser=: (String browser) -> void
6
+ def self?.page_path=: (String path) -> void
7
+ def self?.spec_path=: (String path) -> void
8
+ def self?.feature_path=: (String path) -> void
9
+ def self?.helper_path=: (String path) -> void
10
+ def self?.url=: (String url) -> void
11
+ def self?.timeout=: (String | Integer seconds) -> void
12
+ def self?.viewport=: (String dimensions) -> void
13
+ def self?.platform=: (String platform) -> void
14
+ def self?.browser_options=: (Array[String] opts) -> void
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
+ def self?.debug=: (bool enabled) -> void
21
+ def self?.batch_update: (**untyped settings) -> void
22
+ def self?.run: (?String? opts) -> void
23
+ def self?.parallel_run: (?String? opts, ?untyped? _settings) -> void
24
+
25
+ private
26
+
27
+ def self?.set: (String key, untyped value) -> void
28
+ def self?.overwrite_yaml: () -> void
29
+ def self?.config: () -> Hash[String, untyped]?
30
+ end
@@ -0,0 +1,34 @@
1
+ # Minimal Thor stubs for type checking
2
+ class Thor
3
+ def self.desc: (String usage, String description, ?Hash[Symbol, untyped] options) -> void
4
+ def self.method_option: (Symbol name, **untyped options) -> void
5
+ def self.class_option: (Symbol name, **untyped options) -> void
6
+ def self.option: (Symbol name, **untyped options) -> void
7
+ def self.map: (Hash[String, Symbol] mappings) -> void
8
+ def self.subcommand: (String name, Class subcommand_class) -> void
9
+ def self.no_commands: () { () -> void } -> void
10
+ def self.start: (?Array[String] args, ?Hash[Symbol, untyped] config) -> void
11
+ def invoke: (Symbol command, ?Array[untyped]? args, ?Array[String]? flags) -> void
12
+ def options: () -> Hash[Symbol, untyped]
13
+ def say: (String message, ?Symbol? color) -> void
14
+ end
15
+
16
+ class Thor::Group
17
+ include Thor::Actions
18
+
19
+ def self.argument: (Symbol name, **untyped options) -> void
20
+ def self.source_root: (?String path) -> String
21
+ def self.source_paths: () -> Array[String]
22
+ def invoke_all: () -> void
23
+ def args: () -> Array[String]
24
+ end
25
+
26
+ module Thor::Actions
27
+ def template: (String source, ?String destination, **untyped options) -> void
28
+ def create_file: (String destination, ?String data) -> void
29
+ def empty_directory: (String destination) -> void
30
+ def copy_file: (String source, ?String destination) -> void
31
+ def remove_file: (String path) -> void
32
+ def destination_root: () -> String
33
+ def self.included: (Module base) -> void
34
+ end
@@ -0,0 +1,15 @@
1
+ # Minimal TTY::Prompt stubs
2
+ module TTY
3
+ class Prompt
4
+ def initialize: (**untyped options) -> void
5
+ def select: (String question, ?Array[String] choices, **untyped options) ?{ (untyped menu) -> void } -> String
6
+ def multi_select: (String question, ?Array[String] choices, **untyped options) ?{ (untyped menu) -> void } -> Array[String]
7
+ def ask: (String question, **untyped options) -> String?
8
+ def yes?: (String question, **untyped options) -> bool
9
+ def no?: (String question, **untyped options) -> bool
10
+ def say: (String message) -> void
11
+ def warn: (String message) -> void
12
+ def error: (String message) -> void
13
+ def ok: (String message) -> void
14
+ end
15
+ end
@@ -126,51 +126,51 @@ RSpec.describe Adopter::AdoptMenu do
126
126
  end
127
127
 
128
128
  it 'raises on missing target_automation' do
129
- expect {
129
+ expect do
130
130
  described_class.validate_params!(source_path: 'x', output_path: 'y')
131
- }.to raise_error(ArgumentError, /target_automation/)
131
+ end.to raise_error(ArgumentError, /target_automation/)
132
132
  end
133
133
 
134
134
  it 'raises on missing target_framework' do
135
- expect {
135
+ expect do
136
136
  described_class.validate_params!(source_path: 'x', output_path: 'y', target_automation: 'selenium')
137
- }.to raise_error(ArgumentError, /target_framework/)
137
+ end.to raise_error(ArgumentError, /target_framework/)
138
138
  end
139
139
 
140
140
  it 'raises on invalid target_automation' do
141
- expect {
141
+ expect do
142
142
  described_class.validate_params!(
143
143
  source_path: 'x', output_path: 'y',
144
144
  target_automation: 'appium', target_framework: 'rspec'
145
145
  )
146
- }.to raise_error(ArgumentError, /target_automation must be/)
146
+ end.to raise_error(ArgumentError, /target_automation must be/)
147
147
  end
148
148
 
149
149
  it 'raises on invalid target_framework' do
150
- expect {
150
+ expect do
151
151
  described_class.validate_params!(
152
152
  source_path: 'x', output_path: 'y',
153
153
  target_automation: 'selenium', target_framework: 'junit'
154
154
  )
155
- }.to raise_error(ArgumentError, /target_framework must be/)
155
+ end.to raise_error(ArgumentError, /target_framework must be/)
156
156
  end
157
157
 
158
158
  it 'accepts valid params without raising' do
159
- expect {
159
+ expect do
160
160
  described_class.validate_params!(
161
161
  source_path: 'x', output_path: 'y',
162
162
  target_automation: 'selenium', target_framework: 'rspec'
163
163
  )
164
- }.not_to raise_error
164
+ end.not_to raise_error
165
165
  end
166
166
 
167
167
  it 'accepts capybara as valid automation' do
168
- expect {
168
+ expect do
169
169
  described_class.validate_params!(
170
170
  source_path: 'x', output_path: 'y',
171
171
  target_automation: 'capybara', target_framework: 'minitest'
172
172
  )
173
- }.not_to raise_error
173
+ end.not_to raise_error
174
174
  end
175
175
  end
176
176
  end
@@ -32,7 +32,7 @@ RSpec.describe Adopter::MigrationPlan do
32
32
  end
33
33
 
34
34
  describe '#to_h' do
35
- it 'serializes all fields' do
35
+ it 'serializes all fields' do # rubocop:disable RSpec/MultipleExpectations
36
36
  hash = plan.to_h
37
37
  expect(hash[:source_path]).to eq('/source')
38
38
  expect(hash[:output_path]).to eq('/output')
@@ -231,8 +231,8 @@ RSpec.describe Adopter::Migrator do
231
231
  },
232
232
  converted_pages: [
233
233
  Adopter::ConvertedFile.new(
234
- output_path: "/dev/null/impossible/path/file.rb",
235
- content: "content",
234
+ output_path: '/dev/null/impossible/path/file.rb',
235
+ content: 'content',
236
236
  source_file: 'pages/bad.rb',
237
237
  conversion_notes: 'Will fail'
238
238
  )
@@ -76,7 +76,7 @@ RSpec.describe Adopter::ProjectDetector do
76
76
  end
77
77
  end
78
78
 
79
- { 'eyes_selenium' => 'applitools', 'axe-core-selenium' => 'axe',
79
+ { 'eyes_selenium' => 'selenium', 'axe-core-selenium' => 'selenium',
80
80
  'capybara' => 'capybara', 'site_prism' => 'capybara' }.each do |gem_name, expected|
81
81
  context "with #{gem_name} in Gemfile" do
82
82
  before { File.write("#{project_dir}/Gemfile", "gem '#{gem_name}'\n") }
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+ require_relative '../../lib/ruby_raider'
5
+
6
+ RSpec.describe RubyRaider::Raider do
7
+ describe 'new command' do
8
+ context 'with parameters' do
9
+ it 'calls InvokeGenerators.generate_framework with parsed hash' do
10
+ allow(InvokeGenerators).to receive(:generate_framework)
11
+
12
+ described_class.new.invoke(:new, nil, %w[my_project -p framework:rspec automation:selenium])
13
+
14
+ expect(InvokeGenerators).to have_received(:generate_framework).with(
15
+ hash_including(framework: 'rspec', automation: 'selenium', name: 'my_project')
16
+ )
17
+ end
18
+ end
19
+
20
+ context 'without parameters' do
21
+ it 'calls MenuGenerator.generate_choice_menu' do
22
+ menu = instance_double(MenuGenerator, generate_choice_menu: nil)
23
+ allow(MenuGenerator).to receive(:new).and_return(menu)
24
+
25
+ described_class.new.invoke(:new, nil, %w[my_project])
26
+
27
+ expect(menu).to have_received(:generate_choice_menu)
28
+ end
29
+ end
30
+ end
31
+
32
+ describe 'version command' do
33
+ it 'outputs the version from lib/version' do
34
+ expected_version = File.read(File.expand_path('../../lib/version', __dir__)).strip
35
+ expect { described_class.new.invoke(:version) }.to output(/#{Regexp.escape(expected_version)}/).to_stdout
36
+ end
37
+ end
38
+
39
+ describe 'subcommand aliases' do
40
+ it 'maps n to new' do
41
+ expect(described_class.map['n']).to eq('new')
42
+ end
43
+
44
+ it 'maps v to version' do
45
+ expect(described_class.map['v']).to eq('version')
46
+ end
47
+
48
+ it 'maps a to adopt' do
49
+ expect(described_class.map['a']).to eq('adopt')
50
+ end
51
+
52
+ it 'maps g to generate' do
53
+ expect(described_class.map['g']).to eq('generate')
54
+ end
55
+
56
+ it 'maps u to utility' do
57
+ expect(described_class.map['u']).to eq('utility')
58
+ end
59
+
60
+ it 'maps pm to plugin_manager' do
61
+ expect(described_class.map['pm']).to eq('plugin_manager')
62
+ end
63
+ end
64
+
65
+ describe 'registered subcommands' do
66
+ let(:subcommands) { described_class.subcommands }
67
+
68
+ it 'includes adopt' do
69
+ expect(subcommands).to include('adopt')
70
+ end
71
+
72
+ it 'includes generate' do
73
+ expect(subcommands).to include('generate')
74
+ end
75
+
76
+ it 'includes utility' do
77
+ expect(subcommands).to include('utility')
78
+ 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
+ end
129
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+ require_relative '../../lib/generators/generator'
5
+
6
+ RSpec.describe Generator do
7
+ describe '#ruby_version' do
8
+ it 'returns the default version when no ruby_version arg is present' do
9
+ generator = described_class.new(%w[selenium rspec test_project])
10
+ expect(generator.ruby_version).to eq('3.4')
11
+ end
12
+
13
+ it 'returns the specified version from args' do
14
+ generator = described_class.new(%w[selenium rspec test_project ruby_version:3.3])
15
+ expect(generator.ruby_version).to eq('3.3')
16
+ end
17
+
18
+ it 'handles version with multiple colons gracefully' do
19
+ generator = described_class.new(%w[selenium rspec test_project ruby_version:3.2])
20
+ expect(generator.ruby_version).to eq('3.2')
21
+ end
22
+ end
23
+ end
@@ -63,7 +63,7 @@ describe ScaffoldingCommands do
63
63
  context 'with a features folder' do
64
64
  let(:new_path) { 'test_folder' }
65
65
 
66
- path = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::APPLITOOLS}"
66
+ path = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
67
67
 
68
68
  before do
69
69
  Dir.chdir path
@@ -43,17 +43,37 @@ describe UtilityCommands do
43
43
  expect(config['browser']).to eql ':firefox'
44
44
  end
45
45
 
46
- it 'updates the browser options', skip: 'review browser options method' do
46
+ it 'updates the browser options' do
47
47
  utility.new.invoke(:browser, nil, %w[:firefox --opts headless start-maximized start-fullscreen])
48
48
  config = YAML.load_file('config/config.yml')
49
49
  expect(config['browser_options']).to eql %w[headless start-maximized start-fullscreen]
50
50
  end
51
51
  end
52
52
 
53
+ context 'with timeout and viewport commands' do
54
+ path = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
55
+
56
+ before do
57
+ Dir.chdir path
58
+ end
59
+
60
+ it 'updates the timeout' do
61
+ utility.new.invoke(:timeout, nil, %w[30])
62
+ config = YAML.load_file('config/config.yml')
63
+ expect(config['timeout']).to eq 30
64
+ end
65
+
66
+ it 'updates the viewport' do
67
+ utility.new.invoke(:viewport, nil, %w[375x812])
68
+ config = YAML.load_file('config/config.yml')
69
+ expect(config['viewport']).to eq({ 'width' => 375, 'height' => 812 })
70
+ end
71
+ end
72
+
53
73
  context 'with a features folder' do
54
74
  let(:new_path) { 'test_folder' }
55
75
 
56
- path = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::APPLITOOLS}"
76
+ path = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
57
77
 
58
78
  before do
59
79
  Dir.chdir path
@@ -71,7 +91,7 @@ describe UtilityCommands do
71
91
  expect(config['feature_path']).to eql path
72
92
  end
73
93
 
74
- it 'updates only the browser options', skip: 'review browser options method' do
94
+ it 'updates only the browser options' do
75
95
  utility.new.invoke(:browser, nil, %w[:firefox --opts headless])
76
96
  config = YAML.load_file('config/config.yml')
77
97
  expect(config['browser_options']).to eql %w[headless]