diff --git a/CHANGELOG.md b/CHANGELOG.md index be6191d0..eb83b329 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Changed ### Fixed +- Full-page screenshots no longer resize the window, preventing focus steal on macOS [#580] ### Removed diff --git a/lib/ferrum/page/screenshot.rb b/lib/ferrum/page/screenshot.rb index d9f9de7d..102ec01f 100644 --- a/lib/ferrum/page/screenshot.rb +++ b/lib/ferrum/page/screenshot.rb @@ -282,22 +282,11 @@ def to_camel_case(option) end def capture_screenshot(options, full, background_color) - maybe_resize_fullscreen(full) do - with_background_color(background_color) do - command("Page.captureScreenshot", **options) - end - end.fetch("data") - end - - def maybe_resize_fullscreen(full) - if full - width, height = viewport_size.dup - resize(fullscreen: true) - end + options = options.merge(captureBeyondViewport: true) if full - yield - ensure - resize(width: width, height: height) if full + with_background_color(background_color) do + command("Page.captureScreenshot", **options) + end.fetch("data") end def with_background_color(color) diff --git a/spec/page/screenshot_spec.rb b/spec/page/screenshot_spec.rb index f068444a..a85c3e14 100644 --- a/spec/page/screenshot_spec.rb +++ b/spec/page/screenshot_spec.rb @@ -208,14 +208,15 @@ def create_screenshot(**options) expect(browser.viewport_size).to eq([800, 200]) end - it "resets to previous viewport when exception is raised" do + it "keeps previous viewport when exception is raised" do browser.go_to("/custom_html_size") browser.resize(width: 100, height: 100) allow(browser.page).to receive(:command).and_call_original expect(browser.page).to receive(:command) .with("Page.captureScreenshot", - format: "png", clip: { x: 0, y: 0, width: 1280, height: 1024, scale: 1.0 }) + format: "png", clip: { x: 0, y: 0, width: 1280, height: 1024, scale: 1.0 }, + captureBeyondViewport: true) .and_raise(StandardError) expect { browser.screenshot(path: file, full: true) } .to raise_exception(StandardError) @@ -226,6 +227,43 @@ def create_screenshot(**options) expect(File.exist?(file)).not_to be expect(browser.viewport_size).to eq([100, 100]) end + + it "does not mutate window state (no native macOS fullscreen transition)" do + browser.go_to("/long_page") + + client = browser.page.client + commands = [] + allow(client).to receive(:command).and_wrap_original do |m, name, **opts| + commands << [name, opts] + m.call(name, **opts) + end + + browser.screenshot(path: file, full: true) + + # Fix Ruby 3 `and_call_original` bug + RSpec::Mocks.space.proxy_for(client).reset + + bounds_calls = commands.select { |(name, _)| name == "Browser.setWindowBounds" } + expect(bounds_calls).to be_empty + end + + it "forwards captureBeyondViewport: true to Page.captureScreenshot" do + browser.go_to("/long_page") + + client = browser.page.client + capture_opts = nil + allow(client).to receive(:command).and_wrap_original do |m, name, **opts| + capture_opts = opts if name == "Page.captureScreenshot" + m.call(name, **opts) + end + + browser.screenshot(path: file, full: true) + + # Fix Ruby 3 `and_call_original` bug + RSpec::Mocks.space.proxy_for(client).reset + + expect(capture_opts).to include(captureBeyondViewport: true) + end end context "with area screenshot" do