55class PrimerOpenProjectAvatarWithFallbackTest < Minitest ::Test
66 include Primer ::ComponentTestHelpers
77
8- def test_renders_image_avatar_with_src
8+ # "Fallback First" pattern tests:
9+ # - img.src is ALWAYS the fallback SVG initially
10+ # - data-avatar-src contains the real URL for JS to test-load
11+ # - JS swaps to real image only on successful load
12+
13+ def test_renders_fallback_first_with_real_url_in_data_attribute
914 render_inline ( Primer ::OpenProject ::AvatarWithFallback . new ( src : "https://github.com/github.png" , alt : "github" ) )
1015
11- # Always wrapped in avatar- fallback for 404 error handling
12- assert_selector ( "avatar-fallback[data-fallback -src^='data:image/svg+xml;base64, ']" ) do
13- assert_selector ( "img.avatar[src='https://github.com/github.png ']" )
16+ # Image always shows fallback SVG first
17+ assert_selector ( "avatar-fallback[data-avatar -src='https://github.com/github.png ']" ) do
18+ assert_selector ( "img.avatar[src^='data:image/svg+xml;base64, ']" )
1419 end
1520 end
1621
17- def test_image_avatar_error_handling_setup
22+ def test_preserves_unique_id_and_alt_text_for_client_side_processing
1823 render_inline ( Primer ::OpenProject ::AvatarWithFallback . new ( src : "https://example.com/avatar.png" , alt : "Alice Johnson" , unique_id : 123 ) )
1924
20- # Original src is preserved (client-side JS handles error -> fallback swap)
21- assert_selector ( "avatar-fallback[data-unique-id='123'][data-alt-text='Alice Johnson']" ) do
22- assert_selector ( "img.avatar[src='https://example.com/avatar.png']" )
25+ assert_selector ( "avatar-fallback[data-unique-id='123'][data-alt-text='Alice Johnson'][data-avatar-src='https://example.com/avatar.png']" ) do
26+ assert_selector ( "img.avatar[src^='data:image/svg+xml;base64,']" )
2327 end
2428
25- # Verify fallback SVG is available and contains correct initials
29+ # Verify fallback SVG contains correct initials
2630 fallback_wrapper = page . find ( "avatar-fallback" )
27- fallback_src = fallback_wrapper [ "data-fallback-src" ]
28-
29- assert fallback_src . start_with? ( "data:image/svg+xml;base64," )
30- svg_content = Base64 . decode64 ( fallback_src . sub ( "data:image/svg+xml;base64," , "" ) )
31+ img = fallback_wrapper . find ( "img" )
32+ svg_content = Base64 . decode64 ( img [ "src" ] . sub ( "data:image/svg+xml;base64," , "" ) )
3133 assert_includes svg_content , ">AJ<" , "Fallback SVG should contain initials 'AJ'"
3234 end
3335
3436 def test_renders_fallback_when_src_is_nil
3537 render_inline ( Primer ::OpenProject ::AvatarWithFallback . new ( src : nil , alt : "OpenProject Admin" ) )
3638
37- # Should render avatar-fallback element wrapping an img with base64 SVG data URI
38- assert_selector ( "avatar-fallback[data-alt-text='OpenProject Admin']" ) do
39+ # No data- avatar-src when src is nil
40+ assert_selector ( "avatar-fallback[data-alt-text='OpenProject Admin']:not([data-avatar-src]) " ) do
3941 assert_selector ( "img.avatar[src^='data:image/svg+xml;base64,']" )
4042 end
4143 end
4244
4345 def test_renders_fallback_when_src_is_blank
4446 render_inline ( Primer ::OpenProject ::AvatarWithFallback . new ( src : "" , alt : "OpenProject Admin" ) )
4547
46- assert_selector ( "avatar-fallback[data-alt-text='OpenProject Admin']" ) do
48+ # No data-avatar-src when src is blank
49+ assert_selector ( "avatar-fallback[data-alt-text='OpenProject Admin']:not([data-avatar-src])" ) do
4750 assert_selector ( "img.avatar[src^='data:image/svg+xml;base64,']" )
4851 end
4952 end
@@ -101,7 +104,6 @@ def test_sets_size_height_and_width
101104 def test_fallback_sets_correct_size_class
102105 render_inline ( Primer ::OpenProject ::AvatarWithFallback . new ( src : nil , alt : "Test User" , size : 40 ) )
103106
104- # Size is set via attributes, not a dedicated class
105107 assert_selector ( "img.avatar[size='40'][height='40'][width='40'][src^='data:image/svg+xml;base64,']" )
106108 end
107109
@@ -132,7 +134,6 @@ def test_renders_link_wrapper
132134 def test_fallback_renders_link_wrapper
133135 render_inline ( Primer ::OpenProject ::AvatarWithFallback . new ( src : nil , alt : "Test User" , href : "#test" ) )
134136
135- # When href is provided, the avatar class is on the <a> tag, not the <img>
136137 assert_selector ( "avatar-fallback" ) do
137138 assert_selector ( "a.avatar[href='#test']" ) do
138139 assert_selector ( "img[src^='data:image/svg+xml;base64,']" )
@@ -143,7 +144,6 @@ def test_fallback_renders_link_wrapper
143144 def test_fallback_with_unique_id_in_data_attribute
144145 render_inline ( Primer ::OpenProject ::AvatarWithFallback . new ( src : nil , alt : "Test User" , unique_id : 123 ) )
145146
146- # Should have data attributes for client-side processing
147147 assert_selector ( "avatar-fallback[data-unique-id='123'][data-alt-text='Test User']" ) do
148148 assert_selector ( "img.avatar[src^='data:image/svg+xml;base64,']" )
149149 end
@@ -189,9 +189,10 @@ def test_raises_when_both_src_and_alt_are_blank
189189 def test_fallback_with_single_word_name
190190 render_inline ( Primer ::OpenProject ::AvatarWithFallback . new ( src : nil , alt : "Alice" ) )
191191
192- assert_selector ( "avatar-fallback" ) do
193- assert_selector ( "img.avatar[src^='data:image/svg+xml;base64,']" )
194- end
192+ img = page . find ( "img.avatar" )
193+ svg_content = Base64 . decode64 ( img [ "src" ] . sub ( "data:image/svg+xml;base64," , "" ) )
194+
195+ assert_includes svg_content , ">A<" , "Single word name should produce single initial 'A'"
195196 end
196197
197198 def test_status
0 commit comments