Skip to content
43 changes: 43 additions & 0 deletions components/Avatar/Avatar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Avatar from './Avatar';
import { render, screen } from '@testing-library/react';
import { type ComponentProps } from 'react';

jest.mock('@radix-ui/react-avatar', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI for anyone coming across this. My first instinct was to ask why are we mocking this as you always want to mock as little as possible or not at all so we are testing the actual implementation.

In this case, we mock Radix’s Avatar.Image because in JSDOM, what we use in Jest tests, image load events don’t fire as it's not a real browser environment, so only the fallback is ever shown in tests if we don't mock.

const actual = jest.requireActual('@radix-ui/react-avatar');
return ({
...actual,
Image: (props: ComponentProps<'img'>) => {
return <img {...props}/>;
}
})
});

describe('Avatar Component', () => {

it('Renders the component with user image using valid src attribute', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the fallback component show here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this scenario. I wanted to test that the user provided image is correctly added to the document.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an exception to check that fallback doesn't show in this default scenario.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly the fallback image is still showing in the document for this scenario. I tried using .not.toBeVisible() method as well as .not.toBeInTheDocument() but both tests fail:

1st attempt:

+ const avatarElementFallbackImage = screen.getByTestId('avatar-fallback')
+ expect(avatarElementFallbackImage).not.toBeVisible();

2nd attempt:

+ const avatarElementFallbackImage = screen.getByTestId('avatar-fallback')
+ expect(avatarElementFallbackImage).not.toBeInTheDocument();

I tried looking at screen.debug() and it's showing both elements in the JSDOM. Are both of these supposed to show up like this?

Screen-debug-avatar-component

render(<Avatar userAvatar='https://mdbcdn.b-cdn.net/img/new/avatars/2.webp' />);

const avatarElementWithImage = screen.getByTestId('avatar-image')
expect(avatarElementWithImage).toBeInTheDocument();
expect(avatarElementWithImage).toHaveAttribute(
'src',
'https://mdbcdn.b-cdn.net/img/new/avatars/2.webp',
);

});

it('Renders the fallback image when src is undefined', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about when there's a string given bug the image is not found?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, I'll add this test scenario.

render(<Avatar userAvatar={undefined} />);

const avatarElementFallbackImage = screen.getByTestId('avatar-fallback')
expect(avatarElementFallbackImage).toBeInTheDocument();
});

it('Renders the fallback image when an invalid src is provided', () => {
render(<Avatar userAvatar='https://mdbcdn.b-cdn.net/img/new/avatars/bad-img-url.webp' />);

const avatarElementFallbackImage = screen.getByTestId('avatar-fallback')
expect(avatarElementFallbackImage).toBeInTheDocument();
});

});
1 change: 1 addition & 0 deletions components/Avatar/AvatarImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const AvatarImage = forwardRef<
ref={ref}
alt={alt}
className={cn('aspect-square h-full w-full', className)}
data-testid="avatar-image"
{...props}
/>
),
Expand Down
Loading