ruby_raider 3.12.1 → 3.13.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/README.md +2 -0
- data/lib/commands/utility_commands.rb +16 -0
- data/lib/generators/cucumber/templates/partials/selenium_env.tt +65 -1
- data/lib/generators/generator.rb +10 -1
- data/lib/generators/helper_generator.rb +7 -0
- data/lib/generators/templates/common/gemfile.tt +1 -1
- data/lib/generators/templates/common/partials/web_config.tt +7 -0
- data/lib/generators/templates/common/read_me.tt +45 -0
- data/lib/generators/templates/helpers/driver_helper.tt +22 -0
- data/lib/generators/templates/helpers/partials/selenium_driver.tt +11 -1
- data/lib/generators/templates/helpers/raider_element.tt +4 -4
- data/lib/generators/templates/helpers/spec_helper.tt +19 -0
- data/lib/generators/templates/helpers/trace_helper.tt +1097 -0
- data/lib/generators/templates/helpers/wait_helper.tt +145 -4
- data/lib/utilities/utilities.rb +7 -0
- data/lib/version +1 -1
- data/ruby_raider.gemspec +1 -0
- data/sig/commands/utility_commands.rbs +2 -0
- data/sig/generators/generator.rbs +4 -0
- data/sig/generators/helper_generator.rbs +1 -0
- data/sig/utilities/utilities.rbs +1 -0
- data/spec/generators/fixtures/video_helper_stubs/selenium-webdriver.rb +11 -2
- data/spec/generators/trace_helper_spec.rb +945 -0
- data/spec/integration/content/config_content_spec.rb +20 -0
- data/spec/integration/content/cucumber_reporter_content_spec.rb +51 -0
- data/spec/integration/content/gemfile_content_spec.rb +2 -2
- data/spec/integration/content/helper_content_spec.rb +60 -1
- data/spec/integration/content/readme_content_spec.rb +46 -0
- data/spec/integration/content/rspec_reporter_content_spec.rb +2 -2
- data/spec/integration/end_to_end_spec.rb +392 -29
- data/spec/integration/generators/helpers_generator_spec.rb +26 -0
- data/spec/integration/helpers/wait_helper_spec.rb +183 -0
- data/spec/integration/trace_format_checker.rb +141 -0
- data/spec/integration/trace_page_server.rb +80 -0
- data/spec/utilities/trace_command_spec.rb +66 -0
- metadata +27 -2
|
@@ -59,6 +59,22 @@ describe 'Config file content' do
|
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
shared_examples 'trace config' do |project_name|
|
|
63
|
+
it 'has tracing enabled with 200 steps and 20 MB, with the spec comments' do
|
|
64
|
+
raw = read_generated(project_name, 'config/config.yml')
|
|
65
|
+
config = YAML.safe_load(raw, permitted_classes: [Symbol])
|
|
66
|
+
expect(config['trace']).to eq('enabled' => true, 'max_steps' => 200, 'max_mb' => 20)
|
|
67
|
+
expect(raw.index('trace:')).to be > raw.index('video:')
|
|
68
|
+
expect(raw.index('trace:')).to be < raw.index('login_state:')
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
shared_examples 'no trace config' do |project_name|
|
|
73
|
+
it 'has no trace block' do
|
|
74
|
+
expect(read_generated(project_name, 'config/config.yml')).not_to include('trace')
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
62
78
|
shared_examples 'login state config' do |project_name|
|
|
63
79
|
it 'has a login_state max_age of an hour' do
|
|
64
80
|
config = YAML.safe_load(read_generated(project_name, 'config/config.yml'), permitted_classes: [Symbol])
|
|
@@ -73,6 +89,7 @@ describe 'Config file content' do
|
|
|
73
89
|
include_examples 'valid web config', name
|
|
74
90
|
include_examples 'selenium config with timeout', name
|
|
75
91
|
include_examples 'video config', name
|
|
92
|
+
include_examples 'trace config', name
|
|
76
93
|
include_examples 'login state config', name
|
|
77
94
|
end
|
|
78
95
|
|
|
@@ -80,6 +97,7 @@ describe 'Config file content' do
|
|
|
80
97
|
name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
|
|
81
98
|
include_examples 'valid web config', name
|
|
82
99
|
include_examples 'config without driver_options', name
|
|
100
|
+
include_examples 'no trace config', name
|
|
83
101
|
include_examples 'login state config', name
|
|
84
102
|
end
|
|
85
103
|
|
|
@@ -87,6 +105,7 @@ describe 'Config file content' do
|
|
|
87
105
|
name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
|
|
88
106
|
include_examples 'valid web config', name
|
|
89
107
|
include_examples 'selenium config with timeout', name
|
|
108
|
+
include_examples 'trace config', name
|
|
90
109
|
include_examples 'login state config', name
|
|
91
110
|
end
|
|
92
111
|
|
|
@@ -95,6 +114,7 @@ describe 'Config file content' do
|
|
|
95
114
|
# Single-platform Appium projects have no config.yml; VideoHelper falls back to its defaults.
|
|
96
115
|
context 'with rspec and cross platform' do
|
|
97
116
|
include_examples 'video config', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
|
|
117
|
+
include_examples 'no trace config', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
|
|
98
118
|
end
|
|
99
119
|
|
|
100
120
|
context 'with rspec and appium android' do
|
|
@@ -68,6 +68,57 @@ describe 'Cucumber raider_reporter wiring' do
|
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
if automation == 'selenium'
|
|
72
|
+
context 'with trace recording' do
|
|
73
|
+
it 'requires trace_helper' do
|
|
74
|
+
expect(env).to include("require_relative '../../helpers/trace_helper'")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'counts attempts per scenario location and starts the trace recorder after the video recorder' do
|
|
78
|
+
before_hook = env[/^Before do.*?^end$/m]
|
|
79
|
+
expect(env).to match(/^TRACE_ATTEMPTS = Hash\.new\(0\) unless defined\?\(TRACE_ATTEMPTS\)$/)
|
|
80
|
+
expect(before_hook).to include('TRACE_ATTEMPTS[scenario.location.to_s] += 1', '@trace_recorder = TraceHelper.recorder_for(driver)')
|
|
81
|
+
expect(before_hook).to match(/^Before do \|scenario\|$/)
|
|
82
|
+
expect(before_hook.index('@video_recorder.start')).to be < before_hook.index('@trace_recorder = TraceHelper')
|
|
83
|
+
expect(before_hook).to match(/if defined\?\(TraceHelper\)\n(.*\n)*.*@trace_recorder = TraceHelper/)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'stops with keep: TraceHelper.keep_all? || scenario.failed? before the video, attaches it and cleans up before quitting' do
|
|
87
|
+
expect(hook).to include('TraceHelper.keep_all? || scenario.failed?', 'error: scenario.exception', 'attempt: @trace_attempt')
|
|
88
|
+
expect(hook).to include("RaiderReporter.attach('trace', trace_path, type: :trace, attempt: @trace_attempt) if trace_path")
|
|
89
|
+
order = [hook.index('@trace_recorder&.stop'), hook.index('@video_recorder&.stop'), hook.index("RaiderReporter.attach('trace'"),
|
|
90
|
+
hook.index(/^ensure/), hook.index('@trace_recorder&.cleanup'), hook.index('@video_recorder&.cleanup'), hook.index('driver.quit')]
|
|
91
|
+
expect(order).to all(be_an(Integer)).and eq(order.compact.sort)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'survives a Before that raised before the trace init, and a failing plugin setup or handler' do
|
|
95
|
+
expect(hook).to include('@trace_test&.merge(')
|
|
96
|
+
expect(hook).not_to include('@trace_test.merge(')
|
|
97
|
+
plugin = env[/^InstallPlugin do.*?^end$/m]
|
|
98
|
+
expect(plugin.scan('rescue StandardError => e').size).to eq(3)
|
|
99
|
+
expect(plugin.index('AstLookup.new')).to be > plugin.index("begin\n")
|
|
100
|
+
expect(plugin).to include('TraceHelper.warn_once("Gherkin step groups unavailable')
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'turns tracing off with TraceHelper.disable! when a step group handler raises' do
|
|
104
|
+
plugin = env[/^InstallPlugin do.*?^end$/m]
|
|
105
|
+
expect(plugin.scan(/TraceHelper\.disable!\("step groups failed: \#\{e\.message\}"\) if defined\?\(TraceHelper\)/).size).to eq(2)
|
|
106
|
+
expect(plugin).not_to include('tracing disabled')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'records each Gherkin step as a group through the InstallPlugin step events, skipping hooks' do
|
|
110
|
+
plugin = env[/^InstallPlugin do.*?^end$/m]
|
|
111
|
+
expect(plugin).to include('config.on_event(:test_step_started)', 'config.on_event(:test_step_finished)', 'next if event.test_step.hook?')
|
|
112
|
+
expect(plugin).to include('TraceHelper.active_recorder&.step_started', 'TraceHelper.active_recorder&.step_finished')
|
|
113
|
+
expect(plugin).to include('defined?(TraceHelper)')
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
else
|
|
117
|
+
it 'has no trace wiring' do
|
|
118
|
+
expect(env).not_to match(/trace/i)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
71
122
|
it 'does not generate the allure helper' do
|
|
72
123
|
expect(File).not_to exist(File.join(project_name, 'helpers/allure_helper.rb'))
|
|
73
124
|
end
|
|
@@ -127,7 +127,7 @@ describe 'Gemfile content' do
|
|
|
127
127
|
let(:gemfile) { read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'Gemfile') }
|
|
128
128
|
|
|
129
129
|
it 'includes raider_reporter' do
|
|
130
|
-
expect(gemfile).to include("gem 'raider_reporter', '~> 0.
|
|
130
|
+
expect(gemfile).to include("gem 'raider_reporter', '~> 0.12'")
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
it 'has no allure gems' do
|
|
@@ -143,7 +143,7 @@ describe 'Gemfile content' do
|
|
|
143
143
|
let(:gemfile) { read_generated("#{FrameworkIndex::CUCUMBER}_#{automation}", 'Gemfile') }
|
|
144
144
|
|
|
145
145
|
it 'includes raider_reporter' do
|
|
146
|
-
expect(gemfile).to include("gem 'raider_reporter', '~> 0.
|
|
146
|
+
expect(gemfile).to include("gem 'raider_reporter', '~> 0.12'")
|
|
147
147
|
end
|
|
148
148
|
|
|
149
149
|
it 'drops allure-cucumber' do
|
|
@@ -43,6 +43,21 @@ describe 'Helper file content' do
|
|
|
43
43
|
it 'does not reference Capybara' do
|
|
44
44
|
expect(helper).not_to include('Capybara')
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
it 'requires trace_helper' do
|
|
48
|
+
expect(helper).to include("require_relative 'trace_helper'")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'sets web_socket_url only for chrome, edge and firefox and not with TRACE=off' do
|
|
52
|
+
expect(helper).to include('options.web_socket_url = true if defined?(TraceHelper) && TraceHelper.bidi?(load_browser)')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'fans the video and trace listeners out through one listener, each guarded by defined?' do
|
|
56
|
+
expect(helper).to include('class FanOutListener < Selenium::WebDriver::Support::AbstractEventListener',
|
|
57
|
+
'listener = FanOutListener.for(listeners)',
|
|
58
|
+
'listeners << VideoHelper.listener if defined?(VideoHelper)',
|
|
59
|
+
'listeners << TraceHelper.listener if defined?(TraceHelper)')
|
|
60
|
+
end
|
|
46
61
|
end
|
|
47
62
|
|
|
48
63
|
# --- Browser helper ---
|
|
@@ -168,7 +183,7 @@ describe 'Helper file content' do
|
|
|
168
183
|
after_hook.index(/driver\.quit|browser\.quit/)]
|
|
169
184
|
expect(order).to all(be_an(Integer)).and eq(order.compact.sort)
|
|
170
185
|
expect(after_hook.scan(/driver\.quit|browser\.quit/).size).to eq(1)
|
|
171
|
-
expect(after_hook[order[2]..]).to match(/\n @video_recorder&\.cleanup\n (driver|browser)\.quit(_driver)?\n end\n/)
|
|
186
|
+
expect(after_hook[order[2]..]).to match(/\n (@trace_recorder&\.cleanup\n )?@video_recorder&\.cleanup\n (driver|browser)\.quit(_driver)?\n end\n/)
|
|
172
187
|
end
|
|
173
188
|
|
|
174
189
|
it 'keeps the screenshot attachment' do
|
|
@@ -176,6 +191,41 @@ describe 'Helper file content' do
|
|
|
176
191
|
end
|
|
177
192
|
end
|
|
178
193
|
|
|
194
|
+
shared_examples 'trace spec helper wiring' do |project_name|
|
|
195
|
+
subject(:helper) { read_generated(project_name, 'helpers/spec_helper.rb') }
|
|
196
|
+
|
|
197
|
+
let(:before_hook) { helper[/config\.before\(:each\) do.*?^ end$/m] }
|
|
198
|
+
let(:after_hook) { helper[/config\.after\(:each\).*\z/m] }
|
|
199
|
+
|
|
200
|
+
it 'starts the trace recorder after the video recorder, each guarded by defined?(TraceHelper)' do
|
|
201
|
+
expect(before_hook).to include('@trace_recorder = TraceHelper.recorder_for(driver) if defined?(TraceHelper)', '@trace_recorder&.start')
|
|
202
|
+
expect(before_hook.index('@video_recorder.start')).to be < before_hook.index('@trace_recorder = TraceHelper')
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it 'keeps the trace for TRACE=on or a final-attempt failure, falling back to keeping failures without a video helper' do
|
|
206
|
+
expect(after_hook).to include('TraceHelper.keep_all? || (example.exception && (defined?(VideoHelper) ? VideoHelper.final_attempt?(example) : true))')
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it 'counts the attempt from the rspec-retry metadata and hands the recorder the test' do
|
|
210
|
+
expect(after_hook).to include('example.metadata[:retry_attempts].to_i + 1', 'error: example.exception')
|
|
211
|
+
expect(after_hook).to include('@trace_recorder&.stop(keep: keep_trace, test: trace_test)')
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'stops the trace before the video and the screenshot, then attaches it, then cleans up before quitting' do
|
|
215
|
+
order = [after_hook.index('@trace_recorder&.stop'), after_hook.index('@video_recorder&.stop'), after_hook.index('RaiderReporter.attach(\'screenshot\''),
|
|
216
|
+
after_hook.index("RaiderReporter.attach('trace', trace_path, type: :trace, attempt: attempt) if trace_path"),
|
|
217
|
+
after_hook.index("\n ensure\n"), after_hook.index('@trace_recorder&.cleanup'), after_hook.index('@video_recorder&.cleanup'),
|
|
218
|
+
after_hook.index('driver.quit')]
|
|
219
|
+
expect(order).to all(be_an(Integer)).and eq(order.compact.sort)
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
shared_examples 'no trace wiring' do |project_name, file|
|
|
224
|
+
it "leaves #{file} without trace code" do
|
|
225
|
+
expect(read_generated(project_name, file)).not_to match(/trace/i)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
179
229
|
shared_examples 'selenium spec helper' do |project_name|
|
|
180
230
|
subject(:helper) { read_generated(project_name, 'helpers/spec_helper.rb') }
|
|
181
231
|
|
|
@@ -313,6 +363,10 @@ describe 'Helper file content' do
|
|
|
313
363
|
it 'does not wire a listener into the appium driver helper' do
|
|
314
364
|
expect(read_generated(name, 'helpers/driver_helper.rb')).not_to include('listener')
|
|
315
365
|
end
|
|
366
|
+
|
|
367
|
+
it 'does not wire tracing or BiDi into the appium driver helper' do
|
|
368
|
+
expect(read_generated(name, 'helpers/driver_helper.rb')).not_to include('TraceHelper', 'web_socket_url')
|
|
369
|
+
end
|
|
316
370
|
end
|
|
317
371
|
|
|
318
372
|
# --- RSpec + automation contexts ---
|
|
@@ -357,6 +411,11 @@ describe 'Helper file content' do
|
|
|
357
411
|
it_behaves_like 'raider reporter spec helper', name, screenshot_call
|
|
358
412
|
it_behaves_like 'video spec helper wiring', name, automation == 'watir' ? 'browser' : 'driver',
|
|
359
413
|
%w[selenium watir].include?(automation) ? ':webm' : ':mp4'
|
|
414
|
+
if automation == 'selenium'
|
|
415
|
+
it_behaves_like 'trace spec helper wiring', name
|
|
416
|
+
else
|
|
417
|
+
it_behaves_like 'no trace wiring', name, 'helpers/spec_helper.rb'
|
|
418
|
+
end
|
|
360
419
|
end
|
|
361
420
|
|
|
362
421
|
context "with cucumber and #{automation}" do
|
|
@@ -52,6 +52,52 @@ describe 'Generated Readme content' do
|
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
|
+
|
|
56
|
+
context "with #{framework} and #{automation}, the Trace replay section" do
|
|
57
|
+
subject(:section) { readme[/^### Trace replay\n.*?(?=^##)/m]&.gsub(/\s+/, ' ') }
|
|
58
|
+
|
|
59
|
+
let(:readme) { read_generated("#{framework}_#{automation}", 'Readme.md') }
|
|
60
|
+
|
|
61
|
+
if automation == 'selenium'
|
|
62
|
+
it 'covers the defaults, TRACE=on, TRACE=off, the file location and how to open it' do
|
|
63
|
+
expect(section).to include('only for failing tests', 'TRACE=on', 'TRACE=off', 'raider u trace off',
|
|
64
|
+
'raider u trace on', 'raider-results/attachments/', 'Raider Desktop', 'Hideout',
|
|
65
|
+
'helpers/trace_helper.rb')
|
|
66
|
+
expect(section).to include('raider-results/attachments/<n>-trace.zip')
|
|
67
|
+
expect(section).to include('`raider u trace on` and `raider u trace off` write `enabled:`')
|
|
68
|
+
expect(section).not_to include('Both write')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'states the per-step cost and the caps' do
|
|
72
|
+
expect(section).to include('one screenshot and one page HTML', 'max_mb', 'max_steps', 'trace:')
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'allows at most one [trace] notice, plus one line when tracing stops' do
|
|
76
|
+
expect(section).to include('at most one `[trace]` notice', 'one more `[trace]` line', 'tracing disabled for this run')
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'limits network and console to Chrome, Edge or Firefox' do
|
|
80
|
+
expect(section).to include('Chrome, Edge or Firefox', 'Safari', 'steps, screenshots and HTML')
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'says what is hidden, what is kept and what is never captured' do
|
|
84
|
+
expect(section).to include('password', 'RAIDER_SECRET_', 'page text', 'query strings', 'console text',
|
|
85
|
+
'like the video', 'never captured', 'cookies')
|
|
86
|
+
expect(section).to include('Failure messages can contain typed text too, because an assertion message is kept as it is')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'says how to remove the trace helper and notes the wait helper link' do
|
|
90
|
+
expect(readme).to include('Removing the trace helper', 'require_relative',
|
|
91
|
+
'without WaitHelper a trace records only navigation and the failure')
|
|
92
|
+
expect(readme).not_to match(/allure/i)
|
|
93
|
+
expect(readme).not_to include('—')
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
it 'does not mention trace replay' do
|
|
97
|
+
expect(readme).not_to include('Trace replay', 'TRACE=', 'trace_helper')
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
55
101
|
end
|
|
56
102
|
|
|
57
103
|
AUTOMATION_TYPES.each do |automation|
|
|
@@ -18,8 +18,8 @@ describe 'RSpec projects without Allure' do
|
|
|
18
18
|
expect(File).not_to exist(File.join(project_name, 'allure-results'))
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
it 'pins raider_reporter 0.
|
|
22
|
-
expect(read_generated(project_name, 'Gemfile')).to include("gem 'raider_reporter', '~> 0.
|
|
21
|
+
it 'pins raider_reporter 0.12' do
|
|
22
|
+
expect(read_generated(project_name, 'Gemfile')).to include("gem 'raider_reporter', '~> 0.12'")
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|