Skip to content

Commit

Permalink
test(Image): test for Image added
Browse files Browse the repository at this point in the history
  • Loading branch information
niktverd committed Sep 19, 2023
1 parent f95a76f commit 32491b8
Show file tree
Hide file tree
Showing 6 changed files with 323 additions and 64 deletions.
22 changes: 14 additions & 8 deletions src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ import React from 'react';
import {render, screen} from '@testing-library/react';

import {testCustomClassName, testCustomStyle} from '../../../../test-utils/shared/common';
import {testSourceProps} from '../../../../test-utils/shared/image';
import {BackgroundImageProps} from '../../../models';
import {getQaAttrubutes} from '../../../utils';
import BackgroundImage from '../BackgroundImage';

const qa = 'background-image-component';

const imageSrc =
'https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img-gray.png';

const qaAttributes = getQaAttrubutes(qa, 'image-display-source');

describe('BackgroundImage', () => {
test('Render BackgroundImage by default', async () => {
render(<BackgroundImage qa={qa} />);
Expand All @@ -21,17 +25,19 @@ describe('BackgroundImage', () => {
});

test('add image as src prop', () => {
render(<BackgroundImage src={imageSrc} />);
const component = screen.getByRole('img');

expect(component).toHaveAttribute('src', imageSrc);
testSourceProps<BackgroundImageProps>({
component: BackgroundImage,
props: {src: imageSrc, qa},
options: {qaId: qaAttributes.imageDisplaySource},
});
});

test('add image as desktop prop', () => {
render(<BackgroundImage desktop={imageSrc} />);
const component = screen.getByRole('img');

expect(component).toHaveAttribute('src', imageSrc);
testSourceProps<BackgroundImageProps>({
component: BackgroundImage,
props: {desktop: imageSrc, qa},
options: {qaId: qaAttributes.imageDisplaySource},
});
});

test('should hide image', () => {
Expand Down
15 changes: 5 additions & 10 deletions src/components/Button/__tests__/Button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import React from 'react';

import {ButtonSize} from '@gravity-ui/uikit';
import {render, screen} from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import {testCustomClassName} from '../../../../test-utils/shared/common';
import {testCustomClassName, testOnClick} from '../../../../test-utils/shared/common';
import {ButtonImagePosition, ButtonTheme} from '../../../models';
import Button, {ButtonProps} from '../Button';
import {ICON_QA} from '../utils';
Expand Down Expand Up @@ -63,14 +62,10 @@ describe('Button', () => {
});

test('call onClick', async () => {
const user = userEvent.setup();
const handleOnClick = jest.fn();
render(<Button text={buttonProps.text} onClick={handleOnClick} />);

const button = screen.getByRole('button');

await user.click(button);
expect(handleOnClick).toHaveBeenCalledTimes(1);
testOnClick<ButtonProps>({
component: Button,
props: {text: buttonProps.text, qa},
});
});

test.each(new Array<ButtonSize>('s', 'm', 'l', 'xl'))('render with given "%s" size', (size) => {
Expand Down
67 changes: 37 additions & 30 deletions src/components/Image/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,35 @@ export interface ImageProps extends Partial<ImageObjectProps>, Partial<ImageDevi
containerClassName?: string;
}

export interface DeviceSpecificFragmentProps extends QAProps {
disableWebp: boolean;
src: string;
breakpoint: 'md' | 'sm';
}

const checkWebP = (src: string) => {
return src.endsWith('.webp') ? src : src + '.webp';
};

const DeviceSpecificFragment = ({
disableWebp,
src,
breakpoint,
qa,
}: DeviceSpecificFragmentProps) => (
<Fragment>
{!disableWebp && (
<source
srcSet={checkWebP(src)}
type="image/webp"
media={`(max-width: ${BREAKPOINTS[breakpoint]}px)`}
data-qa={`${qa}-compressed`}
/>
)}
<source srcSet={src} media={`(max-width: ${BREAKPOINTS[breakpoint]}px)`} data-qa={qa} />
</Fragment>
);

const Image = (props: ImageProps) => {
const projectSettings = useContext(ProjectSettingsContext);
const {
Expand Down Expand Up @@ -61,38 +86,20 @@ const Image = (props: ImageProps) => {
return (
<picture className={containerClassName} data-qa={qa}>
{mobile && (
<Fragment>
{!disableWebp && (
<source
srcSet={checkWebP(mobile)}
type="image/webp"
media={`(max-width: ${BREAKPOINTS.sm}px)`}
data-qa={qaAttributes.mobileWebpSource}
/>
)}
<source
srcSet={mobile}
media={`(max-width: ${BREAKPOINTS.sm}px)`}
data-qa={qaAttributes.mobileSource}
/>
</Fragment>
<DeviceSpecificFragment
src={mobile}
disableWebp={disableWebp}
breakpoint="sm"
qa={qaAttributes.mobileSource}
/>
)}
{tablet && (
<Fragment>
{!disableWebp && (
<source
srcSet={checkWebP(tablet)}
type="image/webp"
media={`(max-width: ${BREAKPOINTS.md}px)`}
data-qa={qaAttributes.tabletWebpSource}
/>
)}
<source
srcSet={tablet}
media={`(max-width: ${BREAKPOINTS.md}px)`}
data-qa={qaAttributes.tabletSource}
/>
</Fragment>
<DeviceSpecificFragment
src={tablet}
disableWebp={disableWebp}
breakpoint="md"
qa={qaAttributes.tabletSource}
/>
)}
{src && !disableWebp && (
<source
Expand Down
131 changes: 131 additions & 0 deletions src/components/Image/__tests__/Image.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React from 'react';

import {render, screen} from '@testing-library/react';

import {
testCustomClassName,
testCustomStyle,
testOnClick,
} from '../../../../test-utils/shared/common';
import {testSourceProps} from '../../../../test-utils/shared/image';
import Image, {ImageProps} from '../Image';
import i18n from '../i18n';

const qaId = 'image-component';

const imageSrc =
'https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img-gray.png';

describe('Image', () => {
test('Render Image by default', async () => {
render(<Image src={imageSrc} qa={qaId} />);

const component = screen.getByTestId(qaId);
expect(component).toBeInTheDocument();
expect(component).toBeVisible();
});

test('add image as src prop', () => {
testSourceProps<ImageProps>({
component: Image,
props: {src: imageSrc, qa: qaId},
});
});

test('add image as desktop prop', () => {
testSourceProps<ImageProps>({
component: Image,
props: {desktop: imageSrc, qa: qaId},
});
});

test('add image as tablet prop', () => {
testSourceProps<ImageProps>({
component: Image,
props: {desktop: imageSrc, tablet: imageSrc, qa: qaId},
});
});

test('add image as mobile prop', () => {
testSourceProps<ImageProps>({
component: Image,
props: {desktop: imageSrc, mobile: imageSrc, qa: qaId},
});
});

test('add image as src prop with disabledCompress', () => {
testSourceProps<ImageProps>({
component: Image,
props: {src: imageSrc, qa: qaId, disableCompress: true},
});
});

test('add image as desktop prop with disabledCompress', () => {
testSourceProps<ImageProps>({
component: Image,
props: {desktop: imageSrc, qa: qaId, disableCompress: true},
});
});

test('add image as tablet prop with disabledCompress', () => {
testSourceProps<ImageProps>({
component: Image,
props: {desktop: imageSrc, tablet: imageSrc, qa: qaId, disableCompress: true},
});
});

test('add image as mobile prop with disabledCompress', () => {
testSourceProps<ImageProps>({
component: Image,
props: {desktop: imageSrc, mobile: imageSrc, qa: qaId, disableCompress: true},
});
});

test('add className', () => {
testCustomClassName<ImageProps>({
component: Image,
props: {src: imageSrc, qa: qaId},
options: {customClassNameProp: 'containerClassName'},
});
});

test('add className to image', () => {
const className = 'custom-class-name';

render(<Image className={className} src={imageSrc} qa={qaId} />);

const component = screen.getByRole('img');
expect(component).toHaveClass(className);
});

test('add style', () => {
testCustomStyle<ImageProps>({
component: Image,
props: {src: imageSrc, qa: qaId},
options: {role: 'img'},
});
});

test('render default "alt"', () => {
render(<Image src={imageSrc} qa={qaId} />);

const component = screen.getByRole('img');
expect(component).toHaveAttribute('alt', i18n('img-alt'));
});

test('render custom "alt"', () => {
const alt = 'defined-alt';
render(<Image src={imageSrc} alt={alt} qa={qaId} />);

const component = screen.getByRole('img');
expect(component).toHaveAttribute('alt', alt);
});

test('call onClick', async () => {
testOnClick<ImageProps>({
component: Image,
props: {src: imageSrc, qa: qaId},
options: {role: 'img'},
});
});
});
64 changes: 48 additions & 16 deletions test-utils/shared/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,49 @@ import {ERROR_INPUT_DATA_MESSAGE} from '../constants';
type CommonTestArgs<T> = {
component: ElementType;
props: T & QAProps;
options?: {qaId?: string};
options?: {qaId?: string; customClassNameProp?: string; role?: string};
};

const validateInputProps = <T,>(props: CommonTestArgs<T>['props']) => {
if (!props.qa) {
throw new Error(ERROR_INPUT_DATA_MESSAGE);
}
};

const getComponent = <T,>({props, options}: Omit<CommonTestArgs<T>, 'component'>) => {
if (!props.qa) {
throw new Error(ERROR_INPUT_DATA_MESSAGE);
}

return options?.role
? screen.getByRole(options.role)
: screen.getByTestId(options?.qaId || props.qa);
};

export const testCustomClassName = <T,>({
component: Component,
props,
options,
}: CommonTestArgs<T>) => {
if (!props.qa) {
throw new Error(ERROR_INPUT_DATA_MESSAGE);
}
validateInputProps(props);

const className = 'custom-class-name';
render(<Component className={className} {...props} />);
const anchor = screen.getByTestId(options?.qaId || props.qa);
expect(anchor).toHaveClass(className);
const classNameProps = {
[options?.customClassNameProp || 'className']: className,
};
render(<Component {...props} {...classNameProps} />);
const component = getComponent({props, options});

expect(component).toHaveClass(className);
};

export const testCustomStyle = <T,>({component: Component, props}: CommonTestArgs<T>) => {
if (!props.qa) {
throw new Error(ERROR_INPUT_DATA_MESSAGE);
}
export const testCustomStyle = <T,>({component: Component, props, options}: CommonTestArgs<T>) => {
validateInputProps(props);

const style = {color: 'red'};

render(<Component {...props} style={style} />);
const component = screen.getByTestId(props.qa);
const component = getComponent({props, options});

expect(component).toHaveStyle(style);
};
Expand All @@ -44,14 +60,30 @@ export const testAnimated = async <T,>({
props,
options,
}: CommonTestArgs<T>) => {
if (!options?.qaId) {
throw new Error(ERROR_INPUT_DATA_MESSAGE);
}
validateInputProps(props);

const user = userEvent.setup();
render(<Component animated {...props} />);
const component = screen.getByTestId(options?.qaId);
const component = getComponent({props, options});

await user.hover(component);

expect(component).toHaveClass('animate');
};

export const testOnClick = async <T,>({
component: Component,
props,
options,
}: CommonTestArgs<T>) => {
validateInputProps(props);

const user = userEvent.setup();
const handleOnClick = jest.fn();
render(<Component {...props} onClick={handleOnClick} />);

const component = getComponent({props, options});

await user.click(component);
expect(handleOnClick).toHaveBeenCalledTimes(1);
};
Loading

0 comments on commit 32491b8

Please sign in to comment.