From 57948421dbe06ce5b3bfc1447dcfdc5fccf1380e Mon Sep 17 00:00:00 2001 From: Nik Tverd Date: Fri, 3 Nov 2023 17:36:59 +0600 Subject: [PATCH 1/2] test(MetaBlock): test for MetaBlock added --- .mocks/post.json | 1 + src/blocks/Meta/Meta.tsx | 9 +- src/blocks/Meta/__tests__/Meta.test.tsx | 130 ++++++++++++++++++ src/components/PostInfo/PostInfo.tsx | 8 +- src/components/PostInfo/components/Date.tsx | 8 +- .../PostInfo/components/ReadingTime.tsx | 7 +- src/components/PostInfo/components/Save.tsx | 2 +- src/contexts/PostPageContext.ts | 12 +- src/models/blocks.ts | 2 +- 9 files changed, 158 insertions(+), 21 deletions(-) create mode 100644 src/blocks/Meta/__tests__/Meta.test.tsx diff --git a/.mocks/post.json b/.mocks/post.json index ed46eafd..b21f040e 100644 --- a/.mocks/post.json +++ b/.mocks/post.json @@ -93,6 +93,7 @@ "updatedAt": "2022-07-29T11:12:19.605Z" } ], + "shareOptions": ["Telegram"], "textTitle": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", "htmlTitle": "strong>Lorem ipsum dolor sit amet consectetur adipiscing elit" } diff --git a/src/blocks/Meta/Meta.tsx b/src/blocks/Meta/Meta.tsx index f753c8cf..cac26ad0 100644 --- a/src/blocks/Meta/Meta.tsx +++ b/src/blocks/Meta/Meta.tsx @@ -10,7 +10,7 @@ import {PostPageContext} from '../../contexts/PostPageContext'; import {MetaProps} from '../../models/blocks'; import {PaddingsDirections} from '../../models/paddings'; import {block} from '../../utils/cn'; -import {getBreadcrumbs} from '../../utils/common'; +import {getBreadcrumbs, getQaAttributes} from '../../utils/common'; import './Meta.scss'; @@ -32,9 +32,10 @@ const breadcrumbsGoals = [ ]; export const Meta = (props: MetaProps) => { - const {paddingTop = 'l', paddingBottom = 'l', theme = 'light'} = props; + const {paddingTop = 'l', paddingBottom = 'l', theme = 'light', qa} = props; const {post} = useContext(PostPageContext); const {locale} = useContext(LocaleContext); + const qaAttributes = getQaAttributes(qa, 'post-info'); const {title, id, date, readingTime, tags} = post; @@ -48,7 +49,7 @@ export const Meta = (props: MetaProps) => { [PaddingsDirections.top]: paddingTop, [PaddingsDirections.bottom]: paddingBottom, }} - qa="blog-meta-content" + qa={qaAttributes.wrapper} > {breadcrumbs && ( { date={date} readingTime={readingTime} metrikaGoals={metrikaGoals} - qa="blog-meta-block" + qa={qaAttributes.postInfo} /> )} diff --git a/src/blocks/Meta/__tests__/Meta.test.tsx b/src/blocks/Meta/__tests__/Meta.test.tsx new file mode 100644 index 00000000..32069059 --- /dev/null +++ b/src/blocks/Meta/__tests__/Meta.test.tsx @@ -0,0 +1,130 @@ +import React from 'react'; + +import {render, screen} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import {PADDING_SIZES} from '../../../../test-utils/constants'; +import {testPaddingBottom, testPaddingTop} from '../../../../test-utils/shared/common'; +import {MetaProps} from '../../../models/blocks'; +import {PaddingSize} from '../../../models/paddings'; +import {getQaAttributes} from '../../../utils/common'; +import {Meta} from '../Meta'; +import {LikesRoutineType, PostPageContext} from '../../../contexts/PostPageContext'; +import post from '../../../../.mocks/post.json'; +import {PostData} from '../../../models/common'; +import {LocaleContext} from '../../../contexts/LocaleContext'; +import {Lang} from '../../../models/locale'; +import {format} from '../../../utils/date'; +import {Keyset, i18} from '../../../i18n'; + +const locale = { + code: 'en-En', + lang: Lang.En, + langName: 'English', + pathPrefix: 'en', +}; + +const metaProps = { + locale: 'en', + qa: 'meta-block', +}; + +const qaAttributes = getQaAttributes(metaProps.qa, 'post-info'); +const likes: LikesRoutineType = { + handleUserLike: jest.fn(), + likesCount: 1, + hasUserLike: true, +}; + +const RenderComponent = (props: MetaProps) => { + return ( + + + + + + ); +}; + +describe('Meta', () => { + test('render meta by default', async () => { + render(); + const meta = screen.getByText(post.title); + expect(meta).toHaveClass('yfm_blog_breadcrumbs'); + }); + + test('render with breadcrumbs', async () => { + render(); + const blogBreadcrumb = screen.getByText('Blog'); + const tagBreadcrumb = screen.getByText('Slug'); + const titleBreadcrumb = screen.getByText(post.title); + + expect(blogBreadcrumb).toHaveClass('pc-header-breadcrumbs__text'); + expect(tagBreadcrumb).toHaveClass('pc-header-breadcrumbs__text'); + expect(titleBreadcrumb).toHaveClass('yfm_blog_breadcrumbs'); + }); + + test('render with date', async () => { + const qaAttr = getQaAttributes(qaAttributes.postInfo, 'date'); + + render(); + const blogBreadcrumb = screen.getByTestId(qaAttr.date); + + expect(blogBreadcrumb).toHaveTextContent(format(post.date, 'longDate', metaProps.locale)); + }); + + test('render with reading time', async () => { + const qaAttr = getQaAttributes(qaAttributes.postInfo, 'reading-time'); + + render(); + const blogBreadcrumb = screen.getByTestId(qaAttr.readingTime); + + expect(blogBreadcrumb).toHaveTextContent( + i18(Keyset.ContextReadingTime, {count: post.readingTime}), + ); + }); + + test('render with share menu', async () => { + render(); + const user = userEvent.setup(); + const shareComponent = screen.getByText('Share'); + await user.click(shareComponent); + + const shareOption = screen.getByText('Copy link'); + + expect(shareOption).toBeVisible(); + }); + + test('render with likes', async () => { + const qaAttr = getQaAttributes(qaAttributes.postInfo, 'save'); + + render(); + + const component = screen.getByTestId(qaAttr.save); + + expect(component).toHaveTextContent(likes.likesCount.toString()); + }); + + test.each(new Array(...PADDING_SIZES))( + 'render with given "%s" paddingTop size', + (size: PaddingSize) => { + testPaddingTop({ + component: RenderComponent, + props: {...metaProps, paddingTop: size}, + options: {qaId: qaAttributes.wrapper}, + }); + }, + ); + + test.each(new Array(...PADDING_SIZES))( + 'render with given "%s" paddingBottom size', + (size: PaddingSize) => { + testPaddingBottom({ + component: RenderComponent, + props: {...metaProps, paddingBottom: size}, + options: {qaId: qaAttributes.wrapper}, + }); + }, + ); +}); diff --git a/src/components/PostInfo/PostInfo.tsx b/src/components/PostInfo/PostInfo.tsx index 05bc0090..0f706da7 100644 --- a/src/components/PostInfo/PostInfo.tsx +++ b/src/components/PostInfo/PostInfo.tsx @@ -8,6 +8,7 @@ import {Date} from './components/Date'; import {ReadingTime} from './components/ReadingTime'; import {Save} from './components/Save'; import {Sharing} from './components/Sharing'; +import {getQaAttributes} from '../../utils/common'; import './PostInfo.scss'; @@ -50,11 +51,12 @@ export const PostInfo = ({ qa, }: PostInfoProps) => { const {likes} = useContext(PostPageContext); + const qaAttributes = getQaAttributes(qa, 'date', 'reading-time', 'save'); return (
- {date && } - {readingTime && } + {date && } + {readingTime && } {likes && ( )}
diff --git a/src/components/PostInfo/components/Date.tsx b/src/components/PostInfo/components/Date.tsx index a46a9af8..6afbffef 100644 --- a/src/components/PostInfo/components/Date.tsx +++ b/src/components/PostInfo/components/Date.tsx @@ -1,7 +1,7 @@ import React, {useContext} from 'react'; import {LocaleContext} from '../../../contexts/LocaleContext'; -import {PostCardSize} from '../../../models/common'; +import {PostCardSize, QAProps} from '../../../models/common'; import {block} from '../../../utils/cn'; import {format} from '../../../utils/date'; @@ -9,17 +9,17 @@ import '../PostInfo.scss'; const b = block('post-info'); -type DateProps = { +type DateProps = QAProps & { date: string | number; size?: PostCardSize; id?: string; }; -export const Date = ({date, size = PostCardSize.SMALL, id}: DateProps) => { +export const Date = ({date, size = PostCardSize.SMALL, id, qa}: DateProps) => { const {locale} = useContext(LocaleContext); return ( -
+
{format(date, 'longDate', locale?.code)}
); diff --git a/src/components/PostInfo/components/ReadingTime.tsx b/src/components/PostInfo/components/ReadingTime.tsx index bd36288a..71a2ceb4 100644 --- a/src/components/PostInfo/components/ReadingTime.tsx +++ b/src/components/PostInfo/components/ReadingTime.tsx @@ -6,20 +6,21 @@ import {Keyset, i18} from '../../../i18n'; import {Time} from '../../../icons/Time'; import {block} from '../../../utils/cn'; +import {QAProps} from '../../../models/common'; import '../PostInfo.scss'; const b = block('post-info'); const ICON_SIZE = 16; -type ReadingTimeProps = { +type ReadingTimeProps = QAProps & { readingTime: number; size?: 's' | 'm'; id?: string; }; -export const ReadingTime = ({readingTime, size = 's', id}: ReadingTimeProps) => ( -
+export const ReadingTime = ({readingTime, size = 's', id, qa}: ReadingTimeProps) => ( +
diff --git a/src/components/PostInfo/components/Save.tsx b/src/components/PostInfo/components/Save.tsx index 9b8a5e8b..e2ed4be7 100644 --- a/src/components/PostInfo/components/Save.tsx +++ b/src/components/PostInfo/components/Save.tsx @@ -81,7 +81,7 @@ export const Save = ({ metrika.reachGoal(MetrikaCounter.CrossSite, metrikaGoal); handleAnalytics(); }} - data-qa={`${qa ? qa + '-' : ''}save`} + data-qa={qa} >
diff --git a/src/contexts/PostPageContext.ts b/src/contexts/PostPageContext.ts index 573e49ed..1f86d1f4 100644 --- a/src/contexts/PostPageContext.ts +++ b/src/contexts/PostPageContext.ts @@ -4,14 +4,16 @@ import {ShareOptions} from '@gravity-ui/components'; import {PostData} from '../models/common'; +export type LikesRoutineType = { + handleUserLike: () => void; + hasUserLike: boolean; + likesCount: number; +}; + export interface PostPageContextProps { post: PostData; suggestedPosts: PostData[]; - likes?: { - handleUserLike: () => void; - hasUserLike: boolean; - likesCount: number; - }; + likes?: LikesRoutineType; shareOptions?: ShareOptions[]; } diff --git a/src/models/blocks.ts b/src/models/blocks.ts index 2f1c28d6..f1d34283 100644 --- a/src/models/blocks.ts +++ b/src/models/blocks.ts @@ -51,7 +51,7 @@ export type MediaProps = ClassNameProps & text?: string; }; -export type MetaProps = { +export type MetaProps = QAProps & { locale: string; theme?: TextTheme; } & PaddingsYFMProps; From 18e916f02088fc9d5156668e623bec4bf0f71cba Mon Sep 17 00:00:00 2001 From: Nik Tverd Date: Thu, 9 Nov 2023 08:50:04 +0100 Subject: [PATCH 2/2] fixup! test(MetaBlock): test for MetaBlock added --- src/blocks/Meta/__tests__/Meta.test.tsx | 27 ++++++++----------------- test-utils/constants.ts | 12 +++++++++++ test-utils/shared/common.tsx | 13 +++++++++++- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/blocks/Meta/__tests__/Meta.test.tsx b/src/blocks/Meta/__tests__/Meta.test.tsx index 32069059..e50a18b5 100644 --- a/src/blocks/Meta/__tests__/Meta.test.tsx +++ b/src/blocks/Meta/__tests__/Meta.test.tsx @@ -2,8 +2,8 @@ import React from 'react'; import {render, screen} from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import {PADDING_SIZES} from '../../../../test-utils/constants'; -import {testPaddingBottom, testPaddingTop} from '../../../../test-utils/shared/common'; +import {PADDING_SIZES_BY_PADDING_TYPE} from '../../../../test-utils/constants'; +import {testPadding} from '../../../../test-utils/shared/common'; import {MetaProps} from '../../../models/blocks'; import {PaddingSize} from '../../../models/paddings'; import {getQaAttributes} from '../../../utils/common'; @@ -106,24 +106,13 @@ describe('Meta', () => { expect(component).toHaveTextContent(likes.likesCount.toString()); }); - test.each(new Array(...PADDING_SIZES))( - 'render with given "%s" paddingTop size', - (size: PaddingSize) => { - testPaddingTop({ + test.each(new Array>(...PADDING_SIZES_BY_PADDING_TYPE))( + 'render with given "%s" padding size', + ({optionKey, paddingSize}: Record) => { + testPadding({ component: RenderComponent, - props: {...metaProps, paddingTop: size}, - options: {qaId: qaAttributes.wrapper}, - }); - }, - ); - - test.each(new Array(...PADDING_SIZES))( - 'render with given "%s" paddingBottom size', - (size: PaddingSize) => { - testPaddingBottom({ - component: RenderComponent, - props: {...metaProps, paddingBottom: size}, - options: {qaId: qaAttributes.wrapper}, + props: {...metaProps, [optionKey]: paddingSize}, + options: {qaId: qaAttributes.wrapper, paddingKey: optionKey}, }); }, ); diff --git a/test-utils/constants.ts b/test-utils/constants.ts index f4846ef2..dbcd7ff9 100644 --- a/test-utils/constants.ts +++ b/test-utils/constants.ts @@ -1,5 +1,17 @@ import {PaddingSize} from '../src/models/paddings'; export const PADDING_SIZES: PaddingSize[] = ['xs', 's', 'm', 'l', 'xl']; +export const PADDING_TYPES: string[] = ['paddingTop', 'paddingBottom']; + +export const PADDING_SIZES_BY_PADDING_TYPE: Record[] = PADDING_TYPES.reduce( + (acc, optionKey) => { + const mappedPaddingSizes = PADDING_SIZES.map((paddingSize) => { + return {optionKey, paddingSize} as Record; + }); + + return [...acc, ...mappedPaddingSizes]; + }, + [] as Record[], +); export const ERROR_INPUT_DATA_MESSAGE = 'There are errors in input test data'; diff --git a/test-utils/shared/common.tsx b/test-utils/shared/common.tsx index 96383c00..7959fbcd 100644 --- a/test-utils/shared/common.tsx +++ b/test-utils/shared/common.tsx @@ -11,7 +11,7 @@ type CommonTestInputType = { paddingTop?: PaddingSize; paddingBottom?: PaddingSize; } & Required; - options?: {qaId?: string}; + options?: {qaId?: string; paddingKey?: string}; }; export const testCustomClassName = ({component: Component, props}: CommonTestInputType) => { @@ -51,3 +51,14 @@ export const testPaddingBottom = ({ expect(component).toHaveClass(`bc-wrapper_padding-bottom_${props.paddingBottom}`); }; + +export const testPadding = ({component: Component, props, options}: CommonTestInputType) => { + render(); + const component = screen.getByTestId(options?.qaId || props.qa); + + const classSuffix = options?.paddingKey === 'paddingTop' ? 'top' : 'bottom'; + const classEdning = + options?.paddingKey === 'paddingTop' ? props.paddingTop : props.paddingBottom; + + expect(component).toHaveClass(`bc-wrapper_padding-${classSuffix}_${classEdning}`); +};