diff --git a/src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx b/src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx
index 4326a66d3..d32bc5059 100644
--- a/src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx
+++ b/src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx
@@ -3,7 +3,9 @@ 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';
@@ -11,6 +13,8 @@ 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();
@@ -21,17 +25,19 @@ describe('BackgroundImage', () => {
});
test('add image as src prop', () => {
- render();
- const component = screen.getByRole('img');
-
- expect(component).toHaveAttribute('src', imageSrc);
+ testSourceProps({
+ component: BackgroundImage,
+ props: {src: imageSrc, qa},
+ options: {qaId: qaAttributes.imageDisplaySource},
+ });
});
test('add image as desktop prop', () => {
- render();
- const component = screen.getByRole('img');
-
- expect(component).toHaveAttribute('src', imageSrc);
+ testSourceProps({
+ component: BackgroundImage,
+ props: {desktop: imageSrc, qa},
+ options: {qaId: qaAttributes.imageDisplaySource},
+ });
});
test('should hide image', () => {
diff --git a/src/components/Button/__tests__/Button.test.tsx b/src/components/Button/__tests__/Button.test.tsx
index a3064bece..a7afd6ec7 100644
--- a/src/components/Button/__tests__/Button.test.tsx
+++ b/src/components/Button/__tests__/Button.test.tsx
@@ -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';
@@ -63,14 +62,10 @@ describe('Button', () => {
});
test('call onClick', async () => {
- const user = userEvent.setup();
- const handleOnClick = jest.fn();
- render();
-
- const button = screen.getByRole('button');
-
- await user.click(button);
- expect(handleOnClick).toHaveBeenCalledTimes(1);
+ testOnClick({
+ component: Button,
+ props: {text: buttonProps.text, qa},
+ });
});
test.each(new Array('s', 'm', 'l', 'xl'))('render with given "%s" size', (size) => {
diff --git a/src/components/Image/Image.tsx b/src/components/Image/Image.tsx
index 1861be1e7..167f408bd 100644
--- a/src/components/Image/Image.tsx
+++ b/src/components/Image/Image.tsx
@@ -16,10 +16,35 @@ export interface ImageProps extends Partial, Partial {
return src.endsWith('.webp') ? src : src + '.webp';
};
+const DeviceSpecificFragment = ({
+ disableWebp,
+ src,
+ breakpoint,
+ qa,
+}: DeviceSpecificFragmentProps) => (
+
+ {!disableWebp && (
+
+ )}
+
+
+);
+
const Image = (props: ImageProps) => {
const projectSettings = useContext(ProjectSettingsContext);
const {
@@ -61,38 +86,20 @@ const Image = (props: ImageProps) => {
return (
{mobile && (
-
- {!disableWebp && (
-
- )}
-
-
+
)}
{tablet && (
-
- {!disableWebp && (
-
- )}
-
-
+
)}
{src && !disableWebp && (
{
+ test('Render Image by default', async () => {
+ render();
+
+ const component = screen.getByTestId(qaId);
+ expect(component).toBeInTheDocument();
+ expect(component).toBeVisible();
+ });
+
+ test('add image as src prop', () => {
+ testSourceProps({
+ component: Image,
+ props: {src: imageSrc, qa: qaId},
+ });
+ });
+
+ test('add image as desktop prop', () => {
+ testSourceProps({
+ component: Image,
+ props: {desktop: imageSrc, qa: qaId},
+ });
+ });
+
+ test('add image as tablet prop', () => {
+ testSourceProps({
+ component: Image,
+ props: {desktop: imageSrc, tablet: imageSrc, qa: qaId},
+ });
+ });
+
+ test('add image as mobile prop', () => {
+ testSourceProps({
+ component: Image,
+ props: {desktop: imageSrc, mobile: imageSrc, qa: qaId},
+ });
+ });
+
+ test('add image as src prop with disabledCompress', () => {
+ testSourceProps({
+ component: Image,
+ props: {src: imageSrc, qa: qaId, disableCompress: true},
+ });
+ });
+
+ test('add image as desktop prop with disabledCompress', () => {
+ testSourceProps({
+ component: Image,
+ props: {desktop: imageSrc, qa: qaId, disableCompress: true},
+ });
+ });
+
+ test('add image as tablet prop with disabledCompress', () => {
+ testSourceProps({
+ component: Image,
+ props: {desktop: imageSrc, tablet: imageSrc, qa: qaId, disableCompress: true},
+ });
+ });
+
+ test('add image as mobile prop with disabledCompress', () => {
+ testSourceProps({
+ component: Image,
+ props: {desktop: imageSrc, mobile: imageSrc, qa: qaId, disableCompress: true},
+ });
+ });
+
+ test('add className', () => {
+ testCustomClassName({
+ component: Image,
+ props: {src: imageSrc, qa: qaId},
+ options: {customClassNameProp: 'containerClassName'},
+ });
+ });
+
+ test('add className to image', () => {
+ const className = 'custom-class-name';
+
+ render();
+
+ const component = screen.getByRole('img');
+ expect(component).toHaveClass(className);
+ });
+
+ test('add style', () => {
+ testCustomStyle({
+ component: Image,
+ props: {src: imageSrc, qa: qaId},
+ options: {role: 'img'},
+ });
+ });
+
+ test('render default "alt"', () => {
+ render();
+
+ const component = screen.getByRole('img');
+ expect(component).toHaveAttribute('alt', i18n('img-alt'));
+ });
+
+ test('render custom "alt"', () => {
+ const alt = 'defined-alt';
+ render();
+
+ const component = screen.getByRole('img');
+ expect(component).toHaveAttribute('alt', alt);
+ });
+
+ test('call onClick', async () => {
+ testOnClick({
+ component: Image,
+ props: {src: imageSrc, qa: qaId},
+ options: {role: 'img'},
+ });
+ });
+});
diff --git a/test-utils/shared/common.tsx b/test-utils/shared/common.tsx
index 0d5028851..45b07ae07 100644
--- a/test-utils/shared/common.tsx
+++ b/test-utils/shared/common.tsx
@@ -8,7 +8,23 @@ import {ERROR_INPUT_DATA_MESSAGE} from '../constants';
type CommonTestArgs = {
component: ElementType;
props: T & QAProps;
- options?: {qaId?: string};
+ options?: {qaId?: string; customClassNameProp?: string; role?: string};
+};
+
+const validateInputProps = (props: CommonTestArgs['props']) => {
+ if (!props.qa) {
+ throw new Error(ERROR_INPUT_DATA_MESSAGE);
+ }
+};
+
+const getComponent = ({props, options}: Omit, '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 = ({
@@ -16,25 +32,25 @@ export const testCustomClassName = ({
props,
options,
}: CommonTestArgs) => {
- if (!props.qa) {
- throw new Error(ERROR_INPUT_DATA_MESSAGE);
- }
+ validateInputProps(props);
const className = 'custom-class-name';
- render();
- const anchor = screen.getByTestId(options?.qaId || props.qa);
- expect(anchor).toHaveClass(className);
+ const classNameProps = {
+ [options?.customClassNameProp || 'className']: className,
+ };
+ render();
+ const component = getComponent({props, options});
+
+ expect(component).toHaveClass(className);
};
-export const testCustomStyle = ({component: Component, props}: CommonTestArgs) => {
- if (!props.qa) {
- throw new Error(ERROR_INPUT_DATA_MESSAGE);
- }
+export const testCustomStyle = ({component: Component, props, options}: CommonTestArgs) => {
+ validateInputProps(props);
const style = {color: 'red'};
render();
- const component = screen.getByTestId(props.qa);
+ const component = getComponent({props, options});
expect(component).toHaveStyle(style);
};
@@ -44,14 +60,30 @@ export const testAnimated = async ({
props,
options,
}: CommonTestArgs) => {
- if (!options?.qaId) {
- throw new Error(ERROR_INPUT_DATA_MESSAGE);
- }
+ validateInputProps(props);
const user = userEvent.setup();
render();
- const component = screen.getByTestId(options?.qaId);
+ const component = getComponent({props, options});
+
await user.hover(component);
expect(component).toHaveClass('animate');
};
+
+export const testOnClick = async ({
+ component: Component,
+ props,
+ options,
+}: CommonTestArgs) => {
+ validateInputProps(props);
+
+ const user = userEvent.setup();
+ const handleOnClick = jest.fn();
+ render();
+
+ const component = getComponent({props, options});
+
+ await user.click(component);
+ expect(handleOnClick).toHaveBeenCalledTimes(1);
+};
diff --git a/test-utils/shared/image.tsx b/test-utils/shared/image.tsx
new file mode 100644
index 000000000..68074ba84
--- /dev/null
+++ b/test-utils/shared/image.tsx
@@ -0,0 +1,88 @@
+import {render, screen} from '@testing-library/react';
+import React, {ElementType} from 'react';
+
+import {getQaAttrubutes} from '../../src';
+import {QAProps} from '../../src/models';
+import {isCompressible} from '../../src/utils/imageCompress';
+import {ERROR_INPUT_DATA_MESSAGE} from '../constants';
+
+export const testSourceProps = ({
+ component: Component,
+ props,
+ options,
+}: {
+ component: ElementType;
+ props: T &
+ QAProps & {
+ src?: string;
+ tablet?: string;
+ desktop?: string;
+ mobile?: string;
+ disableCompress?: boolean;
+ };
+ options?: {
+ qaId?: string;
+ };
+}) => {
+ const src = props.src || props.desktop;
+ if (!src) {
+ throw new Error(ERROR_INPUT_DATA_MESSAGE);
+ }
+ const qaId = options?.qaId;
+
+ const qaAttributes = getQaAttrubutes(
+ props.qa,
+ 'mobile-source-compressed',
+ 'mobile-source',
+ 'tablet-source-compressed',
+ 'tablet-source',
+ 'display-source',
+ );
+
+ const disableWebp = src && (props.disableCompress || !isCompressible(src));
+
+ render();
+
+ const component = screen.queryByRole('img');
+ expect(component).toHaveAttribute('src', src);
+
+ if (disableWebp) {
+ const sourceWebP = screen.queryByTestId(qaId || qaAttributes.displaySource);
+ expect(sourceWebP).not.toBeInTheDocument();
+ } else {
+ const sourceWebP = screen.getByTestId(qaId || qaAttributes.displaySource);
+ expect(sourceWebP).toHaveAttribute('srcset', src + '.webp');
+ }
+
+ if (props.tablet) {
+ if (disableWebp) {
+ const source = screen.getAllByTestId(qaId || qaAttributes.tabletSource);
+ const sourceWebP = screen.queryByTestId(qaId || qaAttributes.tabletSourceCompressed);
+
+ expect(source[0]).toHaveAttribute('srcset', props.tablet);
+ expect(sourceWebP).not.toBeInTheDocument();
+ } else {
+ const source = screen.getAllByTestId(qaId || qaAttributes.tabletSource);
+ const sourceWebP = screen.getByTestId(qaId || qaAttributes.tabletSourceCompressed);
+
+ expect(source[0]).toHaveAttribute('srcset', props.tablet);
+ expect(sourceWebP).toHaveAttribute('srcset', props.tablet + '.webp');
+ }
+ }
+
+ if (props.mobile) {
+ if (disableWebp) {
+ const source = screen.getAllByTestId(qaId || qaAttributes.mobileSource);
+ const sourceWebP = screen.queryByTestId(qaId || qaAttributes.mobileSourceCompressed);
+
+ expect(source[0]).toHaveAttribute('srcset', props.mobile);
+ expect(sourceWebP).not.toBeInTheDocument();
+ } else {
+ const source = screen.getAllByTestId(qaId || qaAttributes.mobileSource);
+ const sourceWebP = screen.getByTestId(qaId || qaAttributes.mobileSourceCompressed);
+
+ expect(source[0]).toHaveAttribute('srcset', props.mobile);
+ expect(sourceWebP).toHaveAttribute('srcset', props.mobile + '.webp');
+ }
+ }
+};