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
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Given('I am on the home page') do
|
|
4
|
+
<% if capybara? -%>
|
|
5
|
+
visit '/'
|
|
6
|
+
<% elsif watir? -%>
|
|
7
|
+
browser.goto 'https://raider-test-site.onrender.com/'
|
|
8
|
+
<% else -%>
|
|
9
|
+
driver.get 'https://raider-test-site.onrender.com/'
|
|
10
|
+
<% end -%>
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
Then('the page should be accessible') do
|
|
14
|
+
<% if capybara? -%>
|
|
15
|
+
expect(page).to be_axe_clean
|
|
16
|
+
<% elsif watir? -%>
|
|
17
|
+
expect(browser.driver).to be_axe_clean
|
|
18
|
+
<% else -%>
|
|
19
|
+
expect(driver).to be_axe_clean
|
|
20
|
+
<% end -%>
|
|
21
|
+
end
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<%- if allure_reporter? -%>
|
|
2
|
+
default: --format AllureCucumber::CucumberFormatter --out allure-results --publish-quiet --retry 0
|
|
3
|
+
<%- else -%>
|
|
4
|
+
default: --publish-quiet --retry 0
|
|
5
|
+
<%- end -%>
|
|
6
|
+
<%- if json_reporter? -%>
|
|
7
|
+
json: --format json --out results/results.json --publish-quiet
|
|
8
|
+
<%- end -%>
|
|
@@ -4,11 +4,7 @@ Feature: Login Page
|
|
|
4
4
|
Scenario: A user can login
|
|
5
5
|
Given I'm a registered user on the login page
|
|
6
6
|
When I login with my credentials
|
|
7
|
-
<%- if axe? -%>
|
|
8
|
-
Then the page should be axe clean
|
|
9
|
-
<%- else -%>
|
|
10
7
|
Then I'm logged in
|
|
11
|
-
<% end -%>
|
|
12
8
|
|
|
13
9
|
<%- else -%>
|
|
14
10
|
Feature: Home Page
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
require 'tmpdir'
|
|
2
2
|
require_relative '../../helpers/allure_helper'
|
|
3
|
+
require_relative '../../helpers/video_helper'
|
|
3
4
|
|
|
4
5
|
Before do
|
|
5
6
|
AllureHelper.configure
|
|
6
7
|
driver.start_driver
|
|
8
|
+
@video_recorder = VideoHelper.recorder_for(driver)
|
|
9
|
+
@video_recorder&.start(self.class.to_s)
|
|
7
10
|
end
|
|
8
11
|
|
|
9
12
|
After do |scenario|
|
|
13
|
+
video_file = @video_recorder&.stop
|
|
14
|
+
AllureHelper.add_video(scenario.name, video_file)
|
|
10
15
|
Dir.mktmpdir do |temp_folder|
|
|
11
16
|
screenshot = driver.screenshot("#{temp_folder}/#{scenario.name}.png")
|
|
12
17
|
AllureHelper.add_screenshot(scenario.name, screenshot)
|
|
@@ -4,14 +4,32 @@ require 'rspec'
|
|
|
4
4
|
require 'tmpdir'
|
|
5
5
|
require_relative '../../helpers/allure_helper'
|
|
6
6
|
require_relative '../../helpers/capybara_helper'
|
|
7
|
+
require_relative '../../helpers/video_helper'
|
|
8
|
+
require_relative '../../helpers/debug_helper'
|
|
7
9
|
|
|
8
10
|
CapybaraHelper.configure
|
|
9
11
|
|
|
10
12
|
Before do
|
|
11
|
-
|
|
13
|
+
viewport = YAML.load_file('config/config.yml')['viewport']
|
|
14
|
+
if viewport
|
|
15
|
+
Capybara.current_session.driver.browser.manage.window.resize_to(viewport['width'], viewport['height'])
|
|
16
|
+
else
|
|
17
|
+
Capybara.current_session.driver.browser.manage.window.maximize
|
|
18
|
+
end
|
|
19
|
+
@video_recorder = VideoHelper.recorder_for(Capybara.current_session.driver)
|
|
20
|
+
@video_recorder&.start(self.class.to_s)
|
|
21
|
+
DebugHelper.enable_network_logging(Capybara.current_session.driver)
|
|
22
|
+
@debug_action_logger = DebugHelper.action_logger_for(self.class.to_s)
|
|
12
23
|
end
|
|
13
24
|
|
|
14
25
|
After do |scenario|
|
|
26
|
+
if scenario.failed?
|
|
27
|
+
DebugHelper.capture_failure_diagnostics(Capybara.current_session.driver, scenario.name, exception: scenario.exception)
|
|
28
|
+
DebugHelper.capture_network_logs(DebugHelper.resolve_selenium_driver(Capybara.current_session.driver), DebugHelper.sanitize(scenario.name))
|
|
29
|
+
end
|
|
30
|
+
@debug_action_logger&.close
|
|
31
|
+
video_file = @video_recorder&.stop
|
|
32
|
+
AllureHelper.add_video(scenario.name, video_file)
|
|
15
33
|
Dir.mktmpdir do |temp_folder|
|
|
16
34
|
screenshot = Capybara.page.save_screenshot("#{temp_folder}/#{scenario.name}.png")
|
|
17
35
|
AllureHelper.add_screenshot(scenario.name, screenshot)
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
require_relative '../../helpers/driver_helper'
|
|
2
|
-
<%- if visual? -%>
|
|
3
|
-
require_relative '../../helpers/visual_helper'
|
|
4
|
-
<%- end -%>
|
|
5
2
|
<%- if selenium_based? -%>
|
|
6
3
|
require_relative '../../models/user_factory'
|
|
7
4
|
|
|
8
|
-
World(DriverHelper
|
|
5
|
+
World(DriverHelper)
|
|
9
6
|
<%- else -%>
|
|
10
7
|
|
|
11
8
|
World(DriverHelper)
|
|
@@ -1,52 +1,39 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
<%- if visual? -%>
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
require_relative '../../helpers/allure_helper'
|
|
6
|
-
require_relative '../../helpers/driver_helper'
|
|
7
|
-
require_relative '../../helpers/visual_helper'
|
|
8
|
-
|
|
9
|
-
include DriverHelper
|
|
10
|
-
include VisualHelper
|
|
11
|
-
|
|
12
|
-
Before do
|
|
13
|
-
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
|
14
|
-
@grid_runner = VisualHelper.create_grid_runner
|
|
15
|
-
@eyes = VisualHelper.create_eyes(@grid_runner)
|
|
16
|
-
VisualHelper.configure_eyes @eyes
|
|
17
|
-
@driver = @eyes.open(driver: driver)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
After do |scenario|
|
|
21
|
-
Dir.mktmpdir do |temp_folder|
|
|
22
|
-
screenshot = driver.save_screenshot("#{temp_folder}/#{scenario.name}.png")
|
|
23
|
-
AllureHelper.add_screenshot(scenario.name, screenshot)
|
|
24
|
-
end
|
|
25
|
-
@eyes.close
|
|
26
|
-
@driver.quit
|
|
27
|
-
@eyes.abort_async
|
|
28
|
-
results = @grid_runner.get_all_test_results
|
|
29
|
-
puts results
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
<%- else -%>
|
|
33
|
-
|
|
34
|
-
<%- if axe? && cucumber? -%>
|
|
3
|
+
<%- if axe_addon? && cucumber? -%>
|
|
35
4
|
require 'axe-rspec'
|
|
36
5
|
<%- end -%>
|
|
37
6
|
require 'rspec'
|
|
38
7
|
require 'tmpdir'
|
|
8
|
+
require 'yaml'
|
|
39
9
|
require_relative '../../helpers/allure_helper'
|
|
10
|
+
require_relative '../../helpers/video_helper'
|
|
11
|
+
require_relative '../../helpers/debug_helper'
|
|
40
12
|
|
|
41
13
|
Before do
|
|
42
|
-
|
|
14
|
+
viewport = YAML.load_file('config/config.yml')['viewport']
|
|
15
|
+
if viewport
|
|
16
|
+
driver.manage.window.resize_to(viewport['width'], viewport['height'])
|
|
17
|
+
else
|
|
18
|
+
driver.manage.window.maximize
|
|
19
|
+
end
|
|
20
|
+
@video_recorder = VideoHelper.recorder_for(driver)
|
|
21
|
+
@video_recorder&.start(self.class.to_s)
|
|
22
|
+
DebugHelper.enable_network_logging(driver)
|
|
23
|
+
@debug_action_logger = DebugHelper.action_logger_for(self.class.to_s)
|
|
43
24
|
end
|
|
44
25
|
|
|
45
26
|
After do |scenario|
|
|
27
|
+
if scenario.failed?
|
|
28
|
+
DebugHelper.capture_failure_diagnostics(driver, scenario.name, exception: scenario.exception)
|
|
29
|
+
DebugHelper.capture_network_logs(DebugHelper.resolve_selenium_driver(driver), DebugHelper.sanitize(scenario.name))
|
|
30
|
+
end
|
|
31
|
+
@debug_action_logger&.close
|
|
32
|
+
video_file = @video_recorder&.stop
|
|
33
|
+
AllureHelper.add_video(scenario.name, video_file)
|
|
46
34
|
Dir.mktmpdir do |temp_folder|
|
|
47
35
|
screenshot = driver.save_screenshot("#{temp_folder}/#{scenario.name}.png")
|
|
48
36
|
AllureHelper.add_screenshot(scenario.name, screenshot)
|
|
49
37
|
end
|
|
50
38
|
driver.quit
|
|
51
|
-
end
|
|
52
|
-
<%- end -%>
|
|
39
|
+
end
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'tmpdir'
|
|
4
|
+
require 'yaml'
|
|
4
5
|
require_relative '../../helpers/allure_helper'
|
|
6
|
+
require_relative '../../helpers/video_helper'
|
|
7
|
+
require_relative '../../helpers/debug_helper'
|
|
5
8
|
|
|
6
9
|
Before do
|
|
7
|
-
|
|
10
|
+
viewport = YAML.load_file('config/config.yml')['viewport']
|
|
11
|
+
if viewport
|
|
12
|
+
browser.window.resize_to(viewport['width'], viewport['height'])
|
|
13
|
+
else
|
|
14
|
+
browser.window.maximize
|
|
15
|
+
end
|
|
16
|
+
@video_recorder = VideoHelper.recorder_for(browser)
|
|
17
|
+
@video_recorder&.start(self.class.to_s)
|
|
18
|
+
DebugHelper.enable_network_logging(browser)
|
|
19
|
+
@debug_action_logger = DebugHelper.action_logger_for(self.class.to_s)
|
|
8
20
|
end
|
|
9
21
|
|
|
10
22
|
After do |scenario|
|
|
23
|
+
if scenario.failed?
|
|
24
|
+
DebugHelper.capture_failure_diagnostics(browser, scenario.name, exception: scenario.exception)
|
|
25
|
+
DebugHelper.capture_network_logs(DebugHelper.resolve_selenium_driver(browser), DebugHelper.sanitize(scenario.name))
|
|
26
|
+
end
|
|
27
|
+
@debug_action_logger&.close
|
|
28
|
+
video_file = @video_recorder&.stop
|
|
29
|
+
AllureHelper.add_video(scenario.name, video_file)
|
|
11
30
|
Dir.mktmpdir do |temp_folder|
|
|
12
31
|
screenshot = browser.screenshot.save("#{temp_folder}/#{scenario.name}.png")
|
|
13
32
|
AllureHelper.add_screenshot(scenario.name, screenshot)
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Uncomment for interactive debugging:
|
|
4
|
+
# require 'debug' # Ruby's built-in debugger (binding.break)
|
|
5
|
+
# require 'pry' # Pry debugger (binding.pry)
|
|
6
|
+
|
|
3
7
|
require_relative '../../page_objects/pages/account'
|
|
4
8
|
require_relative '../../page_objects/pages/login'
|
|
5
9
|
|
|
@@ -10,22 +14,12 @@ Given("I'm a {user} on the login page") do |user|
|
|
|
10
14
|
end
|
|
11
15
|
|
|
12
16
|
When('I login with my credentials') do
|
|
17
|
+
# binding.break # Uncomment to pause here and inspect state
|
|
13
18
|
@login_page.login(@user['username'], @user['password'])
|
|
14
19
|
end
|
|
15
20
|
|
|
16
|
-
<%- if axe? -%>
|
|
17
|
-
Then('the page should be axe clean') do
|
|
18
|
-
account = Account.new(driver)
|
|
19
|
-
expect(account.page).to be_axe_clean
|
|
20
|
-
end
|
|
21
|
-
<%- else -%>
|
|
22
21
|
Then("I'm logged in") do
|
|
23
22
|
account_page = <% if capybara? %>Account.new<% elsif watir? %>Account.new(browser)<% else %>Account.new(driver)<% end %>
|
|
24
|
-
<%- if visual? -%>
|
|
25
|
-
check_page account_page
|
|
26
|
-
<%- else -%>
|
|
27
23
|
account_page.<% if capybara? %>visit_page<% else %>visit<% end %>
|
|
28
24
|
expect(account_page.header.customer_name).to eq "Welcome back #{@user['name']}"
|
|
29
|
-
|
|
30
|
-
end
|
|
31
|
-
<%- end -%>
|
|
25
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../helpers/performance_helper'
|
|
4
|
+
|
|
5
|
+
include PerformanceHelper
|
|
6
|
+
|
|
7
|
+
Given('I audit the home page performance') do
|
|
8
|
+
@result = assert_performance_above('https://raider-test-site.onrender.com/', threshold: 0.7)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Then('the performance score should be above the threshold') do
|
|
12
|
+
expect(@result[:status]).not_to eq(:error),
|
|
13
|
+
"Lighthouse error: #{@result[:message]}"
|
|
14
|
+
|
|
15
|
+
expect(@result[:passed]).to be(true),
|
|
16
|
+
"Performance below threshold (#{@result[:threshold]}): #{@result[:scores]}"
|
|
17
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../helpers/visual_helper'
|
|
4
|
+
require_relative '../../page_objects/pages/login'
|
|
5
|
+
|
|
6
|
+
include VisualHelper
|
|
7
|
+
|
|
8
|
+
Given("I'm on the login page") do
|
|
9
|
+
@login_page = <% if capybara? %>Login.new<% elsif watir? %>Login.new(browser)<% else %>Login.new(driver)<% end %>
|
|
10
|
+
@login_page.<% if capybara? %>visit_page<% else %>visit<% end %>
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
Then('the page should match the visual baseline {string}') do |baseline_name|
|
|
14
|
+
screenshot_path = <% if capybara? %>page.save_screenshot("tmp/visual_#{baseline_name}.png")<% elsif watir? %>browser.screenshot.save("tmp/visual_#{baseline_name}.png")<% else %>driver.save_screenshot("tmp/visual_#{baseline_name}.png")<% end %>
|
|
15
|
+
result = compare_screenshot(baseline_name, screenshot_path)
|
|
16
|
+
|
|
17
|
+
expect(result[:status]).not_to eq(:mismatch),
|
|
18
|
+
"Visual diff: #{(result[:diff].to_f * 100).round(2)}% difference. See: #{result[:diff_path]}"
|
|
19
|
+
end
|
data/lib/generators/generator.rb
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
require 'thor'
|
|
4
4
|
require_relative 'template_renderer'
|
|
5
5
|
|
|
6
|
-
# :reek:TooManyMethods { enabled: false }
|
|
7
6
|
class Generator < Thor::Group
|
|
8
7
|
include Thor::Actions
|
|
9
8
|
include TemplateRenderer
|
|
10
9
|
|
|
10
|
+
LATEST_RUBY = '3.4'
|
|
11
|
+
|
|
11
12
|
argument :automation
|
|
12
13
|
argument :framework
|
|
13
14
|
argument :name
|
|
@@ -64,8 +65,8 @@ class Generator < Thor::Group
|
|
|
64
65
|
args.include?('capybara')
|
|
65
66
|
end
|
|
66
67
|
|
|
67
|
-
def
|
|
68
|
-
args.include?('
|
|
68
|
+
def visual_addon?
|
|
69
|
+
args.include?('visual_addon')
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
def watir?
|
|
@@ -73,15 +74,45 @@ class Generator < Thor::Group
|
|
|
73
74
|
end
|
|
74
75
|
|
|
75
76
|
def web?
|
|
76
|
-
(args & %w[selenium watir
|
|
77
|
+
(args & %w[selenium watir capybara]).count.positive?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def axe_addon?
|
|
81
|
+
args.include?('axe_addon')
|
|
77
82
|
end
|
|
78
83
|
|
|
79
|
-
def
|
|
80
|
-
args.include?('
|
|
84
|
+
def lighthouse_addon?
|
|
85
|
+
args.include?('lighthouse_addon')
|
|
81
86
|
end
|
|
82
87
|
|
|
83
88
|
def selenium_based?
|
|
84
|
-
(
|
|
89
|
+
args.include?('selenium')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def skip_allure?
|
|
93
|
+
args.include?('skip_allure')
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def skip_video?
|
|
97
|
+
args.include?('skip_video')
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def allure_reporter?
|
|
101
|
+
has_reporter = args.any? { |a| a&.start_with?('reporter_') }
|
|
102
|
+
has_reporter ? args.include?('reporter_allure') : !skip_allure?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def junit_reporter?
|
|
106
|
+
args.include?('reporter_junit')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def json_reporter?
|
|
110
|
+
args.include?('reporter_json')
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def ruby_version
|
|
114
|
+
arg = args.find { |a| a&.start_with?('ruby_version:') }
|
|
115
|
+
arg ? arg.split(':', 2).last : LATEST_RUBY
|
|
85
116
|
end
|
|
86
117
|
|
|
87
118
|
private
|
|
@@ -9,11 +9,12 @@ class HelpersGenerator < Generator
|
|
|
9
9
|
generate_capybara_helper
|
|
10
10
|
generate_appium_helper
|
|
11
11
|
generate_allure_helper
|
|
12
|
+
generate_video_helper
|
|
13
|
+
generate_debug_helper
|
|
14
|
+
generate_visual_helper
|
|
15
|
+
generate_performance_helper
|
|
12
16
|
|
|
13
|
-
if
|
|
14
|
-
generate_visual_helper
|
|
15
|
-
generate_visual_spec_helper
|
|
16
|
-
elsif minitest?
|
|
17
|
+
if minitest?
|
|
17
18
|
generate_test_helper
|
|
18
19
|
else
|
|
19
20
|
generate_spec_helper
|
|
@@ -23,9 +24,17 @@ class HelpersGenerator < Generator
|
|
|
23
24
|
private
|
|
24
25
|
|
|
25
26
|
def generate_allure_helper
|
|
27
|
+
return unless allure_reporter?
|
|
28
|
+
|
|
26
29
|
template('helpers/allure_helper.tt', "#{name}/helpers/allure_helper.rb")
|
|
27
30
|
end
|
|
28
31
|
|
|
32
|
+
def generate_video_helper
|
|
33
|
+
return if skip_video?
|
|
34
|
+
|
|
35
|
+
template('helpers/video_helper.tt', "#{name}/helpers/video_helper.rb")
|
|
36
|
+
end
|
|
37
|
+
|
|
29
38
|
def generate_browser_helper
|
|
30
39
|
return if selenium_based? || mobile? || capybara?
|
|
31
40
|
|
|
@@ -60,13 +69,21 @@ class HelpersGenerator < Generator
|
|
|
60
69
|
template('helpers/test_helper.tt', "#{name}/helpers/test_helper.rb")
|
|
61
70
|
end
|
|
62
71
|
|
|
72
|
+
def generate_debug_helper
|
|
73
|
+
return unless web?
|
|
74
|
+
|
|
75
|
+
template('helpers/debug_helper.tt', "#{name}/helpers/debug_helper.rb")
|
|
76
|
+
end
|
|
77
|
+
|
|
63
78
|
def generate_visual_helper
|
|
79
|
+
return unless visual_addon? && web?
|
|
80
|
+
|
|
64
81
|
template('helpers/visual_helper.tt', "#{name}/helpers/visual_helper.rb")
|
|
65
82
|
end
|
|
66
83
|
|
|
67
|
-
def
|
|
68
|
-
return
|
|
84
|
+
def generate_performance_helper
|
|
85
|
+
return unless lighthouse_addon? && web?
|
|
69
86
|
|
|
70
|
-
template('helpers/
|
|
87
|
+
template('helpers/performance_helper.tt', "#{name}/helpers/performance_helper.rb")
|
|
71
88
|
end
|
|
72
89
|
end
|
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
- uses: actions/checkout@v4
|
|
15
15
|
- uses: ruby/setup-ruby@v1
|
|
16
16
|
with:
|
|
17
|
-
ruby-version:
|
|
17
|
+
ruby-version: <%= ruby_version %>.0
|
|
18
18
|
bundler-cache: true
|
|
19
19
|
|
|
20
20
|
- name: Download iOS app
|
|
@@ -63,7 +63,7 @@ jobs:
|
|
|
63
63
|
- uses: actions/checkout@v4
|
|
64
64
|
- uses: ruby/setup-ruby@v1
|
|
65
65
|
with:
|
|
66
|
-
ruby-version:
|
|
66
|
+
ruby-version: <%= ruby_version %>.0
|
|
67
67
|
bundler-cache: true
|
|
68
68
|
|
|
69
69
|
- name: Download Android app
|
|
@@ -7,8 +7,6 @@ require_relative 'helper_generator'
|
|
|
7
7
|
require_relative 'minitest/minitest_generator'
|
|
8
8
|
require_relative 'rspec/rspec_generator'
|
|
9
9
|
|
|
10
|
-
# :reek:FeatureEnvy { enabled: false }
|
|
11
|
-
# :reek:UtilityFunction { enabled: false }
|
|
12
10
|
module InvokeGenerators
|
|
13
11
|
module_function
|
|
14
12
|
|
|
@@ -16,14 +14,16 @@ module InvokeGenerators
|
|
|
16
14
|
generators = %w[Automation Common Helpers]
|
|
17
15
|
framework = structure[:framework]
|
|
18
16
|
add_generator(generators, framework.capitalize)
|
|
19
|
-
add_generator(generators, structure[:ci_platform].capitalize) if structure[:ci_platform]
|
|
17
|
+
add_generator(generators, structure[:ci_platform].capitalize) if !structure[:skip_ci] && (structure[:ci_platform])
|
|
18
|
+
extra_args = collect_skip_flags(structure)
|
|
20
19
|
generators.each do |generator|
|
|
21
20
|
invoke_generator({
|
|
22
21
|
automation: structure[:automation],
|
|
23
22
|
framework:,
|
|
24
23
|
generator:,
|
|
25
24
|
ci_platform: structure[:ci_platform],
|
|
26
|
-
name: structure[:name]
|
|
25
|
+
name: structure[:name],
|
|
26
|
+
extra_args:
|
|
27
27
|
})
|
|
28
28
|
end
|
|
29
29
|
end
|
|
@@ -32,12 +32,45 @@ module InvokeGenerators
|
|
|
32
32
|
gens.each { |generator| generators.push generator }
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
# Generator class lookup cache — avoids repeated Object.const_get string interpolation
|
|
36
|
+
GENERATOR_CLASSES = Hash.new { |h, k| h[k] = Object.const_get("#{k}Generator") }
|
|
37
|
+
|
|
35
38
|
def invoke_generator(structure = {})
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
args = [structure[:automation], structure[:framework], structure[:name], structure[:ci_platform]]
|
|
40
|
+
args.concat(structure[:extra_args] || [])
|
|
41
|
+
generator_class = GENERATOR_CLASSES[structure[:generator]]
|
|
42
|
+
generator = generator_class.new(args)
|
|
43
|
+
# Enable batch mode on the template cache to skip mtime checks during generation
|
|
44
|
+
generator.class.template_renderer.batch_mode = true if generator.class.respond_to?(:template_renderer)
|
|
45
|
+
generator.invoke_all
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def collect_skip_flags(structure)
|
|
49
|
+
flags = []
|
|
50
|
+
flags << 'skip_allure' if structure[:skip_allure]
|
|
51
|
+
flags << 'skip_video' if structure[:skip_video]
|
|
52
|
+
flags << 'axe_addon' if structure[:accessibility] && !mobile_automation?(structure[:automation])
|
|
53
|
+
flags << 'visual_addon' if structure[:visual] && !mobile_automation?(structure[:automation])
|
|
54
|
+
flags << 'lighthouse_addon' if structure[:performance] && !mobile_automation?(structure[:automation])
|
|
55
|
+
flags << "ruby_version:#{structure[:ruby_version]}" if structure[:ruby_version]
|
|
56
|
+
flags.concat(reporter_flags(structure[:reporter]))
|
|
57
|
+
flags
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def reporter_flags(reporter)
|
|
61
|
+
case reporter
|
|
62
|
+
when 'allure' then ['reporter_allure']
|
|
63
|
+
when 'junit' then ['reporter_junit']
|
|
64
|
+
when 'json' then ['reporter_json']
|
|
65
|
+
when 'both' then %w[reporter_allure reporter_junit]
|
|
66
|
+
when 'all' then %w[reporter_allure reporter_junit reporter_json]
|
|
67
|
+
when 'none' then ['reporter_none']
|
|
68
|
+
else []
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def mobile_automation?(automation)
|
|
73
|
+
%w[ios android cross_platform].include?(automation)
|
|
41
74
|
end
|
|
42
75
|
|
|
43
76
|
def to_bool(string)
|