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,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../lib/scaffolding/url_analyzer'
|
|
4
|
+
|
|
5
|
+
RSpec.describe UrlAnalyzer do
|
|
6
|
+
subject(:analyzer) { described_class.new('https://example.com/login') }
|
|
7
|
+
|
|
8
|
+
let(:sample_html) do
|
|
9
|
+
<<~HTML
|
|
10
|
+
<html>
|
|
11
|
+
<body>
|
|
12
|
+
<form>
|
|
13
|
+
<input type="text" id="username" name="username" />
|
|
14
|
+
<input type="password" id="password" name="password" />
|
|
15
|
+
<input type="hidden" name="csrf" value="token123" />
|
|
16
|
+
<select id="role" name="role"><option>Admin</option></select>
|
|
17
|
+
<textarea id="bio" name="bio"></textarea>
|
|
18
|
+
<button id="login-btn">Log In</button>
|
|
19
|
+
<input type="submit" id="submit-btn" value="Submit" />
|
|
20
|
+
<a href="/forgot">Forgot Password</a>
|
|
21
|
+
</form>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
24
|
+
HTML
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
before do
|
|
28
|
+
stub_request = instance_double(Net::HTTPSuccess, body: sample_html)
|
|
29
|
+
allow(Net::HTTP).to receive(:get_response).and_return(stub_request)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe '#analyze' do
|
|
33
|
+
before { analyzer.analyze }
|
|
34
|
+
|
|
35
|
+
it 'parses input elements (excluding hidden)' do
|
|
36
|
+
inputs = analyzer.elements.select { |e| e[:type] == :input }
|
|
37
|
+
expect(inputs.length).to eq(2)
|
|
38
|
+
names = inputs.map { |e| e[:name] }
|
|
39
|
+
expect(names).to include('username', 'password')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'parses select elements' do
|
|
43
|
+
selects = analyzer.elements.select { |e| e[:type] == :select }
|
|
44
|
+
expect(selects.length).to eq(1)
|
|
45
|
+
expect(selects.first[:name]).to eq('role')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'parses textarea elements' do
|
|
49
|
+
textareas = analyzer.elements.select { |e| e[:type] == :textarea }
|
|
50
|
+
expect(textareas.length).to eq(1)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'parses button elements' do
|
|
54
|
+
buttons = analyzer.elements.select { |e| e[:type] == :button }
|
|
55
|
+
expect(buttons.length).to eq(1)
|
|
56
|
+
expect(buttons.first[:text]).to eq('Log In')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'parses submit inputs' do
|
|
60
|
+
submits = analyzer.elements.select { |e| e[:type] == :submit }
|
|
61
|
+
expect(submits.length).to eq(1)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'parses link elements' do
|
|
65
|
+
links = analyzer.elements.select { |e| e[:type] == :link }
|
|
66
|
+
expect(links.length).to eq(1)
|
|
67
|
+
expect(links.first[:name]).to eq('forgot_password')
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'prefers id locators' do
|
|
71
|
+
username = analyzer.elements.find { |e| e[:name] == 'username' }
|
|
72
|
+
expect(username[:locator]).to eq(type: :id, value: 'username')
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe '#page_name' do
|
|
77
|
+
it 'derives name from URL path' do
|
|
78
|
+
expect(analyzer.page_name).to eq('login')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'uses name override when provided' do
|
|
82
|
+
custom = described_class.new('https://example.com/login', name_override: 'auth')
|
|
83
|
+
expect(custom.page_name).to eq('auth')
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'defaults to home for root URL' do
|
|
87
|
+
root = described_class.new('https://example.com/')
|
|
88
|
+
expect(root.page_name).to eq('home')
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe '#to_h' do
|
|
93
|
+
it 'returns structured hash' do
|
|
94
|
+
analyzer.analyze
|
|
95
|
+
result = analyzer.to_h
|
|
96
|
+
expect(result).to include(:page_name, :url, :url_path, :elements)
|
|
97
|
+
expect(result[:url_path]).to eq('/login')
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe 'AI mode' do
|
|
102
|
+
let(:ai_analyzer) { described_class.new('https://example.com/login', ai: true) }
|
|
103
|
+
|
|
104
|
+
it 'falls back to regex parsing when LLM is unavailable' do
|
|
105
|
+
allow_any_instance_of(described_class).to receive(:analyze_with_llm).and_return(nil)
|
|
106
|
+
ai_analyzer.analyze
|
|
107
|
+
expect(ai_analyzer.elements).not_to be_empty
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require_relative '../../lib/adopter/adopt_menu'
|
|
6
|
+
|
|
7
|
+
describe 'Adopt matrix: all target combinations' do
|
|
8
|
+
source_dir = 'tmp_adopt_matrix_source'
|
|
9
|
+
|
|
10
|
+
before(:all) do # rubocop:disable RSpec/BeforeAfterAll
|
|
11
|
+
FileUtils.mkdir_p("#{source_dir}/pages")
|
|
12
|
+
FileUtils.mkdir_p("#{source_dir}/spec")
|
|
13
|
+
FileUtils.mkdir_p("#{source_dir}/features/step_definitions")
|
|
14
|
+
|
|
15
|
+
File.write("#{source_dir}/Gemfile", <<~GEMFILE)
|
|
16
|
+
gem 'rspec'
|
|
17
|
+
gem 'selenium-webdriver'
|
|
18
|
+
gem 'faker'
|
|
19
|
+
gem 'dotenv'
|
|
20
|
+
GEMFILE
|
|
21
|
+
|
|
22
|
+
File.write("#{source_dir}/pages/login_page.rb", <<~RUBY)
|
|
23
|
+
class LoginPage < BasePage
|
|
24
|
+
def login(user, pass)
|
|
25
|
+
driver.find_element(id: 'user').send_keys user
|
|
26
|
+
driver.find_element(id: 'pass').send_keys pass
|
|
27
|
+
driver.find_element(id: 'submit').click
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
RUBY
|
|
31
|
+
|
|
32
|
+
File.write("#{source_dir}/pages/dashboard_page.rb", <<~RUBY)
|
|
33
|
+
class DashboardPage < BasePage
|
|
34
|
+
def welcome_message
|
|
35
|
+
driver.find_element(css: '.welcome').text
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
RUBY
|
|
39
|
+
|
|
40
|
+
File.write("#{source_dir}/spec/login_spec.rb", <<~RUBY)
|
|
41
|
+
describe 'Login' do
|
|
42
|
+
it 'can log in' do
|
|
43
|
+
page = LoginPage.new(driver)
|
|
44
|
+
page.login('admin', 'secret')
|
|
45
|
+
expect(page).to be_truthy
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
RUBY
|
|
49
|
+
|
|
50
|
+
File.write("#{source_dir}/spec/dashboard_spec.rb", <<~RUBY)
|
|
51
|
+
describe 'Dashboard' do
|
|
52
|
+
it 'shows welcome' do
|
|
53
|
+
expect(true).to eq true
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
RUBY
|
|
57
|
+
|
|
58
|
+
File.write("#{source_dir}/features/login.feature", <<~GHERKIN)
|
|
59
|
+
Feature: Login
|
|
60
|
+
Scenario: Valid login
|
|
61
|
+
Given I am on the login page
|
|
62
|
+
When I log in with valid credentials
|
|
63
|
+
Then I see the dashboard
|
|
64
|
+
GHERKIN
|
|
65
|
+
|
|
66
|
+
File.write("#{source_dir}/features/step_definitions/login_steps.rb", <<~RUBY)
|
|
67
|
+
Given('I am on the login page') do
|
|
68
|
+
@page = LoginPage.new(driver)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
When('I log in with valid credentials') do
|
|
72
|
+
@page.login('admin', 'secret')
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
Then('I see the dashboard') do
|
|
76
|
+
expect(true).to eq true
|
|
77
|
+
end
|
|
78
|
+
RUBY
|
|
79
|
+
|
|
80
|
+
# Generate all 9 combinations
|
|
81
|
+
Adopter::AdoptMenu::WEB_AUTOMATIONS.each do |automation|
|
|
82
|
+
Adopter::AdoptMenu::TEST_FRAMEWORKS.each do |framework|
|
|
83
|
+
output = "tmp_adopt_matrix_#{automation}_#{framework}"
|
|
84
|
+
Adopter::AdoptMenu.adopt(
|
|
85
|
+
source_path: source_dir,
|
|
86
|
+
output_path: output,
|
|
87
|
+
target_automation: automation,
|
|
88
|
+
target_framework: framework
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
after(:all) do # rubocop:disable RSpec/BeforeAfterAll
|
|
95
|
+
FileUtils.rm_rf(source_dir)
|
|
96
|
+
Adopter::AdoptMenu::WEB_AUTOMATIONS.each do |automation|
|
|
97
|
+
Adopter::AdoptMenu::TEST_FRAMEWORKS.each do |framework|
|
|
98
|
+
FileUtils.rm_rf("tmp_adopt_matrix_#{automation}_#{framework}")
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# --- Shared examples ---
|
|
104
|
+
|
|
105
|
+
shared_examples 'valid adopted project structure' do |output_dir|
|
|
106
|
+
it 'creates Gemfile' do
|
|
107
|
+
expect(File).to exist("#{output_dir}/Gemfile")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it 'creates Rakefile' do
|
|
111
|
+
expect(File).to exist("#{output_dir}/Rakefile")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it 'creates Readme.md' do
|
|
115
|
+
expect(File).to exist("#{output_dir}/Readme.md")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'creates .rubocop.yml' do
|
|
119
|
+
expect(File).to exist("#{output_dir}/.rubocop.yml")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'creates config/config.yml' do
|
|
123
|
+
expect(File).to exist("#{output_dir}/config/config.yml")
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'creates page_objects directory' do
|
|
127
|
+
expect(File).to exist("#{output_dir}/page_objects/pages")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it 'creates abstract page' do
|
|
131
|
+
expect(File).to exist("#{output_dir}/page_objects/abstract/page.rb")
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
shared_examples 'converted pages' do |output_dir|
|
|
136
|
+
it 'converts login page into raider path' do
|
|
137
|
+
expect(File).to exist("#{output_dir}/page_objects/pages/login.rb")
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'converts dashboard page into raider path' do
|
|
141
|
+
expect(File).to exist("#{output_dir}/page_objects/pages/dashboard.rb")
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'adds frozen_string_literal to login page' do
|
|
145
|
+
page = File.read("#{output_dir}/page_objects/pages/login.rb")
|
|
146
|
+
expect(page).to include('# frozen_string_literal: true')
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'updates login page base class to Page' do
|
|
150
|
+
page = File.read("#{output_dir}/page_objects/pages/login.rb")
|
|
151
|
+
expect(page).to include('class LoginPage < Page')
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it 'updates dashboard page base class to Page' do
|
|
155
|
+
page = File.read("#{output_dir}/page_objects/pages/dashboard.rb")
|
|
156
|
+
expect(page).to include('class DashboardPage < Page')
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
shared_examples 'merged gems' do |output_dir|
|
|
161
|
+
it 'includes custom gems from source' do
|
|
162
|
+
gemfile = File.read("#{output_dir}/Gemfile")
|
|
163
|
+
expect(gemfile).to include("gem 'faker'")
|
|
164
|
+
expect(gemfile).to include("gem 'dotenv'")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'does not duplicate framework gems' do
|
|
168
|
+
gemfile = File.read("#{output_dir}/Gemfile")
|
|
169
|
+
occurrences = gemfile.scan("gem 'rspec'").length + gemfile.scan("gem 'selenium-webdriver'").length
|
|
170
|
+
expect(occurrences).to be <= 2
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
shared_examples 'allure helper' do |output_dir|
|
|
175
|
+
it 'creates allure_helper.rb' do
|
|
176
|
+
expect(File).to exist("#{output_dir}/helpers/allure_helper.rb")
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'allure_helper defines AllureHelper module' do
|
|
180
|
+
content = File.read("#{output_dir}/helpers/allure_helper.rb")
|
|
181
|
+
expect(content).to include('module AllureHelper')
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# --- Automation-specific helpers ---
|
|
186
|
+
|
|
187
|
+
shared_examples 'selenium helpers' do |output_dir|
|
|
188
|
+
it 'creates driver_helper.rb' do
|
|
189
|
+
expect(File).to exist("#{output_dir}/helpers/driver_helper.rb")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it 'driver_helper defines DriverHelper module' do
|
|
193
|
+
content = File.read("#{output_dir}/helpers/driver_helper.rb")
|
|
194
|
+
expect(content).to include('module DriverHelper')
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it 'driver_helper requires selenium-webdriver' do
|
|
198
|
+
content = File.read("#{output_dir}/helpers/driver_helper.rb")
|
|
199
|
+
expect(content).to include("require 'selenium-webdriver'")
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it 'does not create browser_helper.rb' do
|
|
203
|
+
expect(File).not_to exist("#{output_dir}/helpers/browser_helper.rb")
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it 'does not create capybara_helper.rb' do
|
|
207
|
+
expect(File).not_to exist("#{output_dir}/helpers/capybara_helper.rb")
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
shared_examples 'watir helpers' do |output_dir|
|
|
212
|
+
it 'creates browser_helper.rb' do
|
|
213
|
+
expect(File).to exist("#{output_dir}/helpers/browser_helper.rb")
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it 'browser_helper defines BrowserHelper module' do
|
|
217
|
+
content = File.read("#{output_dir}/helpers/browser_helper.rb")
|
|
218
|
+
expect(content).to include('module BrowserHelper')
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it 'browser_helper requires watir' do
|
|
222
|
+
content = File.read("#{output_dir}/helpers/browser_helper.rb")
|
|
223
|
+
expect(content).to include("require 'watir'")
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it 'does not create driver_helper.rb' do
|
|
227
|
+
expect(File).not_to exist("#{output_dir}/helpers/driver_helper.rb")
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'does not create capybara_helper.rb' do
|
|
231
|
+
expect(File).not_to exist("#{output_dir}/helpers/capybara_helper.rb")
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
shared_examples 'capybara helpers' do |output_dir|
|
|
236
|
+
it 'creates capybara_helper.rb' do
|
|
237
|
+
expect(File).to exist("#{output_dir}/helpers/capybara_helper.rb")
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it 'capybara_helper defines CapybaraHelper module' do
|
|
241
|
+
content = File.read("#{output_dir}/helpers/capybara_helper.rb")
|
|
242
|
+
expect(content).to include('module CapybaraHelper')
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
it 'capybara_helper requires capybara' do
|
|
246
|
+
content = File.read("#{output_dir}/helpers/capybara_helper.rb")
|
|
247
|
+
expect(content).to include("require 'capybara'")
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
it 'does not create driver_helper.rb' do
|
|
251
|
+
expect(File).not_to exist("#{output_dir}/helpers/driver_helper.rb")
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
it 'does not create browser_helper.rb' do
|
|
255
|
+
expect(File).not_to exist("#{output_dir}/helpers/browser_helper.rb")
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# --- Framework-specific structure ---
|
|
260
|
+
|
|
261
|
+
shared_examples 'rspec structure' do |output_dir|
|
|
262
|
+
it 'creates spec directory' do
|
|
263
|
+
expect(File).to exist("#{output_dir}/spec")
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it 'creates spec_helper.rb' do
|
|
267
|
+
expect(File).to exist("#{output_dir}/helpers/spec_helper.rb")
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it 'spec_helper defines SpecHelper module' do
|
|
271
|
+
content = File.read("#{output_dir}/helpers/spec_helper.rb")
|
|
272
|
+
expect(content).to include('module SpecHelper')
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it 'converts source tests into spec directory' do
|
|
276
|
+
expect(File).to exist("#{output_dir}/spec/login_spec.rb")
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'converts dashboard test into spec directory' do
|
|
280
|
+
expect(File).to exist("#{output_dir}/spec/dashboard_spec.rb")
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it 'does not create test directory' do
|
|
284
|
+
expect(Dir).not_to exist("#{output_dir}/test")
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
it 'does not create features directory with step definitions' do
|
|
288
|
+
expect(File).not_to exist("#{output_dir}/features/step_definitions/login_steps.rb")
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
shared_examples 'cucumber structure' do |output_dir|
|
|
293
|
+
it 'creates features directory' do
|
|
294
|
+
expect(File).to exist("#{output_dir}/features")
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
it 'creates features/support/env.rb' do
|
|
298
|
+
expect(File).to exist("#{output_dir}/features/support/env.rb")
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
it 'creates cucumber.yml' do
|
|
302
|
+
expect(File).to exist("#{output_dir}/cucumber.yml")
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
it 'copies feature files' do
|
|
306
|
+
expect(File).to exist("#{output_dir}/features/login.feature")
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
it 'feature files contain Gherkin keywords' do
|
|
310
|
+
content = File.read("#{output_dir}/features/login.feature")
|
|
311
|
+
expect(content).to include('Feature:')
|
|
312
|
+
expect(content).to include('Scenario:')
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it 'copies step definitions' do
|
|
316
|
+
expect(File).to exist("#{output_dir}/features/step_definitions/login_steps.rb")
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
it 'does not create spec directory with converted tests' do
|
|
320
|
+
expect(File).not_to exist("#{output_dir}/spec/login_spec.rb")
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it 'does not create test directory' do
|
|
324
|
+
expect(Dir).not_to exist("#{output_dir}/test")
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
shared_examples 'minitest structure' do |output_dir|
|
|
329
|
+
it 'creates test directory' do
|
|
330
|
+
expect(File).to exist("#{output_dir}/test")
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it 'creates test_helper.rb' do
|
|
334
|
+
expect(File).to exist("#{output_dir}/helpers/test_helper.rb")
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
it 'test_helper defines TestHelper module' do
|
|
338
|
+
content = File.read("#{output_dir}/helpers/test_helper.rb")
|
|
339
|
+
expect(content).to include('module TestHelper')
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
it 'test_helper requires minitest/autorun' do
|
|
343
|
+
content = File.read("#{output_dir}/helpers/test_helper.rb")
|
|
344
|
+
expect(content).to include("require 'minitest/autorun'")
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
it 'converts source tests into test directory' do
|
|
348
|
+
expect(File).to exist("#{output_dir}/test/test_login.rb")
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
it 'does not create spec directory with converted tests' do
|
|
352
|
+
expect(File).not_to exist("#{output_dir}/spec/login_spec.rb")
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
it 'does not create features directory with step definitions' do
|
|
356
|
+
expect(File).not_to exist("#{output_dir}/features/step_definitions/login_steps.rb")
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# --- Automation-framework helper wiring ---
|
|
361
|
+
|
|
362
|
+
shared_examples 'rspec wired to selenium' do |output_dir|
|
|
363
|
+
it 'spec_helper includes DriverHelper' do
|
|
364
|
+
content = File.read("#{output_dir}/helpers/spec_helper.rb")
|
|
365
|
+
expect(content).to include('DriverHelper')
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
it 'spec_helper requires driver_helper' do
|
|
369
|
+
content = File.read("#{output_dir}/helpers/spec_helper.rb")
|
|
370
|
+
expect(content).to include("require_relative 'driver_helper'")
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
shared_examples 'rspec wired to watir' do |output_dir|
|
|
375
|
+
it 'spec_helper includes BrowserHelper' do
|
|
376
|
+
content = File.read("#{output_dir}/helpers/spec_helper.rb")
|
|
377
|
+
expect(content).to include('BrowserHelper')
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
it 'spec_helper requires browser_helper' do
|
|
381
|
+
content = File.read("#{output_dir}/helpers/spec_helper.rb")
|
|
382
|
+
expect(content).to include("require_relative 'browser_helper'")
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
shared_examples 'rspec wired to capybara' do |output_dir|
|
|
387
|
+
it 'spec_helper includes Capybara::DSL' do
|
|
388
|
+
content = File.read("#{output_dir}/helpers/spec_helper.rb")
|
|
389
|
+
expect(content).to include('Capybara::DSL')
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
it 'spec_helper requires capybara_helper' do
|
|
393
|
+
content = File.read("#{output_dir}/helpers/spec_helper.rb")
|
|
394
|
+
expect(content).to include("require_relative 'capybara_helper'")
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
shared_examples 'minitest wired to selenium' do |output_dir|
|
|
399
|
+
it 'test_helper includes DriverHelper' do
|
|
400
|
+
content = File.read("#{output_dir}/helpers/test_helper.rb")
|
|
401
|
+
expect(content).to include('DriverHelper')
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
it 'test_helper requires driver_helper' do
|
|
405
|
+
content = File.read("#{output_dir}/helpers/test_helper.rb")
|
|
406
|
+
expect(content).to include("require_relative 'driver_helper'")
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
shared_examples 'minitest wired to watir' do |output_dir|
|
|
411
|
+
it 'test_helper includes BrowserHelper' do
|
|
412
|
+
content = File.read("#{output_dir}/helpers/test_helper.rb")
|
|
413
|
+
expect(content).to include('BrowserHelper')
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it 'test_helper requires browser_helper' do
|
|
417
|
+
content = File.read("#{output_dir}/helpers/test_helper.rb")
|
|
418
|
+
expect(content).to include("require_relative 'browser_helper'")
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
shared_examples 'minitest wired to capybara' do |output_dir|
|
|
423
|
+
it 'test_helper includes Capybara::DSL' do
|
|
424
|
+
content = File.read("#{output_dir}/helpers/test_helper.rb")
|
|
425
|
+
expect(content).to include('Capybara::DSL')
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
it 'test_helper requires capybara_helper' do
|
|
429
|
+
content = File.read("#{output_dir}/helpers/test_helper.rb")
|
|
430
|
+
expect(content).to include("require_relative 'capybara_helper'")
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# === The 9 combinations (3 automations x 3 frameworks) ===
|
|
435
|
+
|
|
436
|
+
# --- Selenium ---
|
|
437
|
+
|
|
438
|
+
context 'selenium + rspec' do
|
|
439
|
+
output = 'tmp_adopt_matrix_selenium_rspec'
|
|
440
|
+
it_behaves_like 'valid adopted project structure', output
|
|
441
|
+
it_behaves_like 'converted pages', output
|
|
442
|
+
it_behaves_like 'merged gems', output
|
|
443
|
+
it_behaves_like 'allure helper', output
|
|
444
|
+
it_behaves_like 'selenium helpers', output
|
|
445
|
+
it_behaves_like 'rspec structure', output
|
|
446
|
+
it_behaves_like 'rspec wired to selenium', output
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
context 'selenium + cucumber' do
|
|
450
|
+
output = 'tmp_adopt_matrix_selenium_cucumber'
|
|
451
|
+
it_behaves_like 'valid adopted project structure', output
|
|
452
|
+
it_behaves_like 'converted pages', output
|
|
453
|
+
it_behaves_like 'merged gems', output
|
|
454
|
+
it_behaves_like 'allure helper', output
|
|
455
|
+
it_behaves_like 'selenium helpers', output
|
|
456
|
+
it_behaves_like 'cucumber structure', output
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
context 'selenium + minitest' do
|
|
460
|
+
output = 'tmp_adopt_matrix_selenium_minitest'
|
|
461
|
+
it_behaves_like 'valid adopted project structure', output
|
|
462
|
+
it_behaves_like 'converted pages', output
|
|
463
|
+
it_behaves_like 'merged gems', output
|
|
464
|
+
it_behaves_like 'allure helper', output
|
|
465
|
+
it_behaves_like 'selenium helpers', output
|
|
466
|
+
it_behaves_like 'minitest structure', output
|
|
467
|
+
it_behaves_like 'minitest wired to selenium', output
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
# --- Capybara ---
|
|
471
|
+
|
|
472
|
+
context 'capybara + rspec' do
|
|
473
|
+
output = 'tmp_adopt_matrix_capybara_rspec'
|
|
474
|
+
it_behaves_like 'valid adopted project structure', output
|
|
475
|
+
it_behaves_like 'converted pages', output
|
|
476
|
+
it_behaves_like 'merged gems', output
|
|
477
|
+
it_behaves_like 'allure helper', output
|
|
478
|
+
it_behaves_like 'capybara helpers', output
|
|
479
|
+
it_behaves_like 'rspec structure', output
|
|
480
|
+
it_behaves_like 'rspec wired to capybara', output
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
context 'capybara + cucumber' do
|
|
484
|
+
output = 'tmp_adopt_matrix_capybara_cucumber'
|
|
485
|
+
it_behaves_like 'valid adopted project structure', output
|
|
486
|
+
it_behaves_like 'converted pages', output
|
|
487
|
+
it_behaves_like 'merged gems', output
|
|
488
|
+
it_behaves_like 'allure helper', output
|
|
489
|
+
it_behaves_like 'capybara helpers', output
|
|
490
|
+
it_behaves_like 'cucumber structure', output
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
context 'capybara + minitest' do
|
|
494
|
+
output = 'tmp_adopt_matrix_capybara_minitest'
|
|
495
|
+
it_behaves_like 'valid adopted project structure', output
|
|
496
|
+
it_behaves_like 'converted pages', output
|
|
497
|
+
it_behaves_like 'merged gems', output
|
|
498
|
+
it_behaves_like 'allure helper', output
|
|
499
|
+
it_behaves_like 'capybara helpers', output
|
|
500
|
+
it_behaves_like 'minitest structure', output
|
|
501
|
+
it_behaves_like 'minitest wired to capybara', output
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# --- Watir ---
|
|
505
|
+
|
|
506
|
+
context 'watir + rspec' do
|
|
507
|
+
output = 'tmp_adopt_matrix_watir_rspec'
|
|
508
|
+
it_behaves_like 'valid adopted project structure', output
|
|
509
|
+
it_behaves_like 'converted pages', output
|
|
510
|
+
it_behaves_like 'merged gems', output
|
|
511
|
+
it_behaves_like 'allure helper', output
|
|
512
|
+
it_behaves_like 'watir helpers', output
|
|
513
|
+
it_behaves_like 'rspec structure', output
|
|
514
|
+
it_behaves_like 'rspec wired to watir', output
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
context 'watir + cucumber' do
|
|
518
|
+
output = 'tmp_adopt_matrix_watir_cucumber'
|
|
519
|
+
it_behaves_like 'valid adopted project structure', output
|
|
520
|
+
it_behaves_like 'converted pages', output
|
|
521
|
+
it_behaves_like 'merged gems', output
|
|
522
|
+
it_behaves_like 'allure helper', output
|
|
523
|
+
it_behaves_like 'watir helpers', output
|
|
524
|
+
it_behaves_like 'cucumber structure', output
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
context 'watir + minitest' do
|
|
528
|
+
output = 'tmp_adopt_matrix_watir_minitest'
|
|
529
|
+
it_behaves_like 'valid adopted project structure', output
|
|
530
|
+
it_behaves_like 'converted pages', output
|
|
531
|
+
it_behaves_like 'merged gems', output
|
|
532
|
+
it_behaves_like 'allure helper', output
|
|
533
|
+
it_behaves_like 'watir helpers', output
|
|
534
|
+
it_behaves_like 'minitest structure', output
|
|
535
|
+
it_behaves_like 'minitest wired to watir', output
|
|
536
|
+
end
|
|
537
|
+
end
|