From abb49026bd2ff7f8dec60b547130dd096f0c4127 Mon Sep 17 00:00:00 2001 From: Duncan Bayne Date: Thu, 20 Mar 2025 14:05:42 +1100 Subject: [PATCH 1/6] Use forked Ferrum library until upstream accepts our patches We need to expose the mobile setting in the Ferrum API as well. Until that's merged, use a fork of Ferrum that exposes it. --- Gemfile | 1 + lib/capybara/cuprite/page.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index b936ae2f..a6a5fccb 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,7 @@ source "https://rubygems.org" gem "byebug", "~> 11.1", platforms: %i[mri mingw x64_mingw] gem "chunky_png", "~> 1.4" +gem "ferrum", github: "radiopaedia/ferrum", branch: "94-expose-mobile" gem "image_size", "~> 3.0" gem "launchy", "~> 2.5" gem "pdf-reader", "~> 2.12" diff --git a/lib/capybara/cuprite/page.rb b/lib/capybara/cuprite/page.rb index f3e2bf3e..fb116419 100644 --- a/lib/capybara/cuprite/page.rb +++ b/lib/capybara/cuprite/page.rb @@ -144,7 +144,7 @@ def prepare_page super width, height = @options.window_size - resize(width: width, height: height) + resize(width: width, height: height, mobile: @options.mobile) if @options.url_blacklist.any? network.blacklist = @options.url_blacklist From d010e996cb803e6823e622e38fbb0267c31e4bed Mon Sep 17 00:00:00 2001 From: Duncan Bayne Date: Fri, 21 Mar 2025 11:29:26 +1100 Subject: [PATCH 2/6] Test that we can register a driver with mobile emulation This tests for mobile emulation by: * Checking that text controlled by a CSS media query is / isn't visible. * Checking that touch input is enabled / disabled. --- spec/features/driver_spec.rb | 27 ++++++++++++++++++++++++++- spec/spec_helper.rb | 8 ++++++++ spec/support/views/mobile.erb | 26 ++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 spec/support/views/mobile.erb diff --git a/spec/features/driver_spec.rb b/spec/features/driver_spec.rb index 4896324c..dcc12c0a 100644 --- a/spec/features/driver_spec.rb +++ b/spec/features/driver_spec.rb @@ -8,11 +8,12 @@ module Capybara module Cuprite describe Driver do let(:device_pixel_ratio) { @driver.device_pixel_ratio } + let(:mobile) { false } include Spec::Support::ExternalBrowser around do |example| - @session = TestSessions::Cuprite + @session = mobile ? TestSessions::CupriteMobile : TestSessions::Cuprite @driver = @session.driver example.run ensure @@ -50,6 +51,30 @@ def session_url(path) driver&.quit end + describe "mobile emulation" do + context "when mobile emulation is enabled" do + let(:mobile) { true } + + it "emulates a mobile browser" do + @session.visit("/cuprite/mobile") + expect(@session).to have_text("I am a mobile.") + expect(@session).to have_no_text("I am a desktop.") + expect(@session.evaluate_script("'ontouchstart' in window || navigator.maxTouchPoints > 0")).to be_truthy + end + end + + context "when mobile emulation is disabled" do + let(:mobile) { false } + + it "does not emulate a mobile browser" do + @session.visit("/cuprite/mobile") + expect(@session).to have_text("I am a desktop.") + expect(@session).to have_no_text("I am a mobile.") + expect(@session.evaluate_script("'ontouchstart' in window || navigator.maxTouchPoints > 0")).to be_falsy + end + end + end + context "output redirection" do let(:logger) { StringIO.new } let(:session) { Capybara::Session.new(:cuprite_with_logger, TestApp) } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index bcc30d69..8d4e1e37 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -29,6 +29,14 @@ Capybara::Cuprite::Driver.new(app, options) end +Capybara.register_driver(:cuprite_mobile) do |app| + options = { mobile: true } + options.merge!(inspector: true) if ENV["INSPECTOR"] + options.merge!(logger: StringIO.new) if ENV["CI"] + options.merge!(headless: false) if ENV["HEADLESS"] == "false" + Capybara::Cuprite::Driver.new(app, options) +end + module TestSessions Cuprite = Capybara::Session.new(:cuprite, TestApp) end diff --git a/spec/support/views/mobile.erb b/spec/support/views/mobile.erb new file mode 100644 index 00000000..13a16204 --- /dev/null +++ b/spec/support/views/mobile.erb @@ -0,0 +1,26 @@ + + + + Mobile test page + + + +
+ I am a desktop. +
+ +
+ I am a mobile. +
+ + From 8567d60028b47c34defe317b5f3a1babb565c8c0 Mon Sep 17 00:00:00 2001 From: Duncan Bayne Date: Wed, 26 Mar 2025 09:58:29 +1100 Subject: [PATCH 3/6] Fix mobile specs These were (a) trying to use a non-existent session, and (b) trying to set both `mobile: true` and a resolution, which is now disallowed. --- lib/capybara/cuprite/page.rb | 6 +++++- spec/spec_helper.rb | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/capybara/cuprite/page.rb b/lib/capybara/cuprite/page.rb index fb116419..e5aa7e08 100644 --- a/lib/capybara/cuprite/page.rb +++ b/lib/capybara/cuprite/page.rb @@ -144,7 +144,11 @@ def prepare_page super width, height = @options.window_size - resize(width: width, height: height, mobile: @options.mobile) + if @options.mobile + resize(width: 0, height: 0, mobile: @options.mobile) + else + resize(width: width, height: height, mobile: @options.mobile) + end if @options.url_blacklist.any? network.blacklist = @options.url_blacklist diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8d4e1e37..d4a5470a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -39,6 +39,7 @@ module TestSessions Cuprite = Capybara::Session.new(:cuprite, TestApp) + CupriteMobile = Capybara::Session.new(:cuprite_mobile, TestApp) end RSpec.configure do |config| From 32a71823d1819e4f302a3f3592447ad487999a95 Mon Sep 17 00:00:00 2001 From: Duncan Bayne Date: Thu, 27 Mar 2025 14:51:46 +1100 Subject: [PATCH 4/6] Model devices as simply hashes of options for the driver --- lib/capybara/cuprite/devices.rb | 9 +++++++++ lib/capybara/cuprite/page.rb | 6 +----- spec/spec_helper.rb | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 lib/capybara/cuprite/devices.rb diff --git a/lib/capybara/cuprite/devices.rb b/lib/capybara/cuprite/devices.rb new file mode 100644 index 00000000..98aa1ee7 --- /dev/null +++ b/lib/capybara/cuprite/devices.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Capybara + module Cuprite + module Devices + IPHONE_14 = { window_size: [390, 844], mobile: true, scale_factor: 3 } + end + end +end diff --git a/lib/capybara/cuprite/page.rb b/lib/capybara/cuprite/page.rb index e5aa7e08..fb116419 100644 --- a/lib/capybara/cuprite/page.rb +++ b/lib/capybara/cuprite/page.rb @@ -144,11 +144,7 @@ def prepare_page super width, height = @options.window_size - if @options.mobile - resize(width: 0, height: 0, mobile: @options.mobile) - else - resize(width: width, height: height, mobile: @options.mobile) - end + resize(width: width, height: height, mobile: @options.mobile) if @options.url_blacklist.any? network.blacklist = @options.url_blacklist diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d4a5470a..37b9aae1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,6 +11,7 @@ require "capybara/spec/spec_helper" require "capybara/cuprite" +require "capybara/cuprite/devices" require "support/test_app" require "support/external_browser" @@ -30,7 +31,7 @@ end Capybara.register_driver(:cuprite_mobile) do |app| - options = { mobile: true } + options = Capybara::Cuprite::Devices::IPHONE_14 options.merge!(inspector: true) if ENV["INSPECTOR"] options.merge!(logger: StringIO.new) if ENV["CI"] options.merge!(headless: false) if ENV["HEADLESS"] == "false" From 56053515f4c9bb507c176d816500c23b71934ccc Mon Sep 17 00:00:00 2001 From: Duncan Bayne Date: Thu, 27 Mar 2025 14:54:29 +1100 Subject: [PATCH 5/6] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c6b6e376..3a63c2b7 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Capybara.register_driver(:cuprite) do |app| end ``` -if you use `Docker` don't forget to pass `no-sandbox` option: +If you use `Docker` don't forget to pass `no-sandbox` option: ```ruby Capybara::Cuprite::Driver.new(app, browser_options: { 'no-sandbox': nil }) From d2405cd76287a226d258b7391d89cd7bb33455e3 Mon Sep 17 00:00:00 2001 From: Duncan Bayne Date: Thu, 27 Mar 2025 14:57:23 +1100 Subject: [PATCH 6/6] Add documentation about emulation --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 3a63c2b7..d606c04e 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,14 @@ end * `:url_blacklist` (Array) - array of regexes to match against requested URLs * `:url_whitelist` (Array) - array of regexes to match against requested URLs +You can emulate specific devices at the time you register a driver: + +```ruby +require "capybara/cuprite/devices" +Capybara.register_driver(:cuprite) do |app| + Capybara::Cuprite::Driver.new(app, Capybara::Cuprite::Devices::IPHONE_14) +end +``` ## Debugging