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.
- checksums.yaml +4 -4
- data/.github/workflows/e2e_tests.yml +58 -0
- data/.github/workflows/steep.yml +21 -0
- data/.gitignore +1 -1
- data/.reek.yml +46 -4
- data/.ruby-version +1 -1
- data/README.md +138 -77
- data/Steepfile +22 -0
- data/assets/ruby_raider_logo.svg +51 -0
- data/lib/adopter/adopt_menu.rb +11 -15
- data/lib/adopter/converters/base_converter.rb +1 -2
- data/lib/adopter/converters/identity_converter.rb +3 -6
- data/lib/adopter/migration_plan.rb +0 -1
- data/lib/adopter/plan_builder.rb +2 -5
- data/lib/adopter/project_analyzer.rb +1 -5
- data/lib/adopter/project_detector.rb +3 -5
- data/lib/commands/adopt_commands.rb +0 -1
- 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/partials/element.tt +1 -1
- data/lib/generators/automation/templates/partials/initialize_selector.tt +0 -7
- data/lib/generators/automation/templates/partials/url_methods.tt +0 -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/feature.tt +0 -4
- data/lib/generators/cucumber/templates/partials/appium_env.tt +5 -0
- data/lib/generators/cucumber/templates/partials/capybara_env.tt +19 -1
- data/lib/generators/cucumber/templates/partials/driver_world.tt +1 -4
- 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 +6 -12
- 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/visual_feature.tt +5 -0
- data/lib/generators/cucumber/templates/visual_steps.tt +19 -0
- data/lib/generators/generator.rb +38 -7
- data/lib/generators/helper_generator.rb +24 -7
- data/lib/generators/infrastructure/templates/github.tt +1 -1
- data/lib/generators/infrastructure/templates/github_appium.tt +2 -2
- data/lib/generators/infrastructure/templates/gitlab.tt +1 -1
- data/lib/generators/invoke_generators.rb +42 -9
- data/lib/generators/menu_generator.rb +120 -11
- data/lib/generators/minitest/minitest_generator.rb +16 -4
- 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 +5 -34
- 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 +5 -35
- data/lib/generators/rspec/templates/visual_spec.tt +20 -0
- data/lib/generators/template_renderer/partial_cache.rb +11 -1
- data/lib/generators/template_renderer/partial_resolver.rb +17 -10
- data/lib/generators/template_renderer.rb +17 -1
- data/lib/generators/templates/common/gemfile.tt +21 -6
- 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 +16 -7
- data/lib/generators/templates/common/rakefile.tt +36 -0
- data/lib/generators/templates/common/read_me.tt +41 -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 +11 -0
- data/lib/generators/templates/helpers/browser_helper.tt +12 -2
- data/lib/generators/templates/helpers/capybara_helper.tt +5 -1
- data/lib/generators/templates/helpers/debug_helper.tt +190 -0
- data/lib/generators/templates/helpers/driver_helper.tt +2 -10
- data/lib/generators/templates/helpers/partials/appium_driver.tt +0 -2
- 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 +1 -3
- data/lib/generators/templates/helpers/partials/selenium_driver.tt +8 -7
- 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 +57 -8
- data/lib/generators/templates/helpers/test_helper.tt +69 -1
- 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 +47 -12
- 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 +12 -12
- data/spec/adopter/migration_plan_spec.rb +1 -1
- data/spec/adopter/migrator_spec.rb +2 -2
- data/spec/adopter/project_detector_spec.rb +1 -1
- data/spec/commands/raider_commands_spec.rb +129 -0
- data/spec/generators/generator_spec.rb +23 -0
- data/spec/integration/commands/scaffolding_commands_spec.rb +1 -1
- data/spec/integration/commands/utility_commands_spec.rb +23 -3
- 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 +52 -16
- data/spec/integration/generators/automation_generator_spec.rb +0 -12
- data/spec/integration/generators/axe_addon_spec.rb +150 -0
- data/spec/integration/generators/common_generator_spec.rb +12 -13
- data/spec/integration/generators/config_features_spec.rb +155 -0
- data/spec/integration/generators/debug_helper_spec.rb +68 -0
- data/spec/integration/generators/helpers_generator_spec.rb +0 -12
- data/spec/integration/generators/lighthouse_addon_spec.rb +132 -0
- data/spec/integration/generators/minitest_generator_spec.rb +0 -6
- data/spec/integration/generators/reporter_spec.rb +159 -0
- 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 +0 -3
- data/spec/integration/spec_helper.rb +30 -13
- 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/support/system_test_helper.rb +0 -2
- data/spec/utilities/desktop_downloader_spec.rb +92 -0
- metadata +150 -5
- data/lib/generators/automation/templates/visual_options.tt +0 -16
- data/lib/generators/templates/helpers/partials/axe_driver.tt +0 -10
- data/lib/generators/templates/helpers/visual_spec_helper.tt +0 -35
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
2
|
|
|
3
|
+
ruby '~> <%= ruby_version %>.0'
|
|
4
|
+
|
|
3
5
|
gem 'activesupport'
|
|
4
6
|
<% if mobile? %>
|
|
5
7
|
gem 'appium_lib'
|
|
6
8
|
gem 'appium_console'
|
|
7
9
|
<% end %>
|
|
10
|
+
<%- if allure_reporter? -%>
|
|
8
11
|
<%- if cucumber? -%>
|
|
9
12
|
gem 'allure-cucumber', '2.28.0'
|
|
10
13
|
<%- elsif minitest? -%>
|
|
@@ -13,24 +16,32 @@ gem 'allure-ruby-commons', '2.28.0'
|
|
|
13
16
|
gem 'allure-rspec', '2.28.0'
|
|
14
17
|
gem 'allure-ruby-commons', '2.28.0'
|
|
15
18
|
<%- end -%>
|
|
19
|
+
<%- end -%>
|
|
16
20
|
<%- if capybara? -%>
|
|
17
21
|
gem 'capybara'
|
|
18
22
|
gem 'selenium-webdriver'
|
|
19
23
|
<%- end -%>
|
|
20
|
-
<%- if
|
|
24
|
+
<%- if axe_addon? -%>
|
|
25
|
+
<%- if minitest? -%>
|
|
26
|
+
gem 'axe-core-minitest'
|
|
27
|
+
<%- else -%>
|
|
21
28
|
gem 'axe-core-rspec'
|
|
29
|
+
<%- end -%>
|
|
22
30
|
gem 'axe-core-selenium'
|
|
23
31
|
<%- end -%>
|
|
24
|
-
<%- if
|
|
25
|
-
gem '
|
|
26
|
-
gem 'eyes_universal', '~> 3.3', '>= 3.3.1'
|
|
32
|
+
<%- if visual_addon? -%>
|
|
33
|
+
gem 'chunky_png'
|
|
27
34
|
<%- end -%>
|
|
28
|
-
<%- unless visual? -%>
|
|
29
35
|
gem 'parallel_split_test'
|
|
30
36
|
gem 'parallel_tests'
|
|
31
|
-
<%- end -%>
|
|
32
37
|
gem 'rake'
|
|
33
38
|
gem 'reek'
|
|
39
|
+
<%- if rspec? -%>
|
|
40
|
+
gem 'rspec-retry'
|
|
41
|
+
<%- end -%>
|
|
42
|
+
<%- if junit_reporter? && rspec? -%>
|
|
43
|
+
gem 'rspec_junit_formatter'
|
|
44
|
+
<%- end -%>
|
|
34
45
|
gem '<%= framework %>'
|
|
35
46
|
<%- if cucumber? -%>
|
|
36
47
|
gem 'rspec'
|
|
@@ -52,3 +63,7 @@ gem 'selenium-webdriver'
|
|
|
52
63
|
<%- if watir? -%>
|
|
53
64
|
gem 'watir'
|
|
54
65
|
<%- end -%>
|
|
66
|
+
<%- if web? -%>
|
|
67
|
+
gem 'debug', '>= 1.0'
|
|
68
|
+
gem 'pry'
|
|
69
|
+
<%- end -%>
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
browser: chrome
|
|
2
2
|
url: 'https://raider-test-site.onrender.com/'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
:
|
|
7
|
-
:implicit: 10000 # 10 seconds
|
|
8
|
-
<% end -%>
|
|
3
|
+
timeout: 10 # seconds — used for implicit waits and max wait time
|
|
4
|
+
viewport:
|
|
5
|
+
width: 1920
|
|
6
|
+
height: 1080
|
|
9
7
|
|
|
10
8
|
browser_arguments:
|
|
11
9
|
chrome:
|
|
@@ -15,4 +13,15 @@ browser_arguments:
|
|
|
15
13
|
- search-engine-choice-country
|
|
16
14
|
firefox:
|
|
17
15
|
- acceptInsecureCerts
|
|
18
|
-
- no-sandbox
|
|
16
|
+
- no-sandbox
|
|
17
|
+
|
|
18
|
+
video:
|
|
19
|
+
enabled: false
|
|
20
|
+
strategy: auto # auto, cdp, or screen
|
|
21
|
+
|
|
22
|
+
debug:
|
|
23
|
+
enabled: false # also toggled by DEBUG=true env var
|
|
24
|
+
console_logs: true # capture browser console logs on failure
|
|
25
|
+
action_logging: true # log driver actions with timestamps
|
|
26
|
+
network_logging: true # capture HTTP requests on failure (Chrome/Edge only)
|
|
27
|
+
log_dir: 'debug_logs'
|
|
@@ -2,3 +2,39 @@ desc 'Print Ruby Raider version'
|
|
|
2
2
|
task :raider do
|
|
3
3
|
system 'raider version'
|
|
4
4
|
end
|
|
5
|
+
<%- if rspec? -%>
|
|
6
|
+
|
|
7
|
+
require 'rspec/core/rake_task'
|
|
8
|
+
|
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
10
|
+
RSpec::Core::RakeTask.new(:smoke) do |t|
|
|
11
|
+
t.rspec_opts = '--tag smoke'
|
|
12
|
+
end
|
|
13
|
+
RSpec::Core::RakeTask.new(:regression) do |t|
|
|
14
|
+
t.rspec_opts = '--tag regression'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
task default: :spec
|
|
18
|
+
<%- elsif cucumber? -%>
|
|
19
|
+
|
|
20
|
+
require 'cucumber/rake/task'
|
|
21
|
+
|
|
22
|
+
Cucumber::Rake::Task.new(:features)
|
|
23
|
+
Cucumber::Rake::Task.new(:smoke) do |t|
|
|
24
|
+
t.cucumber_opts = '--tags @smoke'
|
|
25
|
+
end
|
|
26
|
+
Cucumber::Rake::Task.new(:regression) do |t|
|
|
27
|
+
t.cucumber_opts = '--tags @regression'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
task default: :features
|
|
31
|
+
<%- elsif minitest? -%>
|
|
32
|
+
|
|
33
|
+
require 'rake/testtask'
|
|
34
|
+
|
|
35
|
+
Rake::TestTask.new(:test) do |t|
|
|
36
|
+
t.test_files = FileList['test/**/test_*.rb']
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
task default: :test
|
|
40
|
+
<%- end -%>
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<br />
|
|
5
5
|
<div align="center">
|
|
6
6
|
<a href="https://github.com/RubyRaider/ruby_raider">
|
|
7
|
-
<img src="https://
|
|
7
|
+
<img src="https://www.ruby-raider.com/assets/icon-DYY74ofR.png" alt="Logo" style="width:200px;">
|
|
8
8
|
</a>
|
|
9
9
|
<p align="center">
|
|
10
|
-
<a href="https://github.com/RubyRaider/ruby_raider#getting-started"><strong>Explore the docs
|
|
10
|
+
<a href="https://github.com/RubyRaider/ruby_raider#getting-started"><strong>Explore the docs</strong></a>
|
|
11
11
|
<br />
|
|
12
12
|
<br />
|
|
13
13
|
<a href="https://rubygems.org/gems/ruby_raider">Rubygems</a>
|
|
@@ -21,121 +21,71 @@
|
|
|
21
21
|
|
|
22
22
|
## What is Ruby Raider?
|
|
23
23
|
|
|
24
|
-
Ruby Raider is a generator and scaffolding gem to make UI test automation easier
|
|
24
|
+
Ruby Raider is a generator and scaffolding gem to make UI test automation easier.
|
|
25
25
|
|
|
26
|
-
###
|
|
26
|
+
### Supported Frameworks
|
|
27
27
|
|
|
28
|
-
| Web Testing Framework |
|
|
29
|
-
|
|
30
|
-
| Cucumber and Selenium | Cucumber
|
|
31
|
-
|
|
|
32
|
-
| Cucumber and Watir |
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
28
|
+
| Web Testing Framework | Mobile Testing Framework |
|
|
29
|
+
|-----------------------|------------------------------------|
|
|
30
|
+
| Cucumber and Selenium | Cucumber and Appium for iOS |
|
|
31
|
+
| RSpec and Selenium | RSpec and Appium for iOS |
|
|
32
|
+
| Cucumber and Watir | Cucumber and Appium for Android |
|
|
33
|
+
| RSpec and Watir | RSpec and Appium for Android |
|
|
34
|
+
| Cucumber and Capybara | Cucumber and Appium Cross-platform |
|
|
35
|
+
| RSpec and Capybara | RSpec and Appium Cross-platform |
|
|
36
|
+
| Minitest and Selenium | Minitest and Appium for iOS |
|
|
37
|
+
| Minitest and Watir | Minitest and Appium for Android |
|
|
38
|
+
| Minitest and Capybara | Minitest and Appium Cross-platform |
|
|
39
|
+
|
|
40
|
+
**Optional add-ons for web projects:**
|
|
41
|
+
- **Accessibility testing (axe)**: `--accessibility` flag
|
|
42
|
+
- **Visual regression testing (chunky_png)**: `--visual` flag
|
|
43
|
+
- **Performance auditing (Lighthouse)**: `--performance` flag
|
|
36
44
|
|
|
37
45
|
***The web tests run against the [Raider Test Store](https://raider-test-site.onrender.com/).***
|
|
38
46
|
|
|
39
|
-
***
|
|
40
|
-
***Remember to use the full path of the app that you download in the capabilities file and start the server using one of
|
|
41
|
-
the commands below:***
|
|
47
|
+
***To run Appium tests, download the example [app](https://github.com/RaiderHQ/raider_test_app) and start the server:***
|
|
42
48
|
|
|
43
|
-
```
|
|
49
|
+
```bash
|
|
44
50
|
raider u start_appium
|
|
45
|
-
appium --base /wd/hub
|
|
46
51
|
```
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
more [here](https://applitools.com/docs/topics/overview/obtain-api-key.html#:~:text=If%20you%20already%20have%20an,Your%20key%20will%20be%20displayed.)
|
|
50
|
-
.***
|
|
51
|
-
|
|
52
|
-
***To use the open ai integration you need to set up the OPENAI_ACCESS_TOKEN environment variable and
|
|
53
|
-
you can also set the optional OPENAI_ORGANIZATION_ID if you have an organization***
|
|
54
|
-
|
|
55
|
-
This works in all the platforms (Tested on Mac OS, Linux and Windows).
|
|
53
|
+
This works on all platforms (Mac OS, Linux and Windows).
|
|
56
54
|
|
|
57
|
-
## Getting
|
|
55
|
+
## Getting Started
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
**Just do:**
|
|
62
|
-
|
|
63
|
-
```ruby
|
|
57
|
+
```bash
|
|
64
58
|
gem install ruby_raider
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Then do:**
|
|
68
|
-
|
|
69
|
-
```ruby
|
|
70
59
|
raider new [name_of_project]
|
|
71
60
|
```
|
|
72
61
|
|
|
73
|
-
|
|
74
|
-
selected.
|
|
75
|
-
|
|
76
|
-
Select the ones you will like to work with.
|
|
62
|
+
Or with parameters:
|
|
77
63
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
```ruby
|
|
64
|
+
```bash
|
|
81
65
|
raider new [name_of_project] -p framework:[framework] automation:[automation_type]
|
|
82
66
|
```
|
|
83
67
|
|
|
84
|
-
|
|
68
|
+
### Commands
|
|
85
69
|
|
|
86
|
-
```ruby
|
|
87
|
-
raider new test_project -p framework:rspec automation:selenium
|
|
88
70
|
```
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Commands :
|
|
96
|
-
raider generate # Provides access to all the scaffolding commands
|
|
97
|
-
raider help [COMMAND] # Describe available commands or one specific command
|
|
98
|
-
raider new [PROJECT_NAME] # Creates a new framework based on settings picked
|
|
99
|
-
raider utility # Provides access to all the utility commands
|
|
100
|
-
raider version # It shows the version of Ruby Raider you are currently using
|
|
71
|
+
raider generate # Scaffolding commands
|
|
72
|
+
raider utility # Utility commands
|
|
73
|
+
raider plugin_manager # Plugin management
|
|
74
|
+
raider new [NAME] # Create new project
|
|
75
|
+
raider version # Show version
|
|
76
|
+
raider help [COMMAND] # Describe commands
|
|
101
77
|
```
|
|
102
78
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
* g for generate
|
|
106
|
-
* n for new
|
|
107
|
-
* u for utility
|
|
108
|
-
* v for version
|
|
109
|
-
|
|
110
|
-
### Scaffolding Commands
|
|
111
|
-
|
|
112
|
-
Ruby Raider also supports scaffolding:
|
|
113
|
-
|
|
114
|
-
* To create a new page object you do: ```raider g page [PAGE_NAME]```
|
|
115
|
-
* To create a new spec you do: ```raider g spec [SPEC_NAME]```
|
|
116
|
-
* To create a new feature you do: ```raider g feature [FEATURE_NAME]```
|
|
117
|
-
* To create a new steps definition you do: ```raider g steps [STEPS_NAME]```
|
|
118
|
-
* To create both a page/spec or a page/feature/steps you do: ```raider g scaffold [SCAFFOLD_NAME]```
|
|
119
|
-
|
|
120
|
-
It's possible to add the option --path or p if you want to specify where to create your features, pages, helpers and
|
|
121
|
-
specs.
|
|
79
|
+
Shortcuts: `g` (generate), `n` (new), `u` (utility), `v` (version), `pm` (plugin_manager)
|
|
122
80
|
|
|
123
|
-
|
|
81
|
+
### Scaffolding
|
|
124
82
|
|
|
125
|
-
```ruby
|
|
126
|
-
raider u path [PATH_NAME] - -feature or f
|
|
127
|
-
raider u path [PATH_NAME] - -spec or s
|
|
128
|
-
raider u path [PATH_NAME] - -helper or h
|
|
129
83
|
```
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
To initialise Appium server run this command:
|
|
136
|
-
|
|
137
|
-
```ruby
|
|
138
|
-
raider u start_appium
|
|
84
|
+
raider g page [NAME] # Create page object
|
|
85
|
+
raider g spec [NAME] # Create RSpec test
|
|
86
|
+
raider g feature [NAME] # Create Cucumber feature
|
|
87
|
+
raider g steps [NAME] # Create step definitions
|
|
88
|
+
raider g scaffold [NAME] # Create page + test + steps
|
|
139
89
|
```
|
|
140
90
|
|
|
141
91
|
### Sponsors
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= ruby_version %>
|
|
@@ -21,6 +21,17 @@ module AllureHelper
|
|
|
21
21
|
test_case: true
|
|
22
22
|
)
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
def add_video(name, file)
|
|
26
|
+
return unless file && File.exist?(file)
|
|
27
|
+
|
|
28
|
+
Allure.add_attachment(
|
|
29
|
+
name: "Recording: #{name}",
|
|
30
|
+
source: File.new(file),
|
|
31
|
+
type: 'video/mp4',
|
|
32
|
+
test_case: true
|
|
33
|
+
)
|
|
34
|
+
end
|
|
24
35
|
<%- if rspec? -%>
|
|
25
36
|
|
|
26
37
|
def formatter
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
|
3
4
|
require 'yaml'
|
|
4
5
|
require 'watir'
|
|
5
6
|
|
|
@@ -16,8 +17,17 @@ module BrowserHelper
|
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def create_browser(*args)
|
|
19
|
-
|
|
20
|
+
Watir.default_timeout = config.fetch('timeout', 10)
|
|
21
|
+
browser_name = config['browser'].to_s
|
|
22
|
+
args = args.empty? ? config['browser_arguments'][browser_name] : args
|
|
20
23
|
args += ['--headless'] if ENV['HEADLESS'] && !args.include?('--headless')
|
|
21
|
-
|
|
24
|
+
capitalized = browser_name == 'ie' ? browser_name.upcase : browser_name.capitalize
|
|
25
|
+
browser_options = "Selenium::WebDriver::#{capitalized}::Options".constantize.new(args:)
|
|
26
|
+
debug_cfg = config['debug'] || {}
|
|
27
|
+
if %w[chrome edge msedge].include?(browser_name.downcase) &&
|
|
28
|
+
(debug_cfg.fetch('enabled', false) || ENV['DEBUG']&.downcase == 'true')
|
|
29
|
+
browser_options.add_option('goog:loggingPrefs', { browser: 'ALL', performance: 'ALL' })
|
|
30
|
+
end
|
|
31
|
+
Watir::Browser.new(browser_name.to_sym, options: browser_options)
|
|
22
32
|
end
|
|
23
33
|
end
|
|
@@ -13,7 +13,7 @@ module CapybaraHelper
|
|
|
13
13
|
capybara_config.default_driver = :selenium
|
|
14
14
|
capybara_config.javascript_driver = :selenium
|
|
15
15
|
capybara_config.app_host = config['url']
|
|
16
|
-
capybara_config.default_max_wait_time = 10
|
|
16
|
+
capybara_config.default_max_wait_time = config.fetch('timeout', 10)
|
|
17
17
|
capybara_config.run_server = false
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -22,6 +22,10 @@ module CapybaraHelper
|
|
|
22
22
|
args = config['browser_arguments'][config['browser']] || []
|
|
23
23
|
args += ['--headless'] if ENV['HEADLESS'] && !args.include?('--headless')
|
|
24
24
|
options = Selenium::WebDriver::Chrome::Options.new(args:)
|
|
25
|
+
debug_cfg = config['debug'] || {}
|
|
26
|
+
if debug_cfg.fetch('enabled', false) || ENV['DEBUG']&.downcase == 'true'
|
|
27
|
+
options.add_option('goog:loggingPrefs', { browser: 'ALL', performance: 'ALL' })
|
|
28
|
+
end
|
|
25
29
|
Capybara::Selenium::Driver.new(app, browser:, options:)
|
|
26
30
|
end
|
|
27
31
|
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require 'logger'
|
|
6
|
+
require 'json'
|
|
7
|
+
|
|
8
|
+
module DebugHelper
|
|
9
|
+
LOG_DIR = 'debug_logs'
|
|
10
|
+
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# --- Configuration ---
|
|
14
|
+
|
|
15
|
+
def config
|
|
16
|
+
@config ||= begin
|
|
17
|
+
yml = YAML.load_file('config/config.yml')
|
|
18
|
+
yml['debug'] || {}
|
|
19
|
+
rescue StandardError
|
|
20
|
+
{}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def enabled?
|
|
25
|
+
ENV['DEBUG']&.downcase == 'true' || config.fetch('enabled', false)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def console_logs?
|
|
29
|
+
enabled? && config.fetch('console_logs', true)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def action_logging?
|
|
33
|
+
enabled? && config.fetch('action_logging', true)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def network_logging?
|
|
37
|
+
enabled? && config.fetch('network_logging', true)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def log_dir
|
|
41
|
+
config.fetch('log_dir', LOG_DIR)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def ensure_log_dir
|
|
45
|
+
FileUtils.mkdir_p(log_dir)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# --- Driver Resolution ---
|
|
49
|
+
|
|
50
|
+
def resolve_selenium_driver(obj)
|
|
51
|
+
if obj.respond_to?(:driver) && !obj.is_a?(Selenium::WebDriver::Driver)
|
|
52
|
+
obj.driver
|
|
53
|
+
elsif obj.respond_to?(:browser) && obj.browser.respond_to?(:driver)
|
|
54
|
+
obj.browser.driver
|
|
55
|
+
else
|
|
56
|
+
obj
|
|
57
|
+
end
|
|
58
|
+
rescue StandardError
|
|
59
|
+
obj
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# --- Failure Diagnostics (returns structured hash for desktop integration) ---
|
|
63
|
+
|
|
64
|
+
def capture_failure_diagnostics(driver_or_browser, test_name, exception: nil)
|
|
65
|
+
return {} unless enabled?
|
|
66
|
+
|
|
67
|
+
ensure_log_dir
|
|
68
|
+
sel_driver = resolve_selenium_driver(driver_or_browser)
|
|
69
|
+
safe_name = sanitize(test_name)
|
|
70
|
+
diagnostics = { test_name: test_name, timestamp: Time.now.iso8601 }
|
|
71
|
+
|
|
72
|
+
diagnostics[:url] = sel_driver.current_url rescue 'unknown'
|
|
73
|
+
diagnostics[:title] = sel_driver.title rescue 'unknown'
|
|
74
|
+
|
|
75
|
+
if exception
|
|
76
|
+
diagnostics[:error_message] = exception.message
|
|
77
|
+
diagnostics[:error_class] = exception.class.name
|
|
78
|
+
diagnostics[:stack_trace] = exception.backtrace&.first(20) || []
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
diagnostics[:console_logs] = capture_console_logs(sel_driver) if console_logs?
|
|
82
|
+
diagnostics[:network_log_path] = capture_network_logs(sel_driver, safe_name) if network_logging?
|
|
83
|
+
|
|
84
|
+
# HTML snapshot
|
|
85
|
+
html_path = File.join(log_dir, "#{safe_name}_page.html")
|
|
86
|
+
File.write(html_path, sel_driver.page_source) rescue nil
|
|
87
|
+
diagnostics[:html_snapshot] = html_path
|
|
88
|
+
|
|
89
|
+
# Write diagnostics JSON (desktop app reads this)
|
|
90
|
+
summary_path = File.join(log_dir, "#{safe_name}_diagnostics.json")
|
|
91
|
+
File.write(summary_path, JSON.pretty_generate(diagnostics))
|
|
92
|
+
diagnostics[:summary_path] = summary_path
|
|
93
|
+
|
|
94
|
+
diagnostics
|
|
95
|
+
rescue StandardError => e
|
|
96
|
+
warn "[debug] Failed to capture diagnostics: #{e.message}"
|
|
97
|
+
{}
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# --- Console Log Capture ---
|
|
101
|
+
|
|
102
|
+
def capture_console_logs(sel_driver)
|
|
103
|
+
return [] unless chrome_or_edge?(sel_driver)
|
|
104
|
+
|
|
105
|
+
sel_driver.logs.get(:browser).map { |entry| { level: entry.level, message: entry.message, timestamp: entry.timestamp } }
|
|
106
|
+
rescue StandardError
|
|
107
|
+
[]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# --- Action Logger ---
|
|
111
|
+
|
|
112
|
+
class ActionLogger
|
|
113
|
+
def initialize(test_name)
|
|
114
|
+
DebugHelper.ensure_log_dir
|
|
115
|
+
log_path = File.join(DebugHelper.log_dir, "#{DebugHelper.sanitize(test_name)}_actions.log")
|
|
116
|
+
@logger = Logger.new(log_path)
|
|
117
|
+
@logger.formatter = proc { |severity, datetime, _progname, msg|
|
|
118
|
+
"[#{datetime.strftime('%H:%M:%S.%L')}] #{severity}: #{msg}\n"
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def log(action, details = '')
|
|
123
|
+
@logger.info("#{action} #{details}".strip)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def close
|
|
127
|
+
@logger.close
|
|
128
|
+
rescue StandardError
|
|
129
|
+
nil
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
class NullActionLogger
|
|
134
|
+
def log(_action, _details = '') = nil
|
|
135
|
+
def close = nil
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def action_logger_for(test_name)
|
|
139
|
+
action_logging? ? ActionLogger.new(test_name) : NullActionLogger.new
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# --- Network Logging Setup ---
|
|
143
|
+
|
|
144
|
+
def enable_network_logging(driver_or_browser)
|
|
145
|
+
return unless network_logging?
|
|
146
|
+
|
|
147
|
+
sel_driver = resolve_selenium_driver(driver_or_browser)
|
|
148
|
+
return unless chrome_or_edge?(sel_driver)
|
|
149
|
+
|
|
150
|
+
sel_driver.execute_cdp('Network.enable')
|
|
151
|
+
rescue StandardError => e
|
|
152
|
+
warn "[debug] Could not enable network logging: #{e.message}"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# --- Network Log Capture ---
|
|
156
|
+
|
|
157
|
+
def capture_network_logs(sel_driver, safe_name)
|
|
158
|
+
return unless chrome_or_edge?(sel_driver)
|
|
159
|
+
|
|
160
|
+
logs = sel_driver.logs.get(:performance)
|
|
161
|
+
return if logs.empty?
|
|
162
|
+
|
|
163
|
+
entries = logs.filter_map do |entry|
|
|
164
|
+
parsed = JSON.parse(entry.message)['message'] rescue next
|
|
165
|
+
parsed if parsed.is_a?(Hash) && parsed['method']&.start_with?('Network.')
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
return if entries.empty?
|
|
169
|
+
|
|
170
|
+
network_path = File.join(log_dir, "#{safe_name}_network.json")
|
|
171
|
+
File.write(network_path, JSON.pretty_generate(entries))
|
|
172
|
+
network_path
|
|
173
|
+
rescue StandardError => e
|
|
174
|
+
warn "[debug] Failed to capture network logs: #{e.message}"
|
|
175
|
+
nil
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# --- Helpers ---
|
|
179
|
+
|
|
180
|
+
def chrome_or_edge?(driver)
|
|
181
|
+
browser_name = driver.capabilities[:browser_name].to_s.downcase
|
|
182
|
+
%w[chrome chromium msedge edge].any? { |b| browser_name.include?(b) }
|
|
183
|
+
rescue StandardError
|
|
184
|
+
false
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def sanitize(name)
|
|
188
|
+
name.to_s.gsub(/[^a-zA-Z0-9_-]/, '_')[0..80]
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'axe-selenium'
|
|
4
|
-
<% end -%>
|
|
2
|
+
|
|
5
3
|
require 'yaml'
|
|
6
|
-
<%- unless axe? %>
|
|
7
4
|
<%- if selenium_based? -%>
|
|
8
5
|
require 'active_support/inflector'
|
|
9
6
|
require 'selenium-webdriver'
|
|
10
7
|
<%- else -%>
|
|
11
8
|
require 'appium_lib'
|
|
12
9
|
<%- end -%>
|
|
13
|
-
<%- end -%>
|
|
14
10
|
|
|
15
11
|
module DriverHelper
|
|
16
|
-
<%- if selenium_based?
|
|
12
|
+
<%- if selenium_based? -%>
|
|
17
13
|
def driver(*opts)
|
|
18
14
|
@driver ||= create_driver(*opts)
|
|
19
15
|
end
|
|
20
|
-
<%- elsif axe? -%>
|
|
21
|
-
def driver(browser = :chrome, js_path = nil, skip_iframes = nil)
|
|
22
|
-
@driver ||= create_driver(browser, js_path, skip_iframes)
|
|
23
|
-
end
|
|
24
16
|
<%- else -%>
|
|
25
17
|
def driver
|
|
26
18
|
@driver ||= create_driver
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
@platform_caps ||= YAML.load_file('config/capabilities.yml')[platform]
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
# :reek:UtilityFunction
|
|
15
14
|
def parsed_caps
|
|
16
15
|
platform_caps['appium:options']['app'] = parse_app_path(platform_caps['appium:options']['app'])
|
|
17
16
|
platform_caps
|
|
@@ -22,7 +21,6 @@
|
|
|
22
21
|
end
|
|
23
22
|
<%- else -%>
|
|
24
23
|
|
|
25
|
-
# :reek:UtilityFunction
|
|
26
24
|
def parsed_caps
|
|
27
25
|
caps = YAML.load_file('config/capabilities.yml')
|
|
28
26
|
caps['appium:options']['app'] = app_path(caps['appium:options']['app'])
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<% if capybara? %>
|
|
2
|
+
DebugHelper.capture_failure_diagnostics(Capybara.current_session.driver, example_name, exception: @_exception)
|
|
3
|
+
<% elsif selenium_based? %>
|
|
4
|
+
DebugHelper.capture_failure_diagnostics(driver, example_name, exception: @_exception)
|
|
5
|
+
<% elsif watir? %>
|
|
6
|
+
DebugHelper.capture_failure_diagnostics(browser, example_name, exception: @_exception)
|
|
7
|
+
<% end %>
|