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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e4d2e6fae8f8504215b558818a81660fca9652f52886c6b72f3e1d6850d01bd
|
|
4
|
+
data.tar.gz: 3a8e5a4290303aab776bce5e6e9e8c86023e88a036b935de18a2c56ded688c8c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f0af4e104fc9cc2b0a99f0ebd4a996994f16500302e5f1cabf635569de8d404c30bf289ce4df145376fad0579b5cf1dc865cee19fd45e757954aa0ebcd4c75bc
|
|
7
|
+
data.tar.gz: 67dd60f0a67b57a2cd09605a7aec9b91a822d198ed95c3be94d67663f6aef5b4db0d4b024ef09bd97e764396381d12c0f0b413552efde25f87fac44d57b48d88
|
data/README.md
CHANGED
|
@@ -67,6 +67,7 @@ Every generated project comes with:
|
|
|
67
67
|
- **Example tests or a skeleton (`examples:false`)** — start from the working login examples, or pass `examples:false` for an empty skeleton with the helpers, config, CI and README (see [Getting Started](#getting-started))
|
|
68
68
|
- **Login reuse** — generated web projects (Selenium or Watir) log in once and restore the saved session for examples tagged `:logged_in` (RSpec) or `@logged_in` (Cucumber); `RAIDER_LOGIN_STATE=off|refresh` and `login_state: max_age:` control it, and the state stays in git-ignored `.raider/auth/`
|
|
69
69
|
- **Failure video replay** — Every test is recorded and the video is kept only for failing tests, attached to the report as `video` (WebM from page screenshots for Selenium and Watir, Appium's own MP4 for mobile, which needs `ffmpeg` on the Appium server host for iOS and for Android recordings over 180 s). Turn it off per run with `VIDEO=off`, or per project with `raider u video off`; ffmpeg is downloaded once, SHA-256 checked and cached in `~/.cache/raider`. The RaiderHQ `ffmpeg-7.1` build that the download uses is not published yet, so for now set `RAIDER_FFMPEG_PATH` to an ffmpeg with libvpx to get web videos
|
|
70
|
+
- **Failure trace replay** (Selenium with RSpec or Cucumber) — Failing tests keep a step-by-step trace: each action with its locator and wait time, a screenshot and the page HTML after every step that changes the page, plus network requests and console messages on Chrome, Edge and Firefox. It is saved as `raider-results/attachments/<n>-trace.zip`, attached to the report as `trace` and opened in Raider Desktop or on Hideout. `TRACE=on` keeps passing tests too, `TRACE=off` captures nothing, and `raider u trace on|off` sets it for the project. Typed values in password fields and `RAIDER_SECRET_*` values are hidden; other typed values, page text and URLs are kept, so treat a trace like the video. Request headers, cookies and bodies are never captured
|
|
70
71
|
- **GitHub Actions CI** — Ready-to-use test pipeline that caches ffmpeg for failure videos
|
|
71
72
|
- **Rake tasks** — Default, smoke, and regression tasks with tag-based filtering
|
|
72
73
|
- **Retry support** — RSpec retry with configurable retry count via `RETRY_COUNT` env var
|
|
@@ -204,6 +205,7 @@ raider u platform [PLATFORM] # Set platform for cross-platform tests
|
|
|
204
205
|
raider u start_appium # Start Appium server
|
|
205
206
|
raider u desktop # Download Raider Desktop
|
|
206
207
|
raider u video [ACTION] # Failure videos: install (ffmpeg), status, on, off
|
|
208
|
+
raider u trace [on/off] # Failure traces: turn on or off (Selenium)
|
|
207
209
|
```
|
|
208
210
|
|
|
209
211
|
## Development
|
|
@@ -123,7 +123,23 @@ class UtilityCommands < Thor
|
|
|
123
123
|
end
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
desc 'trace [on|off]', 'Turns trace capture on or off (writes trace.enabled in config/config.yml)'
|
|
127
|
+
|
|
128
|
+
def trace(action)
|
|
129
|
+
case action
|
|
130
|
+
when 'on', 'off' then trace_toggle(action == 'on')
|
|
131
|
+
else
|
|
132
|
+
say_error "Unknown trace command '#{action}'. Use on|off", :red
|
|
133
|
+
exit 1
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
126
137
|
no_commands do
|
|
138
|
+
def trace_toggle(enabled)
|
|
139
|
+
Utilities.trace_enabled = enabled
|
|
140
|
+
say "Trace capture #{enabled ? 'enabled' : 'disabled'}", :green
|
|
141
|
+
end
|
|
142
|
+
|
|
127
143
|
def video_install
|
|
128
144
|
require_relative '../ruby_raider/ffmpeg'
|
|
129
145
|
path = RubyRaider::Ffmpeg.ensure!
|
|
@@ -8,6 +8,9 @@ require 'raider_reporter/cucumber'
|
|
|
8
8
|
require 'tmpdir'
|
|
9
9
|
require 'yaml'
|
|
10
10
|
require_relative '../../helpers/video_helper'
|
|
11
|
+
<%- if trace_helper? -%>
|
|
12
|
+
require_relative '../../helpers/trace_helper'
|
|
13
|
+
<%- end -%>
|
|
11
14
|
require_relative '../../helpers/session_state'
|
|
12
15
|
<%- if examples? -%>
|
|
13
16
|
require_relative '../../models/user_factory'
|
|
@@ -15,7 +18,47 @@ require_relative '../../page_objects/pages/account'
|
|
|
15
18
|
require_relative '../../page_objects/pages/login'
|
|
16
19
|
<%- end -%>
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
<%- if trace_helper? -%>
|
|
22
|
+
# Attempts per scenario across --retry, keyed on the scenario's location, for the trace of each attempt.
|
|
23
|
+
TRACE_ATTEMPTS = Hash.new(0) unless defined?(TRACE_ATTEMPTS)
|
|
24
|
+
|
|
25
|
+
# Each Gherkin step becomes a group in the trace, named by its keyword and text; hook steps are not steps.
|
|
26
|
+
InstallPlugin do |config, _registry|
|
|
27
|
+
if defined?(TraceHelper)
|
|
28
|
+
begin
|
|
29
|
+
ast_lookup = Cucumber::Formatter::AstLookup.new(config)
|
|
30
|
+
groups = {}
|
|
31
|
+
config.on_event(:test_step_started) do |event|
|
|
32
|
+
next if event.test_step.hook?
|
|
33
|
+
|
|
34
|
+
step = event.test_step
|
|
35
|
+
keyword = begin
|
|
36
|
+
ast_lookup.step_source(step).step.keyword.strip
|
|
37
|
+
rescue StandardError
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
location = { file: step.location.file, line: step.location.lines.min }
|
|
41
|
+
groups[step.id] = TraceHelper.active_recorder&.step_started(name: [keyword, step.text].compact.join(' '), source: location)
|
|
42
|
+
rescue StandardError => e
|
|
43
|
+
TraceHelper.disable!("step groups failed: #{e.message}") if defined?(TraceHelper)
|
|
44
|
+
end
|
|
45
|
+
config.on_event(:test_step_finished) do |event|
|
|
46
|
+
next if event.test_step.hook?
|
|
47
|
+
|
|
48
|
+
status = %i[passed failed].include?(event.result.to_sym) ? event.result.to_sym : :skipped
|
|
49
|
+
error = event.result.failed? ? event.result.exception : nil
|
|
50
|
+
TraceHelper.active_recorder&.step_finished(groups.delete(event.test_step.id), status: status, error: error)
|
|
51
|
+
rescue StandardError => e
|
|
52
|
+
TraceHelper.disable!("step groups failed: #{e.message}") if defined?(TraceHelper)
|
|
53
|
+
end
|
|
54
|
+
rescue StandardError => e
|
|
55
|
+
TraceHelper.warn_once("Gherkin step groups unavailable: #{e.message}")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
<%- end -%>
|
|
61
|
+
Before do<%= trace_helper? ? ' |scenario|' : '' %>
|
|
19
62
|
viewport = YAML.load_file('config/config.yml')['viewport']
|
|
20
63
|
if viewport
|
|
21
64
|
driver.manage.window.resize_to(viewport['width'], viewport['height'])
|
|
@@ -24,6 +67,14 @@ Before do
|
|
|
24
67
|
end
|
|
25
68
|
@video_recorder = VideoHelper.recorder_for(driver)
|
|
26
69
|
@video_recorder.start
|
|
70
|
+
<%- if trace_helper? -%>
|
|
71
|
+
if defined?(TraceHelper)
|
|
72
|
+
@trace_attempt = (TRACE_ATTEMPTS[scenario.location.to_s] += 1)
|
|
73
|
+
@trace_test = { identifier: scenario.location.to_s, full_name: scenario.name, attempt: @trace_attempt }
|
|
74
|
+
@trace_recorder = TraceHelper.recorder_for(driver)
|
|
75
|
+
@trace_recorder.start
|
|
76
|
+
end
|
|
77
|
+
<%- end -%>
|
|
27
78
|
end
|
|
28
79
|
|
|
29
80
|
<%- if examples? -%>
|
|
@@ -41,8 +92,18 @@ end
|
|
|
41
92
|
|
|
42
93
|
<%- end -%>
|
|
43
94
|
After do |scenario|
|
|
95
|
+
<%- if trace_helper? -%>
|
|
96
|
+
if defined?(TraceHelper)
|
|
97
|
+
keep_trace = TraceHelper.keep_all? || scenario.failed?
|
|
98
|
+
trace_test = @trace_test&.merge(status: scenario.failed? ? 'failed' : 'passed', error: scenario.exception)
|
|
99
|
+
trace_path = @trace_recorder&.stop(keep: keep_trace, test: trace_test)
|
|
100
|
+
end
|
|
101
|
+
<%- end -%>
|
|
44
102
|
video_path = @video_recorder&.stop(keep: scenario.failed?)
|
|
45
103
|
RaiderReporter.attach('video', video_path, type: :webm) if video_path
|
|
104
|
+
<%- if trace_helper? -%>
|
|
105
|
+
RaiderReporter.attach('trace', trace_path, type: :trace, attempt: @trace_attempt) if trace_path
|
|
106
|
+
<%- end -%>
|
|
46
107
|
if scenario.failed?
|
|
47
108
|
Dir.mktmpdir do |temp_folder|
|
|
48
109
|
screenshot_path = File.join(temp_folder, 'screenshot.png')
|
|
@@ -51,6 +112,9 @@ After do |scenario|
|
|
|
51
112
|
end
|
|
52
113
|
end
|
|
53
114
|
ensure
|
|
115
|
+
<%- if trace_helper? -%>
|
|
116
|
+
@trace_recorder&.cleanup
|
|
117
|
+
<%- end -%>
|
|
54
118
|
@video_recorder&.cleanup
|
|
55
119
|
driver.quit
|
|
56
120
|
end
|
data/lib/generators/generator.rb
CHANGED
|
@@ -73,6 +73,11 @@ class Generator < Thor::Group
|
|
|
73
73
|
!watir?
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
# Selenium web projects record a trace per test; it needs WaitHelper's actions, and mobile has none yet
|
|
77
|
+
def trace_helper?
|
|
78
|
+
wait_helper? && !mobile?
|
|
79
|
+
end
|
|
80
|
+
|
|
76
81
|
# False for `raider new -p examples:false`: an empty skeleton without the example pages, tests and wiring
|
|
77
82
|
def examples?
|
|
78
83
|
!options_after_name.include?('no_examples')
|
|
@@ -90,8 +95,12 @@ class Generator < Thor::Group
|
|
|
90
95
|
selenium?
|
|
91
96
|
end
|
|
92
97
|
|
|
98
|
+
def ruby_raider_version
|
|
99
|
+
File.read(File.expand_path('../version', __dir__)).strip
|
|
100
|
+
end
|
|
101
|
+
|
|
93
102
|
def ruby_raider_version_requirement
|
|
94
|
-
major, minor =
|
|
103
|
+
major, minor = ruby_raider_version.split('.')
|
|
95
104
|
"~> #{major}.#{minor}"
|
|
96
105
|
end
|
|
97
106
|
|
|
@@ -11,6 +11,7 @@ class HelpersGenerator < Generator
|
|
|
11
11
|
generate_video_helper
|
|
12
12
|
generate_session_state
|
|
13
13
|
generate_wait_helper
|
|
14
|
+
generate_trace_helper
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
private
|
|
@@ -50,6 +51,12 @@ class HelpersGenerator < Generator
|
|
|
50
51
|
template('helpers/raider_element.tt', "#{name}/helpers/raider_element.rb")
|
|
51
52
|
end
|
|
52
53
|
|
|
54
|
+
def generate_trace_helper
|
|
55
|
+
return unless trace_helper?
|
|
56
|
+
|
|
57
|
+
template('helpers/trace_helper.tt', "#{name}/helpers/trace_helper.rb")
|
|
58
|
+
end
|
|
59
|
+
|
|
53
60
|
def generate_appium_helper
|
|
54
61
|
return unless cross_platform?
|
|
55
62
|
|
|
@@ -19,6 +19,13 @@ video:
|
|
|
19
19
|
enabled: true
|
|
20
20
|
fps: 5
|
|
21
21
|
max_width: 1280
|
|
22
|
+
<%- if trace_helper? -%>
|
|
23
|
+
|
|
24
|
+
trace:
|
|
25
|
+
enabled: true # capture traces; failing tests keep theirs
|
|
26
|
+
max_steps: 200 # newest steps are kept; older ones lose screenshots and snapshots first
|
|
27
|
+
max_mb: 20 # the zip stays under this; see Cost
|
|
28
|
+
<%- end -%>
|
|
22
29
|
|
|
23
30
|
login_state:
|
|
24
31
|
max_age: 3600 # seconds a saved login is reused before logging in again
|
|
@@ -224,6 +224,9 @@ timeout: 15
|
|
|
224
224
|
- `headless`: not in the file by default. Add `headless: true`, or set `HEADLESS=true` for one run, to run the
|
|
225
225
|
browser without a window.
|
|
226
226
|
- `video`: failure videos, see [Video replay](#video-replay).
|
|
227
|
+
<%- if trace_helper? -%>
|
|
228
|
+
- `trace`: failing-test traces, see [Trace replay](#trace-replay).
|
|
229
|
+
<%- end -%>
|
|
227
230
|
- `login_state`: how long a saved login is reused, see [Reusing the login](#reusing-the-login).
|
|
228
231
|
<%- end -%>
|
|
229
232
|
|
|
@@ -530,6 +533,10 @@ The wait helper is ordinary code in your project, so you can take it out. To do
|
|
|
530
533
|
<%- end -%>
|
|
531
534
|
5. Scaffolding (`raider g page` and `raider g component`) then writes plain `driver.find_element` examples on its
|
|
532
535
|
own, because it checks for `helpers/wait_helper.rb`.
|
|
536
|
+
<%- if trace_helper? -%>
|
|
537
|
+
|
|
538
|
+
Note that without WaitHelper a trace records only navigation and the failure (see [Trace replay](#trace-replay)).
|
|
539
|
+
<%- end -%>
|
|
533
540
|
|
|
534
541
|
<%- end -%>
|
|
535
542
|
<%- if web? -%>
|
|
@@ -674,6 +681,44 @@ The video is a `video.webm` built from page screenshots with ffmpeg.
|
|
|
674
681
|
no video.
|
|
675
682
|
<%- end -%>
|
|
676
683
|
|
|
684
|
+
<%- if trace_helper? -%>
|
|
685
|
+
### Trace replay
|
|
686
|
+
|
|
687
|
+
Every test records a trace, and the trace is kept only for failing tests<%= rspec? ? ' (on the last retry attempt)' : '' %>. A trace is a step-by-step
|
|
688
|
+
record of the test: each action and page load, with the locator, how long it waited, a screenshot and the page HTML
|
|
689
|
+
after it, the network requests, and the browser console. It is saved as `raider-results/attachments/<n>-trace.zip`,
|
|
690
|
+
next to the failure screenshot and video, and attached to the report as `trace`.
|
|
691
|
+
|
|
692
|
+
- Keep the trace of passing tests too with `TRACE=on bundle exec <%= rspec? ? 'rspec' : 'cucumber' %>`. Capture nothing for one run with
|
|
693
|
+
`TRACE=off bundle exec <%= rspec? ? 'rspec' : 'cucumber' %>`, or for the project with `raider u trace off` (`raider u trace on` turns it back on).
|
|
694
|
+
`raider u trace on` and `raider u trace off` write `enabled:` under `trace:` in `config/config.yml`.
|
|
695
|
+
- Open a trace in Raider Desktop, or from the test's page on Hideout when the run is uploaded.
|
|
696
|
+
- Cost: a trace takes one screenshot and one page HTML for every step that changes the page (a click, typing,
|
|
697
|
+
a page load), including in passing tests, whose traces are then thrown away. If that slows your suite down,
|
|
698
|
+
switch tracing off as above.
|
|
699
|
+
- Caps, under `trace:` in `config/config.yml`: `max_steps` (200) keeps the newest steps, and `max_mb` (20) keeps the
|
|
700
|
+
zip under that size. When a cap is reached, the HTML of the oldest steps is dropped first, then their
|
|
701
|
+
screenshots, then the oldest network and console entries. The last 10 steps always keep theirs.
|
|
702
|
+
- Network requests and console messages are captured only on Chrome, Edge or Firefox. Other browsers, such as
|
|
703
|
+
Safari, get a trace with steps, screenshots and HTML only. Capture is passive: the trace listens to the browser and
|
|
704
|
+
never changes a request.
|
|
705
|
+
- The trace helper never fails a test. When it has to leave something out, such as network on a browser without
|
|
706
|
+
BiDi or a screenshot it could not take, you get at most one `[trace]` notice on stderr for the run. If capturing
|
|
707
|
+
breaks, you get one more `[trace]` line ending in "tracing disabled for this run", and no more traces for that run.
|
|
708
|
+
|
|
709
|
+
**Treat a trace like the video: it can contain secrets.** What is hidden: values typed into password fields
|
|
710
|
+
(`type=password`, or an `autocomplete` that contains "password"), and any typed value equal to a `RAIDER_SECRET_*`
|
|
711
|
+
environment variable. Everything else is kept: other typed values, page text, URLs with their query strings, and
|
|
712
|
+
console text. So a secret typed into an ordinary field, or shown on the page, ends up in the trace. Failure messages
|
|
713
|
+
can contain typed text too, because an assertion message is kept as it is. Request headers, cookies and request or
|
|
714
|
+
response bodies are never captured. Do not share or upload traces from runs that handle real credentials.
|
|
715
|
+
|
|
716
|
+
**Removing the trace helper.** The trace helper is ordinary code in your project. Delete `helpers/trace_helper.rb` and
|
|
717
|
+
the `require_relative` lines that load `trace_helper`: in <%= rspec? ? '`helpers/driver_helper.rb`' : '`helpers/driver_helper.rb` and `features/support/env.rb`' %>. The other lines that use it
|
|
718
|
+
(in <%= rspec? ? '`helpers/spec_helper.rb`' : '`features/support/env.rb`' %> and the driver helper's listeners) only run when `TraceHelper` is defined,
|
|
719
|
+
so they can stay. Remove the `trace:` block from `config/config.yml` if you like.
|
|
720
|
+
|
|
721
|
+
<%- end -%>
|
|
677
722
|
<%- unless azure? && mobile? -%>
|
|
678
723
|
### Quarantine
|
|
679
724
|
|
|
@@ -5,12 +5,34 @@ require 'yaml'
|
|
|
5
5
|
require 'active_support/inflector'
|
|
6
6
|
require 'selenium-webdriver'
|
|
7
7
|
require_relative 'video_helper'
|
|
8
|
+
<%- if trace_helper? -%>
|
|
9
|
+
require_relative 'trace_helper'
|
|
10
|
+
<%- end -%>
|
|
8
11
|
<%- else -%>
|
|
9
12
|
require 'appium_lib'
|
|
10
13
|
<%- end -%>
|
|
11
14
|
|
|
12
15
|
module DriverHelper
|
|
13
16
|
<%- if selenium_based? -%>
|
|
17
|
+
# Selenium takes one listener: this one hands every event on to the video and trace listeners.
|
|
18
|
+
class FanOutListener < Selenium::WebDriver::Support::AbstractEventListener
|
|
19
|
+
def self.for(listeners)
|
|
20
|
+
listeners.empty? ? nil : new(listeners)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def initialize(listeners)
|
|
24
|
+
super()
|
|
25
|
+
@listeners = listeners
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Selenium::WebDriver::Support::AbstractEventListener.instance_methods(false).each do |event|
|
|
29
|
+
define_method(event) do |*args|
|
|
30
|
+
@listeners.each { |listener| listener.public_send(event, *args) if listener.respond_to?(event) }
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
14
36
|
def driver(*opts)
|
|
15
37
|
@driver ||= create_driver(*opts)
|
|
16
38
|
end
|
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
@config = YAML.load_file('config/config.yml')
|
|
3
3
|
browser = @config['browser']
|
|
4
4
|
arguments = { options: create_webdriver_options(*opts) }
|
|
5
|
-
listener =
|
|
5
|
+
listener = FanOutListener.for(listeners)
|
|
6
6
|
arguments[:listener] = listener if listener
|
|
7
7
|
Selenium::WebDriver.for(browser.to_sym, **arguments)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
# The helpers' Selenium listeners. Deleting video_helper.rb or trace_helper.rb needs only its require.
|
|
11
|
+
def listeners
|
|
12
|
+
listeners = []
|
|
13
|
+
listeners << VideoHelper.listener if defined?(VideoHelper)
|
|
14
|
+
listeners << TraceHelper.listener if defined?(TraceHelper)
|
|
15
|
+
listeners.compact
|
|
16
|
+
end
|
|
17
|
+
|
|
10
18
|
def browser_arguments(*opts)
|
|
11
19
|
args = opts.empty? ? @config['browser_arguments'][@config['browser']] : opts
|
|
12
20
|
args += ['--headless'] if (ENV['HEADLESS'] || @config['headless']) && !args.include?('--headless')
|
|
@@ -18,5 +26,7 @@
|
|
|
18
26
|
browser = load_browser == 'ie' ? load_browser.upcase : load_browser.capitalize
|
|
19
27
|
options = "Selenium::WebDriver::#{browser}::Options".constantize.new
|
|
20
28
|
browser_arguments(*opts).each { |arg| options.add_argument(arg) }
|
|
29
|
+
# WebDriver BiDi carries the trace's network and console (chrome, edge and firefox).
|
|
30
|
+
options.web_socket_url = true if defined?(TraceHelper) && TraceHelper.bidi?(load_browser)
|
|
21
31
|
options
|
|
22
32
|
end
|
|
@@ -65,13 +65,13 @@ class RaiderElement
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def send_keys(*keys, timeout: nil)
|
|
68
|
-
perform(:send_keys, timeout) { |element| element.send_keys(*keys) }
|
|
68
|
+
perform(:send_keys, timeout, args: keys) { |element| element.send_keys(*keys) }
|
|
69
69
|
self
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
<%- unless mobile? -%>
|
|
73
73
|
def select_by(how, what, timeout: nil)
|
|
74
|
-
perform(:select_by, timeout) { |element| Selenium::WebDriver::Support::Select.new(element).select_by(how, what) }
|
|
74
|
+
perform(:select_by, timeout, args: [how, what]) { |element| Selenium::WebDriver::Support::Select.new(element).select_by(how, what) }
|
|
75
75
|
self
|
|
76
76
|
end
|
|
77
77
|
|
|
@@ -143,8 +143,8 @@ class RaiderElement
|
|
|
143
143
|
WaitHelper::Lookup.for(@driver, locator, by, scope: @lookup)
|
|
144
144
|
end
|
|
145
145
|
|
|
146
|
-
def perform(action, timeout, &block)
|
|
147
|
-
waiter(timeout).perform_action(action, @lookup, WaitHelper::Waiter::CHECKS.fetch(action), &block)
|
|
146
|
+
def perform(action, timeout, args: nil, &block)
|
|
147
|
+
waiter(timeout).perform_action(action, @lookup, WaitHelper::Waiter::CHECKS.fetch(action), args: args, &block)
|
|
148
148
|
end
|
|
149
149
|
|
|
150
150
|
def method_missing(name, *args, **options, &block)
|
|
@@ -62,6 +62,10 @@ module SpecHelper
|
|
|
62
62
|
<%- end -%>
|
|
63
63
|
@video_recorder = VideoHelper.recorder_for(<%= watir? ? 'browser' : 'driver' %>)
|
|
64
64
|
@video_recorder.start
|
|
65
|
+
<%- if trace_helper? -%>
|
|
66
|
+
@trace_recorder = TraceHelper.recorder_for(driver) if defined?(TraceHelper)
|
|
67
|
+
@trace_recorder&.start
|
|
68
|
+
<%- end -%>
|
|
65
69
|
end
|
|
66
70
|
<%- if web? && examples? -%>
|
|
67
71
|
|
|
@@ -80,6 +84,15 @@ module SpecHelper
|
|
|
80
84
|
|
|
81
85
|
config.after(:each) do |example|
|
|
82
86
|
example_name = example.description
|
|
87
|
+
<%- if trace_helper? -%>
|
|
88
|
+
if defined?(TraceHelper)
|
|
89
|
+
attempt = example.metadata[:retry_attempts].to_i + 1
|
|
90
|
+
keep_trace = TraceHelper.keep_all? || (example.exception && (defined?(VideoHelper) ? VideoHelper.final_attempt?(example) : true))
|
|
91
|
+
trace_test = { identifier: example.id.delete_prefix('./'), full_name: example.full_description,
|
|
92
|
+
status: example.exception ? 'failed' : 'passed', attempt: attempt, error: example.exception }
|
|
93
|
+
trace_path = @trace_recorder&.stop(keep: keep_trace, test: trace_test)
|
|
94
|
+
end
|
|
95
|
+
<%- end -%>
|
|
83
96
|
keep_video = example.exception ? VideoHelper.final_attempt?(example) : false
|
|
84
97
|
video_path = @video_recorder&.stop(keep: keep_video)
|
|
85
98
|
if example.exception
|
|
@@ -91,7 +104,13 @@ module SpecHelper
|
|
|
91
104
|
end
|
|
92
105
|
end
|
|
93
106
|
RaiderReporter.attach('video', video_path, type: <%= mobile? ? ':mp4' : ':webm' %>) if video_path
|
|
107
|
+
<%- if trace_helper? -%>
|
|
108
|
+
RaiderReporter.attach('trace', trace_path, type: :trace, attempt: attempt) if trace_path
|
|
109
|
+
<%- end -%>
|
|
94
110
|
ensure
|
|
111
|
+
<%- if trace_helper? -%>
|
|
112
|
+
@trace_recorder&.cleanup
|
|
113
|
+
<%- end -%>
|
|
95
114
|
@video_recorder&.cleanup
|
|
96
115
|
<%= partial('quit_driver', strip: true) %>
|
|
97
116
|
end
|