ruby_raider 1.1.4 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/e2e_tests.yml +58 -0
- data/.github/workflows/integration.yml +4 -6
- data/.github/workflows/reek.yml +6 -5
- data/.github/workflows/release.yml +175 -0
- data/.github/workflows/rubocop.yml +7 -6
- data/.github/workflows/steep.yml +21 -0
- data/.github/workflows/system_tests.yml +83 -0
- data/.gitignore +1 -1
- data/.reek.yml +46 -4
- data/.rubocop.yml +24 -0
- data/.ruby-version +1 -1
- data/README.md +140 -77
- data/RELEASE.md +412 -0
- data/RELEASE_QUICK_GUIDE.md +77 -0
- data/Steepfile +22 -0
- data/assets/ruby_raider_logo.svg +51 -0
- data/bin/release +186 -0
- data/lib/adopter/adopt_menu.rb +146 -0
- data/lib/adopter/converters/base_converter.rb +84 -0
- data/lib/adopter/converters/identity_converter.rb +53 -0
- data/lib/adopter/migration_plan.rb +74 -0
- data/lib/adopter/migrator.rb +96 -0
- data/lib/adopter/plan_builder.rb +275 -0
- data/lib/adopter/project_analyzer.rb +252 -0
- data/lib/adopter/project_detector.rb +157 -0
- data/lib/commands/adopt_commands.rb +42 -0
- data/lib/commands/plugin_commands.rb +0 -2
- data/lib/commands/scaffolding_commands.rb +220 -37
- data/lib/commands/utility_commands.rb +82 -2
- data/lib/generators/automation/automation_generator.rb +0 -7
- data/lib/generators/automation/templates/account.tt +9 -5
- data/lib/generators/automation/templates/appium_caps.tt +60 -6
- data/lib/generators/automation/templates/home.tt +4 -4
- data/lib/generators/automation/templates/login.tt +61 -4
- data/lib/generators/automation/templates/page.tt +13 -7
- data/lib/generators/automation/templates/partials/element.tt +1 -1
- data/lib/generators/automation/templates/partials/home_page_selector.tt +4 -4
- data/lib/generators/automation/templates/partials/initialize_selector.tt +3 -8
- data/lib/generators/automation/templates/partials/pdp_page_selector.tt +4 -4
- data/lib/generators/automation/templates/partials/url_methods.tt +0 -1
- data/lib/generators/automation/templates/partials/visit_method.tt +11 -1
- data/lib/generators/automation/templates/pdp.tt +1 -1
- data/lib/generators/common_generator.rb +12 -0
- data/lib/generators/cucumber/cucumber_generator.rb +36 -0
- data/lib/generators/cucumber/templates/accessibility_feature.tt +5 -0
- data/lib/generators/cucumber/templates/accessibility_steps.tt +21 -0
- data/lib/generators/cucumber/templates/cucumber.tt +8 -1
- data/lib/generators/cucumber/templates/env.tt +6 -4
- data/lib/generators/cucumber/templates/feature.tt +0 -4
- data/lib/generators/cucumber/templates/partials/appium_env.tt +5 -0
- data/lib/generators/cucumber/templates/partials/capybara_env.tt +38 -0
- data/lib/generators/cucumber/templates/partials/capybara_world.tt +6 -0
- data/lib/generators/cucumber/templates/partials/driver_world.tt +1 -4
- data/lib/generators/cucumber/templates/partials/mobile_steps.tt +2 -2
- data/lib/generators/cucumber/templates/partials/selenium_env.tt +22 -35
- data/lib/generators/cucumber/templates/partials/watir_env.tt +20 -1
- data/lib/generators/cucumber/templates/partials/web_steps.tt +10 -15
- data/lib/generators/cucumber/templates/performance_feature.tt +5 -0
- data/lib/generators/cucumber/templates/performance_steps.tt +17 -0
- data/lib/generators/cucumber/templates/steps.tt +2 -2
- data/lib/generators/cucumber/templates/visual_feature.tt +5 -0
- data/lib/generators/cucumber/templates/visual_steps.tt +19 -0
- data/lib/generators/cucumber/templates/world.tt +5 -3
- data/lib/generators/generator.rb +50 -7
- data/lib/generators/helper_generator.rb +39 -9
- data/lib/generators/infrastructure/github_generator.rb +6 -0
- data/lib/generators/infrastructure/templates/github.tt +12 -8
- data/lib/generators/infrastructure/templates/github_appium.tt +108 -0
- data/lib/generators/infrastructure/templates/gitlab.tt +6 -3
- data/lib/generators/invoke_generators.rb +43 -9
- data/lib/generators/menu_generator.rb +122 -11
- data/lib/generators/minitest/minitest_generator.rb +35 -0
- data/lib/generators/minitest/templates/accessibility_test.tt +26 -0
- data/lib/generators/minitest/templates/performance_test.tt +18 -0
- data/lib/generators/minitest/templates/test.tt +64 -0
- data/lib/generators/minitest/templates/visual_test.tt +23 -0
- data/lib/generators/rspec/rspec_generator.rb +16 -4
- data/lib/generators/rspec/templates/accessibility_spec.tt +25 -0
- data/lib/generators/rspec/templates/performance_spec.tt +18 -0
- data/lib/generators/rspec/templates/spec.tt +13 -41
- data/lib/generators/rspec/templates/visual_spec.tt +20 -0
- data/lib/generators/template_renderer/partial_cache.rb +126 -0
- data/lib/generators/template_renderer/partial_resolver.rb +110 -0
- data/lib/generators/template_renderer/template_error.rb +50 -0
- data/lib/generators/template_renderer.rb +106 -0
- data/lib/generators/templates/common/config.tt +2 -2
- data/lib/generators/templates/common/gemfile.tt +36 -9
- data/lib/generators/templates/common/git_ignore.tt +6 -1
- data/lib/generators/templates/common/partials/mobile_config.tt +5 -1
- data/lib/generators/templates/common/partials/web_config.tt +17 -8
- data/lib/generators/templates/common/rakefile.tt +36 -0
- data/lib/generators/templates/common/read_me.tt +43 -91
- data/lib/generators/templates/common/rspec.tt +3 -0
- data/lib/generators/templates/common/ruby_version.tt +1 -0
- data/lib/generators/templates/helpers/allure_helper.tt +13 -2
- data/lib/generators/templates/helpers/browser_helper.tt +13 -2
- data/lib/generators/templates/helpers/capybara_helper.tt +32 -0
- data/lib/generators/templates/helpers/debug_helper.tt +190 -0
- data/lib/generators/templates/helpers/driver_helper.tt +3 -11
- data/lib/generators/templates/helpers/partials/allure_imports.tt +3 -1
- data/lib/generators/templates/helpers/partials/allure_requirements.tt +3 -1
- data/lib/generators/templates/helpers/partials/appium_driver.tt +44 -0
- data/lib/generators/templates/helpers/partials/browserstack_config.tt +13 -0
- data/lib/generators/templates/helpers/partials/debug_diagnostics.tt +7 -0
- data/lib/generators/templates/helpers/partials/debug_start.tt +7 -0
- data/lib/generators/templates/helpers/partials/driver_and_options.tt +5 -115
- data/lib/generators/templates/helpers/partials/quit_driver.tt +3 -1
- data/lib/generators/templates/helpers/partials/screenshot.tt +3 -1
- data/lib/generators/templates/helpers/partials/selenium_driver.tt +26 -0
- data/lib/generators/templates/helpers/partials/video_start.tt +9 -0
- data/lib/generators/templates/helpers/partials/video_stop.tt +4 -0
- data/lib/generators/templates/helpers/performance_helper.tt +57 -0
- data/lib/generators/templates/helpers/spec_helper.tt +72 -10
- data/lib/generators/templates/helpers/test_helper.tt +94 -0
- data/lib/generators/templates/helpers/video_helper.tt +270 -0
- data/lib/generators/templates/helpers/visual_helper.tt +39 -46
- data/lib/llm/client.rb +79 -0
- data/lib/llm/config.rb +57 -0
- data/lib/llm/prompts.rb +84 -0
- data/lib/llm/provider.rb +27 -0
- data/lib/llm/providers/anthropic_provider.rb +43 -0
- data/lib/llm/providers/ollama_provider.rb +56 -0
- data/lib/llm/providers/openai_provider.rb +42 -0
- data/lib/llm/response_parser.rb +67 -0
- data/lib/plugin/plugin.rb +22 -20
- data/lib/plugin/plugin_exposer.rb +16 -38
- data/lib/ruby_raider.rb +51 -11
- data/lib/scaffolding/crud_generator.rb +94 -0
- data/lib/scaffolding/dry_run_presenter.rb +16 -0
- data/lib/scaffolding/name_normalizer.rb +63 -0
- data/lib/scaffolding/page_introspector.rb +45 -0
- data/lib/scaffolding/project_detector.rb +72 -0
- data/lib/scaffolding/scaffold_menu.rb +103 -0
- data/lib/scaffolding/scaffolding.rb +158 -11
- data/lib/scaffolding/templates/component.tt +30 -0
- data/lib/scaffolding/templates/feature.tt +4 -4
- data/lib/scaffolding/templates/helper.tt +15 -1
- data/lib/scaffolding/templates/page_from_url.tt +75 -0
- data/lib/scaffolding/templates/page_object.tt +50 -1
- data/lib/scaffolding/templates/spec.tt +33 -2
- data/lib/scaffolding/templates/spec_from_page.tt +31 -0
- data/lib/scaffolding/templates/spec_from_url.tt +46 -0
- data/lib/scaffolding/templates/steps.tt +17 -5
- data/lib/scaffolding/url_analyzer.rb +179 -0
- data/lib/utilities/desktop_downloader.rb +177 -0
- data/lib/utilities/logo.rb +83 -0
- data/lib/utilities/utilities.rb +53 -20
- data/lib/version +1 -1
- data/ruby_raider.gemspec +1 -0
- data/sig/adopter/adopt_menu.rbs +25 -0
- data/sig/adopter/converters/base_converter.rbs +23 -0
- data/sig/adopter/converters/identity_converter.rbs +16 -0
- data/sig/adopter/migration_plan.rbs +34 -0
- data/sig/adopter/migrator.rbs +21 -0
- data/sig/adopter/plan_builder.rbs +38 -0
- data/sig/adopter/project_analyzer.rbs +39 -0
- data/sig/adopter/project_detector.rbs +26 -0
- data/sig/commands/adopt_commands.rbs +8 -0
- data/sig/commands/loaded_commands.rbs +5 -0
- data/sig/commands/plugin_commands.rbs +9 -0
- data/sig/commands/scaffolding_commands.rbs +28 -0
- data/sig/commands/utility_commands.rbs +21 -0
- data/sig/generators/automation/automation_generator.rbs +20 -0
- data/sig/generators/common_generator.rbs +12 -0
- data/sig/generators/cucumber/cucumber_generator.rbs +16 -0
- data/sig/generators/generator.rbs +40 -0
- data/sig/generators/helper_generator.rbs +18 -0
- data/sig/generators/infrastructure/github_generator.rbs +5 -0
- data/sig/generators/infrastructure/gitlab_generator.rbs +4 -0
- data/sig/generators/invoke_generators.rbs +10 -0
- data/sig/generators/menu_generator.rbs +29 -0
- data/sig/generators/minitest/minitest_generator.rbs +8 -0
- data/sig/generators/rspec/rspec_generator.rbs +8 -0
- data/sig/generators/template_renderer/partial_cache.rbs +20 -0
- data/sig/generators/template_renderer/partial_resolver.rbs +20 -0
- data/sig/generators/template_renderer/template_error.rbs +19 -0
- data/sig/generators/template_renderer.rbs +10 -0
- data/sig/llm/client.rbs +15 -0
- data/sig/llm/config.rbs +20 -0
- data/sig/llm/prompts.rbs +8 -0
- data/sig/llm/provider.rbs +12 -0
- data/sig/llm/providers/anthropic_provider.rbs +16 -0
- data/sig/llm/providers/ollama_provider.rbs +18 -0
- data/sig/llm/providers/openai_provider.rbs +16 -0
- data/sig/llm/response_parser.rbs +13 -0
- data/sig/plugin/plugin.rbs +24 -0
- data/sig/plugin/plugin_exposer.rbs +20 -0
- data/sig/ruby_raider.rbs +15 -0
- data/sig/scaffolding/crud_generator.rbs +16 -0
- data/sig/scaffolding/dry_run_presenter.rbs +4 -0
- data/sig/scaffolding/name_normalizer.rbs +17 -0
- data/sig/scaffolding/page_introspector.rbs +14 -0
- data/sig/scaffolding/project_detector.rbs +14 -0
- data/sig/scaffolding/scaffold_menu.rbs +18 -0
- data/sig/scaffolding/scaffolding.rbs +55 -0
- data/sig/scaffolding/url_analyzer.rbs +28 -0
- data/sig/utilities/desktop_downloader.rbs +23 -0
- data/sig/utilities/logger.rbs +13 -0
- data/sig/utilities/logo.rbs +16 -0
- data/sig/utilities/utilities.rbs +30 -0
- data/sig/vendor/thor.rbs +34 -0
- data/sig/vendor/tty_prompt.rbs +15 -0
- data/spec/adopter/adopt_menu_spec.rb +176 -0
- data/spec/adopter/converters/identity_converter_spec.rb +145 -0
- data/spec/adopter/migration_plan_spec.rb +113 -0
- data/spec/adopter/migrator_spec.rb +277 -0
- data/spec/adopter/plan_builder_spec.rb +298 -0
- data/spec/adopter/project_analyzer_spec.rb +337 -0
- data/spec/adopter/project_detector_spec.rb +295 -0
- data/spec/commands/raider_commands_spec.rb +129 -0
- data/spec/generators/fixtures/templates/test.tt +1 -0
- data/spec/generators/fixtures/templates/test_partial.tt +1 -0
- data/spec/generators/generator_spec.rb +23 -0
- data/spec/generators/template_renderer_spec.rb +298 -0
- data/spec/integration/commands/scaffolding_commands_spec.rb +2 -2
- data/spec/integration/commands/utility_commands_spec.rb +24 -4
- data/spec/integration/content/ci_content_spec.rb +119 -0
- data/spec/integration/content/common_content_spec.rb +288 -0
- data/spec/integration/content/config_content_spec.rb +175 -0
- data/spec/integration/content/content_helper.rb +32 -0
- data/spec/integration/content/gemfile_content_spec.rb +209 -0
- data/spec/integration/content/helper_content_spec.rb +485 -0
- data/spec/integration/content/page_content_spec.rb +259 -0
- data/spec/integration/content/reporter_content_spec.rb +236 -0
- data/spec/integration/content/skip_flags_content_spec.rb +206 -0
- data/spec/integration/content/syntax_validation_spec.rb +30 -0
- data/spec/integration/content/test_content_spec.rb +266 -0
- data/spec/integration/end_to_end_features_spec.rb +690 -0
- data/spec/integration/end_to_end_spec.rb +361 -0
- data/spec/integration/generators/automation_generator_spec.rb +9 -21
- data/spec/integration/generators/axe_addon_spec.rb +150 -0
- data/spec/integration/generators/common_generator_spec.rb +48 -49
- data/spec/integration/generators/config_features_spec.rb +155 -0
- data/spec/integration/generators/cucumber_generator_spec.rb +7 -7
- data/spec/integration/generators/debug_helper_spec.rb +68 -0
- data/spec/integration/generators/github_generator_spec.rb +8 -8
- data/spec/integration/generators/gitlab_generator_spec.rb +8 -8
- data/spec/integration/generators/helpers_generator_spec.rb +70 -44
- data/spec/integration/generators/lighthouse_addon_spec.rb +132 -0
- data/spec/integration/generators/minitest_generator_spec.rb +64 -0
- data/spec/integration/generators/reporter_spec.rb +159 -0
- data/spec/integration/generators/rspec_generator_spec.rb +7 -7
- data/spec/integration/generators/skip_flags_spec.rb +134 -0
- data/spec/integration/generators/visual_addon_spec.rb +148 -0
- data/spec/integration/settings_helper.rb +1 -4
- data/spec/integration/spec_helper.rb +46 -11
- data/spec/llm/client_spec.rb +79 -0
- data/spec/llm/config_spec.rb +92 -0
- data/spec/llm/prompts_spec.rb +49 -0
- data/spec/llm/response_parser_spec.rb +92 -0
- data/spec/menus/adopter_adopt_menu_spec.rb +97 -0
- data/spec/menus/menu_generator_spec.rb +263 -0
- data/spec/scaffolding/name_normalizer_spec.rb +113 -0
- data/spec/scaffolding/page_introspector_spec.rb +82 -0
- data/spec/scaffolding/scaffold_project_detector_spec.rb +104 -0
- data/spec/scaffolding/scaffolding_features_spec.rb +311 -0
- data/spec/scaffolding/url_analyzer_spec.rb +110 -0
- data/spec/system/adopt_matrix_spec.rb +537 -0
- data/spec/system/adopt_spec.rb +225 -0
- data/spec/system/capybara_spec.rb +42 -0
- data/spec/system/selenium_spec.rb +19 -17
- data/spec/system/support/system_test_helper.rb +33 -0
- data/spec/system/watir_spec.rb +19 -17
- data/spec/utilities/desktop_downloader_spec.rb +92 -0
- metadata +193 -18
- data/.github/workflows/push_gem.yml +0 -37
- data/.github/workflows/selenium.yml +0 -22
- data/.github/workflows/watir.yml +0 -22
- data/lib/generators/automation/templates/partials/android_caps.tt +0 -17
- data/lib/generators/automation/templates/partials/cross_platform_caps.tt +0 -25
- data/lib/generators/automation/templates/partials/ios_caps.tt +0 -18
- data/lib/generators/automation/templates/partials/selenium_account.tt +0 -9
- data/lib/generators/automation/templates/partials/selenium_login.tt +0 -34
- data/lib/generators/automation/templates/partials/watir_account.tt +0 -7
- data/lib/generators/automation/templates/partials/watir_login.tt +0 -32
- data/lib/generators/automation/templates/visual_options.tt +0 -16
- data/lib/generators/templates/helpers/visual_spec_helper.tt +0 -35
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Adopter
|
|
4
|
+
module ProjectDetector
|
|
5
|
+
GEM_AUTOMATION_MAP = {
|
|
6
|
+
'site_prism' => 'capybara',
|
|
7
|
+
'capybara' => 'capybara',
|
|
8
|
+
'selenium-webdriver' => 'selenium',
|
|
9
|
+
'watir' => 'watir',
|
|
10
|
+
'appium_lib' => 'appium',
|
|
11
|
+
'eyes_selenium' => 'selenium',
|
|
12
|
+
'axe-core-selenium' => 'selenium',
|
|
13
|
+
'axe-core-rspec' => 'selenium'
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
GEM_FRAMEWORK_MAP = {
|
|
17
|
+
'cucumber' => 'cucumber',
|
|
18
|
+
'rspec' => 'rspec',
|
|
19
|
+
'minitest' => 'minitest'
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
BROWSERS = %w[chrome firefox safari edge].freeze
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def detect(path = '.')
|
|
27
|
+
{
|
|
28
|
+
automation: detect_automation(path),
|
|
29
|
+
framework: detect_framework(path),
|
|
30
|
+
page_path: detect_page_path(path),
|
|
31
|
+
spec_path: detect_spec_path(path),
|
|
32
|
+
feature_path: detect_feature_path(path),
|
|
33
|
+
helper_path: detect_helper_path(path),
|
|
34
|
+
browser: detect_browser(path),
|
|
35
|
+
url: detect_url(path),
|
|
36
|
+
ci_platform: detect_ci_platform(path)
|
|
37
|
+
}.compact
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def detect_automation(path)
|
|
41
|
+
gems = parse_gemfile(path)
|
|
42
|
+
GEM_AUTOMATION_MAP.each do |gem_name, automation|
|
|
43
|
+
return automation if gems.include?(gem_name)
|
|
44
|
+
end
|
|
45
|
+
detect_automation_from_requires(path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def detect_framework(path)
|
|
49
|
+
gems = parse_gemfile(path)
|
|
50
|
+
GEM_FRAMEWORK_MAP.each do |gem_name, framework|
|
|
51
|
+
return framework if gems.include?(gem_name)
|
|
52
|
+
end
|
|
53
|
+
return 'rspec' if Dir.exist?(File.join(path, 'spec'))
|
|
54
|
+
return 'cucumber' if Dir.exist?(File.join(path, 'features'))
|
|
55
|
+
return 'minitest' if Dir.exist?(File.join(path, 'test'))
|
|
56
|
+
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def detect_page_path(path)
|
|
61
|
+
candidates = %w[page_objects/pages page_objects pages page]
|
|
62
|
+
find_existing_dir(path, candidates)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def detect_spec_path(path)
|
|
66
|
+
candidates = %w[spec spec/features spec/tests test tests]
|
|
67
|
+
find_existing_dir(path, candidates)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def detect_feature_path(path)
|
|
71
|
+
candidates = %w[features features/scenarios]
|
|
72
|
+
find_existing_dir(path, candidates)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def detect_helper_path(path)
|
|
76
|
+
candidates = %w[helpers support spec/support features/support]
|
|
77
|
+
find_existing_dir(path, candidates)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def detect_browser(path)
|
|
81
|
+
config_files = helper_and_config_files(path)
|
|
82
|
+
config_files.each do |file|
|
|
83
|
+
next unless File.exist?(file)
|
|
84
|
+
|
|
85
|
+
content = File.read(file)
|
|
86
|
+
BROWSERS.each do |browser|
|
|
87
|
+
return browser if content.match?(/(?:browser|driver)\s*[:=]\s*[:'"]?#{browser}\b/i)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def detect_url(path)
|
|
94
|
+
config_files = helper_and_config_files(path)
|
|
95
|
+
config_files.each do |file|
|
|
96
|
+
next unless File.exist?(file)
|
|
97
|
+
|
|
98
|
+
content = File.read(file)
|
|
99
|
+
match = content.match(%r{(?:base_url|url|app_host)\s*[:=]\s*['"]?(https?://[^\s'"]+)})
|
|
100
|
+
return match[1] if match
|
|
101
|
+
end
|
|
102
|
+
nil
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def detect_ci_platform(path)
|
|
106
|
+
return 'github' if Dir.exist?(File.join(path, '.github', 'workflows'))
|
|
107
|
+
return 'gitlab' if File.exist?(File.join(path, '.gitlab-ci.yml'))
|
|
108
|
+
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def parse_gemfile(path)
|
|
113
|
+
gemfile = File.join(path, 'Gemfile')
|
|
114
|
+
return [] unless File.exist?(gemfile)
|
|
115
|
+
|
|
116
|
+
File.readlines(gemfile).filter_map do |line|
|
|
117
|
+
match = line.match(/^\s*gem\s+['"]([^'"]+)['"]/)
|
|
118
|
+
match[1] if match
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def detect_automation_from_requires(path)
|
|
123
|
+
ruby_files = Dir.glob(File.join(path, '**', '*.rb'))
|
|
124
|
+
ruby_files.first(50).each do |file|
|
|
125
|
+
content = File.read(file)
|
|
126
|
+
return 'capybara' if content.include?("require 'capybara'") || content.include?("require 'site_prism'")
|
|
127
|
+
return 'selenium' if content.include?("require 'selenium-webdriver'")
|
|
128
|
+
return 'watir' if content.include?("require 'watir'")
|
|
129
|
+
return 'appium' if content.include?("require 'appium_lib'")
|
|
130
|
+
end
|
|
131
|
+
nil
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def find_existing_dir(path, candidates)
|
|
135
|
+
candidates.each do |candidate|
|
|
136
|
+
return candidate if Dir.exist?(File.join(path, candidate))
|
|
137
|
+
end
|
|
138
|
+
nil
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def helper_and_config_files(path)
|
|
142
|
+
explicit = [
|
|
143
|
+
File.join(path, 'config', 'config.yml'),
|
|
144
|
+
File.join(path, 'spec', 'spec_helper.rb'),
|
|
145
|
+
File.join(path, 'test', 'test_helper.rb'),
|
|
146
|
+
File.join(path, 'features', 'support', 'env.rb'),
|
|
147
|
+
File.join(path, 'support', 'env.rb'),
|
|
148
|
+
File.join(path, '.env')
|
|
149
|
+
]
|
|
150
|
+
helpers = Dir.glob(File.join(path, '**', '*helper*.rb')).first(10)
|
|
151
|
+
explicit + helpers
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
private_class_method :detect_automation_from_requires, :find_existing_dir,
|
|
155
|
+
:helper_and_config_files, :parse_gemfile
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor'
|
|
4
|
+
require_relative '../adopter/adopt_menu'
|
|
5
|
+
|
|
6
|
+
class AdoptCommands < Thor
|
|
7
|
+
desc 'project [SOURCE_PATH]', 'Adopts an existing test project into Ruby Raider conventions'
|
|
8
|
+
option :parameters,
|
|
9
|
+
type: :hash, required: false,
|
|
10
|
+
desc: 'Parameters to bypass the menu (output_path, target_automation, target_framework, ci_platform)',
|
|
11
|
+
aliases: 'p'
|
|
12
|
+
|
|
13
|
+
def project(source_path)
|
|
14
|
+
params = options[:parameters]
|
|
15
|
+
if params
|
|
16
|
+
parsed = params.transform_keys(&:to_sym)
|
|
17
|
+
parsed[:source_path] = source_path
|
|
18
|
+
result = Adopter::AdoptMenu.adopt(parsed)
|
|
19
|
+
print_programmatic_results(result)
|
|
20
|
+
else
|
|
21
|
+
Adopter::AdoptMenu.new.run
|
|
22
|
+
end
|
|
23
|
+
rescue Adopter::MobileProjectError => e
|
|
24
|
+
puts "Error: #{e.message}"
|
|
25
|
+
exit 1
|
|
26
|
+
rescue ArgumentError => e
|
|
27
|
+
puts "Invalid parameters: #{e.message}"
|
|
28
|
+
exit 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def print_programmatic_results(result)
|
|
34
|
+
plan = result[:plan]
|
|
35
|
+
results = result[:results]
|
|
36
|
+
puts "Adoption complete: #{results[:pages]} pages, #{results[:tests]} tests, " \
|
|
37
|
+
"#{results[:features]} features, #{results[:steps]} steps"
|
|
38
|
+
puts "Warnings: #{plan.warnings.join('; ')}" unless plan.warnings.empty?
|
|
39
|
+
puts "Errors: #{results[:errors].join('; ')}" unless results[:errors].empty?
|
|
40
|
+
puts "Output: #{plan.output_path}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -1,86 +1,166 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'thor'
|
|
4
|
+
require 'fileutils'
|
|
4
5
|
require_relative '../generators/menu_generator'
|
|
5
6
|
require_relative '../scaffolding/scaffolding'
|
|
7
|
+
require_relative '../scaffolding/name_normalizer'
|
|
8
|
+
require_relative '../scaffolding/dry_run_presenter'
|
|
9
|
+
require_relative '../scaffolding/project_detector'
|
|
6
10
|
require_relative '../commands/utility_commands'
|
|
7
11
|
|
|
8
|
-
# :reek:FeatureEnvy { enabled: false }
|
|
9
|
-
# :reek:UtilityFunction { enabled: false }
|
|
10
|
-
# :reek:RepeatedConditional { enabled: false }
|
|
11
12
|
class ScaffoldingCommands < Thor
|
|
13
|
+
class_option :dry_run, type: :boolean, default: false,
|
|
14
|
+
desc: 'Preview files without creating them', banner: ''
|
|
15
|
+
|
|
12
16
|
desc 'page [PAGE_NAME]', 'Creates a new page object'
|
|
13
|
-
option :path,
|
|
14
|
-
|
|
15
|
-
option :delete,
|
|
16
|
-
|
|
17
|
+
option :path, type: :string, required: false,
|
|
18
|
+
desc: 'The path where your page will be created', aliases: '-p'
|
|
19
|
+
option :delete, type: :boolean, required: false,
|
|
20
|
+
desc: 'This will delete the selected page', aliases: '-d'
|
|
21
|
+
option :uses, type: :array, required: false,
|
|
22
|
+
desc: 'Dependent pages to require', aliases: '-u'
|
|
17
23
|
|
|
18
24
|
def page(name)
|
|
19
25
|
return delete_scaffolding(name, 'page') if options[:delete]
|
|
26
|
+
return dry_run_preview(name, 'page') if options[:dry_run]
|
|
20
27
|
|
|
21
|
-
generate_scaffolding(name, 'page', options[:path])
|
|
28
|
+
generate_scaffolding(name, 'page', options[:path], uses: options[:uses])
|
|
22
29
|
end
|
|
23
30
|
|
|
24
31
|
desc 'feature [NAME]', 'Creates a new feature'
|
|
25
|
-
option :path,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
type: :boolean,
|
|
30
|
-
required: false, desc: 'This will delete the selected feature', aliases: '-d'
|
|
32
|
+
option :path, type: :string, required: false,
|
|
33
|
+
desc: 'The path where your feature will be created', aliases: '-p'
|
|
34
|
+
option :delete, type: :boolean, required: false,
|
|
35
|
+
desc: 'This will delete the selected feature', aliases: '-d'
|
|
31
36
|
|
|
32
37
|
def feature(name)
|
|
33
38
|
return delete_scaffolding(name, 'feature') if options[:delete]
|
|
39
|
+
return dry_run_preview(name, 'feature') if options[:dry_run]
|
|
34
40
|
|
|
35
41
|
generate_scaffolding(name, 'feature', options[:path])
|
|
36
42
|
end
|
|
37
43
|
|
|
38
44
|
desc 'spec [SPEC_NAME]', 'Creates a new spec'
|
|
39
|
-
option :path,
|
|
40
|
-
|
|
41
|
-
option :delete,
|
|
42
|
-
|
|
45
|
+
option :path, type: :string, required: false,
|
|
46
|
+
desc: 'The path where your spec will be created', aliases: '-p'
|
|
47
|
+
option :delete, type: :boolean, required: false,
|
|
48
|
+
desc: 'This will delete the selected spec', aliases: '-d'
|
|
49
|
+
option :from, type: :string, required: false,
|
|
50
|
+
desc: 'Generate spec stubs from an existing page object file', aliases: '-f'
|
|
51
|
+
option :uses, type: :array, required: false,
|
|
52
|
+
desc: 'Dependent pages to require', aliases: '-u'
|
|
53
|
+
option :ai, type: :boolean, default: false,
|
|
54
|
+
desc: 'Use LLM to generate meaningful test scenarios'
|
|
43
55
|
|
|
44
56
|
def spec(name)
|
|
45
57
|
return delete_scaffolding(name, 'spec') if options[:delete]
|
|
58
|
+
return dry_run_preview(name, 'spec') if options[:dry_run]
|
|
59
|
+
return generate_spec_from_page(name, options[:from], ai: options[:ai]) if options[:from]
|
|
46
60
|
|
|
47
|
-
generate_scaffolding(name, 'spec', options[:path])
|
|
61
|
+
generate_scaffolding(name, 'spec', options[:path], uses: options[:uses])
|
|
48
62
|
end
|
|
49
63
|
|
|
50
64
|
desc 'helper [HELPER_NAME]', 'Creates a new helper'
|
|
51
|
-
option :path,
|
|
52
|
-
|
|
53
|
-
option :delete,
|
|
54
|
-
|
|
65
|
+
option :path, type: :string, required: false,
|
|
66
|
+
desc: 'The path where your helper will be created', aliases: '-p'
|
|
67
|
+
option :delete, type: :boolean, required: false,
|
|
68
|
+
desc: 'This will delete the selected helper', aliases: '-d'
|
|
55
69
|
|
|
56
70
|
def helper(name)
|
|
57
71
|
return delete_scaffolding(name, 'helper') if options[:delete]
|
|
72
|
+
return dry_run_preview(name, 'helper') if options[:dry_run]
|
|
58
73
|
|
|
59
74
|
generate_scaffolding(name, 'helper', options[:path])
|
|
60
75
|
end
|
|
61
76
|
|
|
62
77
|
desc 'steps [STEPS_NAME]', 'Creates a new steps definition'
|
|
63
|
-
option :path,
|
|
64
|
-
|
|
65
|
-
option :delete,
|
|
66
|
-
|
|
78
|
+
option :path, type: :string, required: false,
|
|
79
|
+
desc: 'The path where your steps will be created', aliases: '-p'
|
|
80
|
+
option :delete, type: :boolean, required: false,
|
|
81
|
+
desc: 'This will delete the selected steps', aliases: '-d'
|
|
67
82
|
|
|
68
83
|
def steps(name)
|
|
69
84
|
return delete_scaffolding(name, 'steps') if options[:delete]
|
|
85
|
+
return dry_run_preview(name, 'steps') if options[:dry_run]
|
|
70
86
|
|
|
71
87
|
generate_scaffolding(name, 'steps', options[:path])
|
|
72
88
|
end
|
|
73
89
|
|
|
74
|
-
desc '
|
|
90
|
+
desc 'component [NAME]', 'Creates a component inheriting from Component'
|
|
91
|
+
option :path, type: :string, required: false,
|
|
92
|
+
desc: 'The path where your component will be created', aliases: '-p'
|
|
93
|
+
option :delete, type: :boolean, required: false,
|
|
94
|
+
desc: 'This will delete the selected component', aliases: '-d'
|
|
95
|
+
|
|
96
|
+
def component(name)
|
|
97
|
+
return delete_scaffolding(name, 'component') if options[:delete]
|
|
98
|
+
return dry_run_preview(name, 'component') if options[:dry_run]
|
|
99
|
+
|
|
100
|
+
generate_scaffolding(name, 'component', options[:path])
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
desc 'scaffold [NAMES...]', 'Generates pages, specs/features, and helpers for one or more names'
|
|
104
|
+
option :with, type: :array, required: false,
|
|
105
|
+
desc: 'Components to generate (page,spec,feature,steps,helper,component,model)', aliases: '-w'
|
|
106
|
+
option :crud, type: :boolean, required: false,
|
|
107
|
+
desc: 'Generate CRUD pages (list, create, detail, edit) + tests + model'
|
|
108
|
+
option :uses, type: :array, required: false,
|
|
109
|
+
desc: 'Dependent pages to require', aliases: '-u'
|
|
110
|
+
|
|
111
|
+
def scaffold(*names)
|
|
112
|
+
return interactive_scaffold if names.empty?
|
|
113
|
+
|
|
114
|
+
names.each do |name|
|
|
115
|
+
if options[:crud]
|
|
116
|
+
generate_crud(name)
|
|
117
|
+
elsif options[:with]
|
|
118
|
+
generate_selected_components(name, options[:with])
|
|
119
|
+
else
|
|
120
|
+
generate_default_scaffold(name)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
desc 'destroy [NAMES...]', 'Removes all scaffolded files for the given names (page, spec/feature, steps)'
|
|
126
|
+
option :with, type: :array, required: false,
|
|
127
|
+
desc: 'Components to destroy (page,spec,feature,steps,helper,component)', aliases: '-w'
|
|
128
|
+
|
|
129
|
+
def destroy(*names)
|
|
130
|
+
if names.empty?
|
|
131
|
+
say 'Please provide at least one name to destroy', :red
|
|
132
|
+
return
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
names.each { |name| destroy_scaffold(name, options[:with]) }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
map 'd' => 'destroy'
|
|
139
|
+
|
|
140
|
+
desc 'from_url [URL]', 'Generates page object and spec from a live URL'
|
|
141
|
+
option :name, type: :string, required: false,
|
|
142
|
+
desc: 'Override the page object name', aliases: '-n'
|
|
143
|
+
option :ai, type: :boolean, default: false,
|
|
144
|
+
desc: 'Use LLM for intelligent page analysis'
|
|
145
|
+
|
|
146
|
+
def from_url(url)
|
|
147
|
+
require_relative '../scaffolding/url_analyzer'
|
|
148
|
+
analyzer = UrlAnalyzer.new(url, name_override: options[:name], ai: options[:ai])
|
|
149
|
+
analysis = analyzer.analyze.to_h
|
|
75
150
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
151
|
+
page_name = analysis[:page_name]
|
|
152
|
+
|
|
153
|
+
if options[:dry_run]
|
|
154
|
+
DryRunPresenter.preview([
|
|
155
|
+
"page_objects/pages/#{page_name}.rb",
|
|
156
|
+
"spec/#{page_name}_spec.rb"
|
|
157
|
+
])
|
|
158
|
+
return
|
|
82
159
|
end
|
|
83
|
-
|
|
160
|
+
|
|
161
|
+
Scaffolding.new([page_name]).generate_page_from_url(analysis)
|
|
162
|
+
Scaffolding.new([page_name]).generate_spec_from_url(analysis)
|
|
163
|
+
say "Generated page object and spec for #{url}"
|
|
84
164
|
end
|
|
85
165
|
|
|
86
166
|
no_commands do
|
|
@@ -92,9 +172,112 @@ class ScaffoldingCommands < Thor
|
|
|
92
172
|
Scaffolding.new([name]).send("delete_#{type}")
|
|
93
173
|
end
|
|
94
174
|
|
|
95
|
-
def generate_scaffolding(name, type, path)
|
|
175
|
+
def generate_scaffolding(name, type, path, uses: nil)
|
|
96
176
|
path ||= load_config_path(type)
|
|
97
|
-
Scaffolding.new([name, path])
|
|
177
|
+
scaffolding = Scaffolding.new([name, path])
|
|
178
|
+
scaffolding.uses = Array(uses) if uses
|
|
179
|
+
scaffolding.send("generate_#{type}")
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def dry_run_preview(name, type)
|
|
183
|
+
path = options[:path] || load_config_path(type)
|
|
184
|
+
file = Scaffolding.planned_path(name, type, path)
|
|
185
|
+
DryRunPresenter.preview([file])
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def generate_default_scaffold(name)
|
|
189
|
+
uses = options[:uses]
|
|
190
|
+
if Pathname.new('spec').exist? && !Pathname.new('features').exist?
|
|
191
|
+
generate_scaffolding(name, 'spec', load_config_path('spec'), uses:)
|
|
192
|
+
else
|
|
193
|
+
generate_scaffolding(name, 'feature', load_config_path('feature'))
|
|
194
|
+
generate_scaffolding(name, 'steps', load_config_path('steps'), uses:)
|
|
195
|
+
end
|
|
196
|
+
generate_scaffolding(name, 'page', load_config_path('page'), uses:)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def generate_selected_components(name, components)
|
|
200
|
+
uses = options[:uses]
|
|
201
|
+
components.each do |comp|
|
|
202
|
+
comp = comp.downcase.strip
|
|
203
|
+
case comp
|
|
204
|
+
when 'model'
|
|
205
|
+
generate_model_data(name)
|
|
206
|
+
else
|
|
207
|
+
generate_scaffolding(name, comp, load_config_path(comp), uses:)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def generate_crud(name)
|
|
213
|
+
require_relative '../scaffolding/crud_generator'
|
|
214
|
+
if options[:dry_run]
|
|
215
|
+
crud = CrudGenerator.new(name, Scaffolding, method(:load_config_path))
|
|
216
|
+
DryRunPresenter.preview(crud.planned_files)
|
|
217
|
+
return
|
|
218
|
+
end
|
|
219
|
+
crud = CrudGenerator.new(name, Scaffolding, method(:load_config_path))
|
|
220
|
+
generated = crud.generate
|
|
221
|
+
say "Generated CRUD scaffold for: #{generated.join(', ')}"
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def generate_spec_from_page(name, source_file, ai: false) # rubocop:disable Naming/MethodParameterName
|
|
225
|
+
Scaffolding.new([name]).generate_spec_from_page(source_file, ai:)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def generate_model_data(name)
|
|
229
|
+
normalized = NameNormalizer.normalize(name)
|
|
230
|
+
path = "models/data/#{normalized}.yml"
|
|
231
|
+
return if File.exist?(path)
|
|
232
|
+
|
|
233
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
234
|
+
File.write(path, model_template(normalized))
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def model_template(name)
|
|
238
|
+
<<~YAML
|
|
239
|
+
# Data model for #{name}
|
|
240
|
+
default:
|
|
241
|
+
name: 'Test #{name.capitalize}'
|
|
242
|
+
email: 'test@example.com'
|
|
243
|
+
|
|
244
|
+
valid:
|
|
245
|
+
name: 'Valid #{name.capitalize}'
|
|
246
|
+
email: 'valid@example.com'
|
|
247
|
+
|
|
248
|
+
invalid:
|
|
249
|
+
name: ''
|
|
250
|
+
email: 'invalid'
|
|
251
|
+
YAML
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def destroy_scaffold(name, components = nil)
|
|
255
|
+
types = components ? components.map { |c| c.downcase.strip } : detect_scaffold_types
|
|
256
|
+
types.each { |type| delete_scaffolding(name, type) }
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def detect_scaffold_types
|
|
260
|
+
if Pathname.new('spec').exist? && !Pathname.new('features').exist?
|
|
261
|
+
%w[page spec]
|
|
262
|
+
else
|
|
263
|
+
%w[page feature steps]
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def interactive_scaffold
|
|
268
|
+
require_relative '../scaffolding/scaffold_menu'
|
|
269
|
+
result = ScaffoldMenu.new.run
|
|
270
|
+
return unless result
|
|
271
|
+
|
|
272
|
+
result[:names].each do |name|
|
|
273
|
+
result[:components].each do |comp|
|
|
274
|
+
if comp == :model
|
|
275
|
+
generate_model_data(name)
|
|
276
|
+
else
|
|
277
|
+
generate_scaffolding(name, comp.to_s, load_config_path(comp.to_s), uses: result[:uses])
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
98
281
|
end
|
|
99
282
|
end
|
|
100
283
|
end
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
require 'thor'
|
|
4
4
|
require_relative '../utilities/utilities'
|
|
5
5
|
|
|
6
|
-
# :reek:FeatureEnvy { enabled: false }
|
|
7
|
-
# :reek:UtilityFunction { enabled: false }
|
|
8
6
|
class UtilityCommands < Thor
|
|
9
7
|
desc 'path [PATH]', 'Sets the default path for scaffolding'
|
|
10
8
|
option :feature,
|
|
@@ -67,14 +65,96 @@ class UtilityCommands < Thor
|
|
|
67
65
|
option :delete,
|
|
68
66
|
type: :boolean, required: false, desc: 'This will delete the selected config file', aliases: '-d'
|
|
69
67
|
|
|
68
|
+
desc 'timeout [SECONDS]', 'Sets the default test timeout in seconds'
|
|
69
|
+
|
|
70
|
+
def timeout(seconds)
|
|
71
|
+
Utilities.timeout = seconds
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
desc 'viewport [DIMENSIONS]', 'Sets the default viewport size (e.g. 1920x1080, 375x812)'
|
|
75
|
+
|
|
76
|
+
def viewport(dimensions)
|
|
77
|
+
Utilities.viewport = dimensions
|
|
78
|
+
end
|
|
79
|
+
|
|
70
80
|
desc 'platform [PLATFORM]', 'Sets the default platform for a cross-platform project'
|
|
71
81
|
|
|
72
82
|
def platform(platform)
|
|
73
83
|
Utilities.platform = platform
|
|
74
84
|
end
|
|
75
85
|
|
|
86
|
+
desc 'debug [on/off]', 'Toggles debug mode for failure diagnostics and logging'
|
|
87
|
+
|
|
88
|
+
def debug(toggle)
|
|
89
|
+
enabled = %w[on true 1 yes].include?(toggle.downcase)
|
|
90
|
+
Utilities.debug = enabled
|
|
91
|
+
state = enabled ? 'enabled' : 'disabled'
|
|
92
|
+
say "Debug mode #{state}", :green
|
|
93
|
+
end
|
|
94
|
+
|
|
76
95
|
desc 'start_appium', 'It starts the appium server'
|
|
77
96
|
def start_appium
|
|
78
97
|
system 'appium --base-path /wd/hub'
|
|
79
98
|
end
|
|
99
|
+
|
|
100
|
+
desc 'desktop', 'Downloads the Raider Desktop GUI application'
|
|
101
|
+
option :path, type: :string, required: false,
|
|
102
|
+
desc: 'Directory to save the download', aliases: '-p'
|
|
103
|
+
|
|
104
|
+
def desktop
|
|
105
|
+
require_relative '../utilities/desktop_downloader'
|
|
106
|
+
version = DesktopDownloader.latest_version
|
|
107
|
+
unless version
|
|
108
|
+
say 'Could not reach GitHub releases. Check your internet connection.', :red
|
|
109
|
+
return
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
say "Raider Desktop v#{version} available for #{DesktopDownloader.platform_display_name}"
|
|
113
|
+
DesktopDownloader.download(options[:path])
|
|
114
|
+
say 'Raider Desktop downloaded successfully!', :green
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
desc 'llm [PROVIDER]', 'Configures the LLM provider (openai, anthropic, ollama)'
|
|
118
|
+
option :key, type: :string, required: false, desc: 'API key for the provider', aliases: '-k'
|
|
119
|
+
option :model, type: :string, required: false, desc: 'Model name to use', aliases: '-m'
|
|
120
|
+
option :url, type: :string, required: false, desc: 'API URL (for ollama)', aliases: '-u'
|
|
121
|
+
option :status, type: :boolean, required: false, desc: 'Show current LLM configuration', aliases: '-s'
|
|
122
|
+
|
|
123
|
+
def llm(provider = nil)
|
|
124
|
+
if options[:status] || provider.nil?
|
|
125
|
+
show_llm_status
|
|
126
|
+
return
|
|
127
|
+
end
|
|
128
|
+
configure_llm(provider)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
no_commands do
|
|
132
|
+
def configure_llm(provider)
|
|
133
|
+
unless %w[openai anthropic ollama].include?(provider)
|
|
134
|
+
say "Unknown provider '#{provider}'. Choose: openai, anthropic, ollama", :red
|
|
135
|
+
return
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
Utilities.llm_provider = provider
|
|
139
|
+
Utilities.llm_api_key = options[:key] if options[:key]
|
|
140
|
+
Utilities.llm_model = options[:model] if options[:model]
|
|
141
|
+
Utilities.llm_url = options[:url] if options[:url]
|
|
142
|
+
say "LLM configured: #{provider}", :green
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def show_llm_status
|
|
146
|
+
require_relative '../llm/client'
|
|
147
|
+
status = Llm::Client.status
|
|
148
|
+
if status[:configured]
|
|
149
|
+
say "Provider: #{status[:provider]}"
|
|
150
|
+
say "Model: #{status[:model] || 'default'}"
|
|
151
|
+
say "Available: #{status[:available] ? 'yes' : 'no'}"
|
|
152
|
+
else
|
|
153
|
+
say 'No LLM configured. Use: raider u llm <provider>', :yellow
|
|
154
|
+
say ' Providers: openai, anthropic, ollama'
|
|
155
|
+
say ' Example: raider u llm ollama'
|
|
156
|
+
say ' Example: raider u llm openai -k sk-...'
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
80
160
|
end
|
|
@@ -9,7 +9,6 @@ class AutomationGenerator < Generator
|
|
|
9
9
|
generate_home_page
|
|
10
10
|
generate_pdp_page
|
|
11
11
|
else
|
|
12
|
-
generate_visual_options
|
|
13
12
|
generate_components
|
|
14
13
|
generate_model_files
|
|
15
14
|
generate_pages
|
|
@@ -47,12 +46,6 @@ class AutomationGenerator < Generator
|
|
|
47
46
|
template('appium_caps.tt', "#{name}/config/capabilities.yml")
|
|
48
47
|
end
|
|
49
48
|
|
|
50
|
-
def generate_visual_options
|
|
51
|
-
return unless visual?
|
|
52
|
-
|
|
53
|
-
template('visual_options.tt', "#{name}/config/options.yml")
|
|
54
|
-
end
|
|
55
|
-
|
|
56
49
|
def generate_login_page
|
|
57
50
|
template('login.tt', "#{name}/page_objects/pages/login.rb")
|
|
58
51
|
end
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../abstract/page'
|
|
4
|
+
|
|
5
|
+
class Account < Page
|
|
6
|
+
def url(_page)
|
|
7
|
+
'index.php?rt=account/account'
|
|
8
|
+
end
|
|
9
|
+
end
|