Skip to content

Commit 8810d6c

Browse files
committed
Refine Playwright auth lifecycle
1 parent eac0407 commit 8810d6c

6 files changed

Lines changed: 77 additions & 33 deletions

File tree

app/models/concerns/upright/playwright/form_authentication.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ module Upright::Playwright::FormAuthentication
33

44
included do
55
class_attribute :authentication_service
6-
76
set_callback :page_ready, :after, :ensure_authenticated
87
end
98

app/models/concerns/upright/playwright/lifecycle.rb

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,7 @@ def user_agent
1717
private
1818
def with_browser(&block)
1919
::Playwright.create(playwright_cli_executable_path: Upright.configuration.playwright_cli_path) do |playwright|
20-
playwright.chromium.launch(headless: ENV.fetch("HEADLESS", "true") != "false", args: chromium_args, &block)
21-
end
22-
end
23-
24-
def chromium_args
25-
[].tap do |args|
26-
args << "--no-sandbox" if Rails.env.production? || ENV["PLAYWRIGHT_NO_SANDBOX"]
20+
playwright.chromium.launch(headless: ENV.fetch("HEADLESS", "true") != "false", &block)
2721
end
2822
end
2923

@@ -34,6 +28,7 @@ def with_context(browser, **options, &block)
3428
yield
3529
ensure
3630
run_callbacks :page_close do
31+
# Rescue each step independently so one failed close does not block artifact capture
3732
page&.close rescue Rails.error.report($!)
3833
context&.close rescue Rails.error.report($!)
3934
end

app/models/concerns/upright/playwright/trace_recording.rb

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Upright::Playwright::TraceRecording
22
extend ActiveSupport::Concern
33

44
included do
5-
attr_accessor :trace_path
5+
attr_accessor :trace_artifacts
66

77
set_callback :page_ready, :before, :start_trace
88
set_callback :page_close, :before, :stop_trace
@@ -18,22 +18,27 @@ def start_trace
1818
end
1919

2020
def stop_trace
21-
self.trace_path = trace_dir.join("#{SecureRandom.hex}.zip").to_s
21+
trace_path = trace_dir.join("#{SecureRandom.hex}.zip").to_s
2222
FileUtils.mkdir_p(trace_dir)
2323
context.tracing.stop(path: trace_path)
24+
25+
self.trace_artifacts ||= []
26+
trace_artifacts << { label: current_recording_label, path: trace_path }
2427
rescue => error
2528
Rails.error.report(error)
26-
self.trace_path = nil
2729
end
2830

2931
def attach_trace(probe_result)
30-
return unless trace_path && File.exist?(trace_path)
32+
Array(trace_artifacts).each do |artifact|
33+
next unless File.exist?(artifact.fetch(:path))
34+
35+
File.open(artifact.fetch(:path), "rb") do |file|
36+
Upright::Artifact.new(name: recording_artifact_filename(artifact[:label], "zip"), content: file).attach_to(probe_result, timestamped: true)
37+
end
3138

32-
File.open(trace_path, "rb") do |file|
33-
Upright::Artifact.new(name: "#{probe_name}.zip", content: file).attach_to(probe_result, timestamped: true)
39+
FileUtils.rm(artifact.fetch(:path))
3440
end
3541

36-
FileUtils.rm(trace_path)
37-
self.trace_path = nil
42+
self.trace_artifacts = []
3843
end
3944
end

app/models/concerns/upright/playwright/video_recording.rb

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module Upright::Playwright::VideoRecording
44
VIDEO_SIZE = { width: 1280, height: 720 }
55

66
included do
7-
attr_accessor :video_path, :video_object
7+
attr_accessor :video_artifacts, :pending_video_recording
88

99
set_callback :page_ready, :after, :capture_video_reference
1010
set_callback :page_close, :after, :finalize_video
@@ -33,28 +33,58 @@ def record_video?
3333
end
3434

3535
def capture_video_reference
36-
self.video_object = page.video if record_video?
36+
return unless record_video?
37+
return unless (video = page.video)
38+
39+
self.pending_video_recording = { label: current_recording_label, video: video }
3740
end
3841

