From fd9da90065cc377f6d287cde23884dd309fd7d84 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Wed, 23 Sep 2026 08:28:42 +1200 Subject: [PATCH] Stop avatars shifting the page during feature specs spec/features/places/searching_a_place_spec.rb intermittently failed on "goes to members' index page": the click on "View all members >>" landed on nothing and the browser stayed put. Member avatars come from gravatar.com over the network and were rendered with img-fluid and no dimensions, so they reserved no space until they arrived. The link sits directly under that grid. Capybara found the link, an avatar landed, the link moved, and the click missed. rails_helper meant to prevent this, but its guard tested for Poltergeist's url_blacklist. Poltergeist is long gone and Selenium's browser has no such method, so the condition was always false and the block never ran. - Give the two avatar image tags explicit width and height, so the box is reserved before the image loads. This fixes real layout shift for members too, not only the specs. - Replace the dead guard with config.x.blank_avatars, which browser specs set, making avatar_uri return a blank inline GIF. Helper specs still assert the real Gravatar URLs. Co-Authored-By: Claude Opus 5 --- app/helpers/application_helper.rb | 7 +++++++ app/views/members/_avatar.html.haml | 2 +- app/views/members/_thumbnail.html.haml | 2 +- spec/rails_helper.rb | 18 ++++++++++-------- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7ebb3dba8..53526098b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -72,6 +72,12 @@ module ApplicationHelper text end + # A 1x1 transparent GIF, standing in for a real avatar when + # config.x.blank_avatars is set, which browser specs do: otherwise they fetch + # every avatar from gravatar.com for real, and one arriving mid-test moves + # whatever sits under it, so clicks land on the wrong thing. + BLANK_AVATAR = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' + # # Returns an image uri for a given member. # @@ -79,6 +85,7 @@ module ApplicationHelper # def avatar_uri(member, size = 150) return unless member + return BLANK_AVATAR if Rails.configuration.x.blank_avatars if member.preferred_avatar_uri.present? # Some avatars support different sizes diff --git a/app/views/members/_avatar.html.haml b/app/views/members/_avatar.html.haml index b4ea132a9..a5e4ed80c 100644 --- a/app/views/members/_avatar.html.haml +++ b/app/views/members/_avatar.html.haml @@ -1 +1 @@ -= link_to image_tag(avatar_uri(member, 150), alt: "Avatar of #{member}", class: 'avatar img img-fluid'), member_path(member) += link_to image_tag(avatar_uri(member, 150), alt: "Avatar of #{member}", class: 'avatar img img-fluid', width: 150, height: 150), member_path(member) diff --git a/app/views/members/_thumbnail.html.haml b/app/views/members/_thumbnail.html.haml index dc9d7b9ca..e82cf5454 100644 --- a/app/views/members/_thumbnail.html.haml +++ b/app/views/members/_thumbnail.html.haml @@ -5,7 +5,7 @@ / Avatar .avatar.mx-auto.white = link_to member do - = image_tag(avatar_uri(member, 150), class: 'rounded-circle img-fluid', alt: member) + = image_tag(avatar_uri(member, 150), class: 'rounded-circle img-fluid', alt: member, width: 150, height: 150) .card-body / Name %h4.card-title diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index bd64cd333..f20057711 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -117,20 +117,22 @@ RSpec.configure do |config| # Allow just create(:factory) instead of needing to specify FactoryBot.create(:factory) config.include FactoryBot::Syntax::Methods - # Prevent Poltergeist from fetching external URLs during feature tests + config.after(:each, :js) do + Rails.configuration.x.blank_avatars = false + end + config.before(:each, :js) do # TODO: Why are we setting this page size then straight afterwards, maximising? width = 1920 height = 1080 Capybara.current_session.driver.browser.manage.window.resize_to(width, height) - if page.driver.browser.respond_to?(:url_blacklist) - page.driver.browser.url_blacklist = [ - 'gravatar.com', - 'okfn.org', - 'googlecode.com' - ] - end + # This used to block gravatar.com and friends through Poltergeist's + # url_blacklist. Poltergeist is long gone and Selenium's browser has no + # such method, so the guard was always false and the block never ran — + # every browser spec has been fetching avatars from gravatar.com for real. + # Stand them down instead, so nothing loads late and shifts the page. + Rails.configuration.x.blank_avatars = true # Historically, we wanted to .maximize; but this actually undoes the resize_to step above # with chrome headless