import React from 'react'; import { render, screen, act } from '@testing-library/react'; import { Avatar } from './'; const originalImage = window.Image; function restoreImage() { window.Image = originalImage; } /** * A Image mock that allows you to trigger `onload` event on demand. */ function mockImage() { const listeners: (() => void)[] = []; const event = { listen: (callback: () => void) => { listeners.push(callback); }, onload: () => { listeners.forEach((listener) => listener()); }, }; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error window.Image = class Image { src = ''; onload = () => { new Error('onload is not defined on the targeted Image'); }; constructor() { event.listen(() => { act(() => this.onload()); }); } }; return { onload: event.onload }; } describe('Avatar component', () => { beforeEach(() => { restoreImage(); }); describe('given src props', () => { it('displays an image tag as child with the `src` from props', async () => { const { onload } = mockImage(); render( , ); // While the image is loading, a placeholder is put in place expect(screen.getByRole('img', { name: 'A dog' })).not.toHaveAttribute( 'src', 'https://placedog.net/401', ); // Trigger onload onload(); // Image is now displayed expect(await screen.findByRole('img', { name: 'A dog' })).toHaveAttribute( 'src', 'https://placedog.net/401', ); }); it('displays the right icon when iconName is provided', () => { render(); expect(screen.getByRole('img')).toHaveAttribute('data-icon', 'person'); }); }); describe('given src is not provided', () => { it.each([ { name: 'Nayden Lennart', size: 24 as const, expected: 'N' }, { name: ' Nayden Lennart', size: 40 as const, expected: 'N' }, { name: ` Nayden Lennart`, size: 32 as const, expected: 'N', }, { name: '(-+=_)Nayden Lennart', size: 16 as const, expected: 'N' }, { name: '%%_$', size: 16 as const, expected: '' }, ])( 'displays $expected given $name as name and $size as size', ({ name, size, expected }) => { render(); expect( screen.getByRole('img', { name: name.trim() }), ).toHaveTextContent(expected); }, ); it('displays the image when src is given after the first render', () => { const { onload } = mockImage(); const text = 'Nayden Lennart'; const { rerender } = render(); onload(); // Avatar always gets the role img, however, properties are different from a img and a span expect(screen.getByRole('img', { name: text })).not.toHaveProperty('src'); rerender( , ); onload(); expect(screen.getByRole('img', { name: text })).toHaveProperty( 'src', 'https://placedog.net/401', ); }); it('fallbacks on fallbackSrc when given', () => { const text = 'Nayden Lennart'; render( , ); expect(screen.getByRole('img', { name: text })).toHaveProperty( 'src', 'https://placedog.net/201', ); }); }); describe('given a `badgeProps` props', () => { describe('when `badgeProps` uses `src` and `alt` properties', () => { it('contains a `Avatar` as child with the props inherited from `badgeProps`', () => { const { onload } = mockImage(); render( , ); onload(); expect(screen.getByRole('img', { name: 'A dog' })).toHaveAttribute( 'src', 'https://placedog.net/401', ); expect( screen.getByRole('img', { name: 'A corgi running' }), ).toHaveAttribute('src', 'https://placedog.net/500'); }); }); describe('when `badgeProps` uses `children` property', () => { it('contains a `Avatar` as child with the props inherited from `badgeProps`', () => { const { onload } = mockImage(); render( , ); onload(); expect(screen.getByRole('img', { name: 'A dog' })).toHaveAttribute( 'src', 'https://placedog.net/401', ); expect(screen.getByText('A')).toBeVisible(); }); }); }); });