import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' import ResponsiveImage from './ResponsiveImage.vue' const ORIGINAL = 'https://files.duffcloudservices.com/kept/assets/hero/abc-123.jpg' describe('ResponsiveImage self-healing fallback', () => { it('renders a with for a CDN image by default', () => { const wrapper = mount(ResponsiveImage, { props: { src: ORIGINAL, alt: 'Hero', context: 'hero' }, }) expect(wrapper.find('picture').exists()).toBe(true) expect(wrapper.find('source').exists()).toBe(true) expect(wrapper.find('img').attributes('src')).toContain('abc-123-md.webp') }) it('swaps to props.src and removes when the variant errors', async () => { const wrapper = mount(ResponsiveImage, { props: { src: ORIGINAL, alt: 'Hero', context: 'hero', class: 'object-cover' }, }) expect(wrapper.find('picture').exists()).toBe(true) expect(wrapper.find('source').exists()).toBe(true) await wrapper.find('img').trigger('error') // / must be neutralized so the original can display. expect(wrapper.find('picture').exists()).toBe(false) expect(wrapper.find('source').exists()).toBe(false) const img = wrapper.find('img') expect(img.exists()).toBe(true) expect(img.attributes('src')).toBe(ORIGINAL) // The class binding survives the fallback render. expect(img.classes()).toContain('object-cover') }) it('renders a plain at props.src when `original` is set', () => { const wrapper = mount(ResponsiveImage, { props: { src: ORIGINAL, alt: 'Hero', context: 'hero', original: true }, }) expect(wrapper.find('picture').exists()).toBe(false) expect(wrapper.find('img').attributes('src')).toBe(ORIGINAL) }) }) describe('ResponsiveImage source-fit variants (C-804 / Q-561=A)', () => { it('omits variants wider than the source once width/height are supplied', () => { // The iron-oak banner shape: a 1024x212 source must stop advertising 1920w. const wrapper = mount(ResponsiveImage, { props: { src: ORIGINAL, alt: 'Banner', context: 'hero', width: 1024, height: 212 }, }) const srcset = wrapper.find('source').attributes('srcset')! expect(srcset).toContain('abc-123-sm.webp 640w') expect(srcset).toContain('abc-123-md.webp 1024w') expect(srcset).not.toContain('-lg.webp') expect(srcset).not.toContain('1920w') const img = wrapper.find('img') expect(img.attributes('src')).toContain('abc-123-md.webp') // The same props also feed the pre-existing CLS hint, which this component // could not emit at all before it grew width/height. expect(img.attributes('width')).toBe('1024') expect(img.attributes('height')).toBe('212') }) it('re-points the fallback when the source is narrower than -md', () => { const wrapper = mount(ResponsiveImage, { props: { src: ORIGINAL, alt: 'Narrow', context: 'content', width: 800 }, }) expect(wrapper.find('source').attributes('srcset')).toBe( 'https://files.duffcloudservices.com/kept/assets/hero/abc-123-sm.webp 640w' ) expect(wrapper.find('img').attributes('src')).toContain('abc-123-sm.webp') }) it('is byte-for-byte unchanged when no width is supplied', () => { const wrapper = mount(ResponsiveImage, { props: { src: ORIGINAL, alt: 'Hero', context: 'hero' }, }) expect(wrapper.find('source').attributes('srcset')).toBe( 'https://files.duffcloudservices.com/kept/assets/hero/abc-123-sm.webp 640w, ' + 'https://files.duffcloudservices.com/kept/assets/hero/abc-123-md.webp 1024w, ' + 'https://files.duffcloudservices.com/kept/assets/hero/abc-123-lg.webp 1920w' ) }) })