3942
def save_video
40-
if video_object
41-
self.video_path = video_dir.join("#{SecureRandom.hex}.webm").to_s
42-
video_object.save_as(video_path)
43-
end
43+
return unless pending_video_recording
44+
45+
video_path = video_dir.join("#{SecureRandom.hex}.webm").to_s
46+
pending_video_recording.fetch(:video).save_as(video_path)
47+
48+
self.video_artifacts ||= []
49+
video_artifacts << pending_video_recording.merge(path: video_path)
50+
ensure
51+
self.pending_video_recording = nil
4452
end
4553

4654
def attach_video(probe_result)
47-
if video_path
48-
File.open(video_path, "rb") do |file|
49-
Upright::Artifact.new(name: "#{probe_name}.webm", content: file).attach_to(probe_result, timestamped: true)
50-
end
55+
Array(video_artifacts).each do |artifact|
56+
next unless File.exist?(artifact.fetch(:path))
5157

52-
if logger.respond_to?(:struct) && probe_result.artifacts.any?
53-
logger.struct probe_artifact_url: Rails.application.routes.url_helpers.rails_blob_url(probe_result.artifacts.first, expires_in: 24.hours)
58+
File.open(artifact.fetch(:path), "rb") do |file|
59+
Upright::Artifact.new(name: recording_artifact_filename(artifact[:label], "webm"), content: file).attach_to(probe_result, timestamped: true)
5460
end
5561

56-
FileUtils.rm(video_path)
57-
self.video_path = nil
62+
FileUtils.rm(artifact.fetch(:path))
5863
end
64+
65+
if logger.respond_to?(:struct)
66+
video_artifact = probe_result.artifacts.find { |attached| attached.content_type == "video/webm" }
67+
if video_artifact
68+
logger.struct probe_artifact_url: Rails.application.routes.url_helpers.rails_blob_url(video_artifact, expires_in: 24.hours)
69+
end
70+
end
71+
72+
self.video_artifacts = []
73+
end
74+
75+
def recording_artifact_filename(label, extension)
76+
[ recording_artifact_basename(label), extension ].join(".")
77+
end
78+
79+
def recording_artifact_basename(label)
80+
[ artifact_recording_name, label ].compact.join(" ")
81+
end
82+
83+
def artifact_recording_name
84+
respond_to?(:probe_name) ? probe_name : service_name.to_s
85+
end
86+
87+
def current_recording_label
88+
nil
5989
end
6090
end

app/models/upright/playwright/authenticator/base.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def initialize
1414
def ensure_authenticated(context, page)
1515
@page = page
1616
load_cached_storage_state(context)
17-
page.goto(signin_redirect_url, timeout: 10.seconds.in_ms)
17+
page.goto(auth_check_url, timeout: 10.seconds.in_ms)
1818

1919
unless session_valid_on?(page)
2020
authenticate_on(page)
@@ -60,6 +60,10 @@ def service_name
6060
end
6161

6262
private
63+
def auth_check_url
64+
signin_redirect_url
65+
end
66+
6367
def authenticate
6468
raise NotImplementedError
6569
end

test/lib/helpers/mock_playwright_helper.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,26 @@ def closed? = @closed
2222

2323
class MockTracing
2424
def start(**options) = nil
25-
def stop(**options) = nil
25+
26+
def stop(path:)
27+
FileUtils.mkdir_p(File.dirname(path))
28+
File.write(path, "trace")
29+
end
30+
end
31+
32+
class MockVideo
33+
def save_as(path)
34+
FileUtils.mkdir_p(File.dirname(path))
35+
File.write(path, "video")
36+
end
2637
end
2738

2839
class MockPage
2940
def goto(url, **options) = nil
3041
def url = "https://example.com/"
3142
def close = nil
3243
def on(event, callback) = nil
33-
def video = nil
44+
def video = MockVideo.new
3445
def wait_for_load_state(**options) = nil
3546
end
3647
end

0 commit comments

Comments
 (0)