44
loading...
This website collects cookies to deliver better user experience
yarn storybook
to start the Storybook and run yarn test --watch
to start the test-runner.// src/components/Image/Image.test.tsx
import * as React from 'react';
import { fireEvent, render } from '@testing-library/react';
import { Image } from './';
import { photoSrc } from '../../constants';
const altText = 'abcd';
describe('Image', () => {
it('should render the image properly', async () => {
// render the Image component
const { getByAltText } = render(<Image src={photoSrc} alt={altText} />);
// retrieve a reference to the image
const image = getByAltText(altText) as HTMLImageElement;
// load the image
fireEvent.load(image);
// verify that the image exists on the DOM
expect(image).toBeTruthy();
// verify the src of the image
expect(image.src).toEqual(photoSrc);
});
});
// src/components/Image/index.tsx
import React from 'react';
// import { fallbackSrc, loadingSrc } from '../../constants';
export interface ImageProps {
src: string;
alt: string;
height?: string | number;
}
export const Image: React.FC<ImageProps> = ({ src, alt, height = '400px' }) => {
return (
<>
<img
src={src}
alt={alt}
style={{ height, width: 'auto', borderRadius: '10px' }}
/>
</>
);
};
// src/components/Image.stories.tsx
import React from 'react';
import { Story, Meta } from '@storybook/react';
import { Image, ImageProps } from './';
import { photoSrc } from '../../constants';
export default {
title: 'Example/Image',
component: Image,
argTypes: {
src: { control: 'text' },
alt: { control: 'text' }
}
} as Meta;
const Template: Story<ImageProps> = args => <Image {...args} />;
export const Primary = Template.bind({});
Primary.args = {
src: photoSrc,
alt: 'Sample alt text'
};
// src/Image/Image.test.tsx
import * as React from 'react';
import { fireEvent, render } from '@testing-library/react';
import { Image } from './';
import { fallbackSrc, loadingSrc, photoSrc } from '../../constants';
const altText = 'abcd';
describe('Image', () => {
it('should render the image properly', async () => {
// render the Image component
const { getByAltText } = render(<Image src={photoSrc} alt={altText} />);
// retrieve a reference to the image
const image = getByAltText(altText) as HTMLImageElement;
// load the image
fireEvent.load(image);
// verify that the image exists on the DOM
expect(image).toBeTruthy();
// verify the src of the image
expect(image.src).toEqual(photoSrc);
});
it('should display the loader until the image loads', async () => {
const { getByAltText } = render(<Image src={photoSrc} alt={altText} />);
const image = getByAltText(altText) as HTMLImageElement;
// verify that the src of the image matches the loader. note that the image has not been loaded yet.
expect(image.src).toEqual(loadingSrc);
});
it('should handle errors and render the fallback', async () => {
const { getByAltText } = render(<Image src="#" alt={altText} />);
const image = getByAltText(altText) as HTMLImageElement;
// fire the error event for the image
fireEvent.error(image);
// verify that the src of the image matches our fallback
expect(image.src).toEqual(fallbackSrc);
});
// an extra test case that verifies that our height prop behaves as expected
it('should apply the provided height', async () => {
const height = '200px';
const { getByAltText } = render(
<Image src={photoSrc} alt={altText} height={height} />
);
const image = getByAltText(altText) as HTMLImageElement;
fireEvent.load(image);
expect(image.style.height).toEqual(height);
});
});
height
prop. More (good 😉) test cases never hurt!// src/components/Image/index.tsx
import React from 'react';
import { fallbackSrc, loadingSrc } from '../../constants';
export interface ImageProps {
src: string;
alt: string;
height?: string | number;
}
export const Image: React.FC<ImageProps> = ({ src, alt, height = '400px' }) => {
// whether an error has occured or not
const [err, setErr] = React.useState(false);
// whether the image is loading or not
const [loading, setLoading] = React.useState(true);
return (
<>
<img
// use the fallback image as src if an error has occured
// use the loader image as src if the image is still loading
src={!err ? (loading ? loadingSrc : src) : fallbackSrc}
alt={alt}
style={{ height, width: 'auto', borderRadius: '10px' }}
// set loading to false once the image has finished loading
onLoad={() => setLoading(false)}
// set err to true if an error occurs
onError={() => setErr(true)}
/>
</>
);
};
export const Src404 = Template.bind({});
Src404.args = {
src: '#',
alt: 'something broke'
};