diff --git a/cypress/e2e/specialFeatures/atiAnalytics/helpers/index.js b/cypress/e2e/specialFeatures/atiAnalytics/helpers/index.js index 310bb401f68..006836c36cd 100644 --- a/cypress/e2e/specialFeatures/atiAnalytics/helpers/index.js +++ b/cypress/e2e/specialFeatures/atiAnalytics/helpers/index.js @@ -26,7 +26,7 @@ const RECENT_AUDIO_EPISODES = 'episodes-audio'; const PODCAST_LINKS = 'third-party'; const LATEST_MEDIA = 'latest'; const RECOMMENDATIONS = 'midarticle-mostread'; -const SCROLLABLE_PROMO = 'edoj'; +const ARTICLE_LINKS_BLOCK = 'edoj'; const BILLBOARD = 'billboard'; const SOCIAL_EMBED = 'social-consent-banner'; const LIVE_MEDIA = 'live-header-media'; @@ -52,7 +52,7 @@ export const COMPONENTS = { RELATED_CONTENT, RELATED_TOPICS, SCROLLABLE_NAVIGATION, - SCROLLABLE_PROMO, + ARTICLE_LINKS_BLOCK, SHARE, SOCIAL_EMBED, TOP_STORIES, diff --git a/scripts/bundleSize/bundleSizeConfig.js b/scripts/bundleSize/bundleSizeConfig.js index f739f087d5d..309ec3f9d0b 100644 --- a/scripts/bundleSize/bundleSizeConfig.js +++ b/scripts/bundleSize/bundleSizeConfig.js @@ -9,5 +9,5 @@ export const VARIANCE = 5; -export const MIN_SIZE = 922; +export const MIN_SIZE = 921; export const MAX_SIZE = 1292; diff --git a/src/app/components/ArticleLinksBlock/Promo/index.styles.tsx b/src/app/components/ArticleLinksBlock/Promo/index.styles.tsx new file mode 100644 index 00000000000..5c77dfa05ce --- /dev/null +++ b/src/app/components/ArticleLinksBlock/Promo/index.styles.tsx @@ -0,0 +1,70 @@ +import { OPERA_MINI_CLASSNAME } from '#app/lib/utilities/addOperaMiniClassScript'; +import pixelsToRem from '#app/utilities/pixelsToRem'; +import { css, Theme } from '@emotion/react'; + +export default { + link: ({ fontSizes, fontVariants, isDarkUi, palette }: Theme) => + css({ + ...fontSizes.pica, + ...fontVariants.serifBold, + display: 'inline-block', + verticalAlign: 'middle', + textDecoration: 'none', + overflowX: 'hidden', + overflowY: 'hidden', + WebkitLineClamp: 4, + WebkitBoxOrient: 'vertical', + color: isDarkUi ? palette.GREY_10 : palette.GREY_8, + + '&:hover, &:focus': { + textDecoration: 'underline', + }, + + '&:visited': { + color: palette.GREY_6, + }, + + '&::before': { + bottom: 0, + content: '""', + left: 0, + overflow: 'hidden', + position: 'absolute', + right: 0, + top: 0, + zIndex: 1, + }, + }), + promoBox: ({ isDarkUi, mq, palette, spacings }: Theme) => + css({ + position: 'relative', + backgroundColor: isDarkUi ? palette.GREY_3 : palette.WHITE, + padding: `${spacings.DOUBLE}rem`, + paddingInlineEnd: `${pixelsToRem(38)}rem`, + height: 'auto', + display: 'block', + width: '100%', + [`.${OPERA_MINI_CLASSNAME} &`]: { + position: 'relative', + backgroundColor: isDarkUi ? palette.GREY_3 : palette.WHITE, + padding: `${spacings.DOUBLE}rem`, + marginBottom: `${spacings.DOUBLE}rem`, + width: `calc(100% - ${spacings.FULL}rem)`, + [mq.GROUP_2_MIN_WIDTH]: { + width: `calc(50% - ${spacings.DOUBLE}rem)`, + }, + }, + }), + timestamp: ({ isDarkUi, palette, spacings }: Theme) => + css({ + marginTop: `${spacings.FULL}rem`, + color: isDarkUi ? palette.GREY_6 : undefined, + }), + chevron: () => + css({ + position: 'absolute', + top: '50%', + transform: 'translateY(-50%)', + insetInlineEnd: `${pixelsToRem(12)}rem`, + }), +}; diff --git a/src/app/components/ArticleLinksBlock/Promo/index.test.tsx b/src/app/components/ArticleLinksBlock/Promo/index.test.tsx new file mode 100644 index 00000000000..c182248fd4f --- /dev/null +++ b/src/app/components/ArticleLinksBlock/Promo/index.test.tsx @@ -0,0 +1,45 @@ +import { render } from '../../react-testing-library-with-providers'; +import { PromoSingleBlock, oneLinkWithTimestamp } from '../helpers/fixtureData'; +import Promo from '.'; +import { ServiceContextProvider } from '../../../contexts/ServiceContext'; + +const ArticleLinksBlock = ({ block }) => ( + + + +); + +describe('Article Links Block', () => { + it('should render a link', () => { + const { queryByRole } = render( + , + ); + expect(queryByRole('link')).toBeInTheDocument(); + }); + + it('should extract and render the correct title', () => { + const { getByText } = render( + , + ); + expect( + getByText( + 'This is a very long headline. I am creating this for a test purpose. I love creating these type of tests. I really do not know what to write.', + ), + ).toBeTruthy(); + }); + + it('should extract and render the correct href', () => { + const { queryByRole } = render( + , + ); + const link = queryByRole('link') as HTMLAnchorElement; + expect(link?.href).toEqual('https://www.bbc.com/mundo'); + }); + + it('should render timestamp if timestamp is available', () => { + const { container } = render( + , + ); + expect(container.getElementsByTagName('time')[0]).toBeInTheDocument(); + }); +}); diff --git a/src/app/components/ArticleLinksBlock/Promo/index.tsx b/src/app/components/ArticleLinksBlock/Promo/index.tsx new file mode 100644 index 00000000000..9676918d455 --- /dev/null +++ b/src/app/components/ArticleLinksBlock/Promo/index.tsx @@ -0,0 +1,56 @@ +import { use } from 'react'; +import filterForBlockType from '#lib/utilities/blockHandlers'; +import PromoTimestamp from '#components/Promo/timestamp'; +import { OptimoBlock } from '#app/models/types/optimo'; +import useClickTrackerHandler from '#app/hooks/useClickTrackerHandler'; +import { Chevron, ChevronOrientation } from '#app/components/icons'; +import { ServiceContext } from '../../../contexts/ServiceContext'; +import styles from './index.styles'; + +interface PromoProps { + block: OptimoBlock; + clickTracker?: ReturnType; +} + +const Promo = ({ block, clickTracker }: PromoProps) => { + const { serviceDatetimeLocale, dir } = use(ServiceContext); + + const textBlock = filterForBlockType( + (block?.model as { blocks?: Record })?.blocks || {}, + 'text', + ); + const aresLinkBlock = filterForBlockType( + (block?.model as { blocks?: Record })?.blocks || {}, + 'aresLink', + ); + const timestamp = + aresLinkBlock?.model?.blocks?.[0]?.model?.timestamp ?? undefined; + + const href = + textBlock?.model?.blocks?.[0]?.model?.blocks?.[0]?.model?.locator ?? ''; + const title = + textBlock?.model?.blocks?.[0]?.model?.blocks?.[0]?.model?.text ?? ''; + + return ( +
+ + {title} + + + {timestamp && ( + + {timestamp} + + )} +
+ ); +}; + +export default Promo; diff --git a/src/app/components/ArticleLinksBlock/PromoList/index.styles.tsx b/src/app/components/ArticleLinksBlock/PromoList/index.styles.tsx new file mode 100644 index 00000000000..b8cb3cb9c83 --- /dev/null +++ b/src/app/components/ArticleLinksBlock/PromoList/index.styles.tsx @@ -0,0 +1,60 @@ +import { OPERA_MINI_CLASSNAME } from '#app/lib/utilities/addOperaMiniClassScript'; +import pixelsToRem from '#app/utilities/pixelsToRem'; +import { css, Theme } from '@emotion/react'; + +export default { + promo: ({ spacings }: Theme) => + css({ + '& ul': { + listStyle: 'none', + paddingInlineStart: '0', + margin: '0', + display: 'flex', + flexDirection: 'column', + gap: `${spacings.FULL}rem`, + width: '100%', + }, + [`.${OPERA_MINI_CLASSNAME} &`]: { + listStyle: 'none', + paddingInlineStart: '0', + margin: '0', + }, + }), + list: ({ mq, spacings }: Theme) => + css({ + display: 'flex', + flexShrink: 0, + marginInline: `${spacings.FULL}rem`, + ':last-of-type': { + marginBottom: `${spacings.TRIPLE}rem`, + }, + [mq.FORCED_COLOURS]: { + border: `solid ${pixelsToRem(3)}rem transparent`, + }, + + [mq.GROUP_2_MIN_WIDTH]: { + marginInline: `${spacings.DOUBLE}rem`, + }, + + [mq.GROUP_3_MIN_WIDTH]: { + marginInline: `${spacings.DOUBLE}rem`, + }, + + [mq.GROUP_4_MIN_WIDTH]: { + marginInline: 0, + }, + [`.${OPERA_MINI_CLASSNAME} &`]: { + [mq.GROUP_0_MAX_WIDTH]: { + marginInline: `${spacings.FULL}rem`, + }, + + [mq.GROUP_2_MIN_WIDTH]: { + marginInline: `${spacings.DOUBLE}rem`, + }, + + [mq.GROUP_4_MIN_WIDTH]: { + marginInline: 0, + }, + }, + }), +}; diff --git a/src/app/components/ArticleLinksBlock/PromoList/index.tsx b/src/app/components/ArticleLinksBlock/PromoList/index.tsx new file mode 100644 index 00000000000..391b45d644b --- /dev/null +++ b/src/app/components/ArticleLinksBlock/PromoList/index.tsx @@ -0,0 +1,35 @@ +import { OptimoBlock } from '#app/models/types/optimo'; +import { ViewTracker } from '#app/lib/analyticsUtils/types'; +import useClickTrackerHandler from '#app/hooks/useClickTrackerHandler'; +import Promo from '../Promo'; +import styles from './index.styles'; + +interface PromoListProps { + blocks: OptimoBlock[]; + viewTracker?: ViewTracker; + clickTracker?: ReturnType; +} + +const PromoList = ({ blocks, viewTracker, clickTracker }: PromoListProps) => { + const listBlocks = blocks.slice(0, 3); + + return ( +
+
    + {listBlocks.map((block, index) => { + return ( +
  • + +
  • + ); + })} +
+
+ ); +}; + +export default PromoList; diff --git a/src/app/components/ArticleLinksBlock/README.md b/src/app/components/ArticleLinksBlock/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/app/components/ArticleLinksBlock/__snapshots__/index.test.tsx.snap b/src/app/components/ArticleLinksBlock/__snapshots__/index.test.tsx.snap new file mode 100644 index 00000000000..8a55fd91be0 --- /dev/null +++ b/src/app/components/ArticleLinksBlock/__snapshots__/index.test.tsx.snap @@ -0,0 +1,1146 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Article Links Block Mid Page Article Links Block it should match a11y snapshot for list 1`] = ` +.emotion-0 { + position: relative; +} + +.emotion-2 { + font-family: ReithSans,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 700; + font-size: 0.875rem; + line-height: 1.125rem; + background-color: #FFFFFF; + border: 0.125rem solid #222222; + color: #222222; + display: block; + left: 0; + line-height: 1; + padding: 0.75rem; + position: absolute; + -webkit-text-decoration: none; + text-decoration: none; + top: 0; + z-index: 10; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-2 { + font-size: 0.875rem; + line-height: 1.125rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-2 { + font-size: 0.8125rem; + line-height: 1rem; + } +} + +.emotion-2:not(:focus):not(:active) { + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; + margin: 0; +} + +.emotion-4 { + font-size: 0.875rem; + line-height: 1.125rem; + font-family: ReithSans,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 400; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #F6F6F6; + width: 100%; + height: 2rem; + color: #3F3F42; + padding: 0 0.5rem; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-4 { + font-size: 0.875rem; + line-height: 1.125rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-4 { + font-size: 0.8125rem; + line-height: 1rem; + } +} + +@media screen and (forced-colors: active) { + .emotion-4 { + border: solid 0.1875rem transparent; + border-bottom: transparent; + } +} + +@media (max-width: 14.9375rem) { + .emotion-4 { + margin-inline: 0.5rem; + margin: 0; + } +} + +@media (min-width: 25rem) { + .emotion-4 { + margin-inline: 1rem; + padding: 0 1rem; + margin: 0 -0.2rem; + } +} + +.emotion-5 ul { + list-style: none; + -webkit-padding-start: 0; + padding-inline-start: 0; + margin: 0; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + gap: 0.5rem; + width: 100%; +} + +.is-opera-mini .emotion-5 { + list-style: none; + -webkit-padding-start: 0; + padding-inline-start: 0; + margin: 0; +} + +.emotion-6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + margin-inline: 0.5rem; +} + +.emotion-6:last-of-type { + margin-bottom: 1.5rem; +} + +@media screen and (forced-colors: active) { + .emotion-6 { + border: solid 0.1875rem transparent; + } +} + +@media (min-width: 25rem) { + .emotion-6 { + margin-inline: 1rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-6 { + margin-inline: 1rem; + } +} + +@media (min-width: 63rem) { + .emotion-6 { + margin-inline: 0; + } +} + +@media (max-width: 14.9375rem) { + .is-opera-mini .emotion-6 { + margin-inline: 0.5rem; + } +} + +@media (min-width: 25rem) { + .is-opera-mini .emotion-6 { + margin-inline: 1rem; + } +} + +@media (min-width: 63rem) { + .is-opera-mini .emotion-6 { + margin-inline: 0; + } +} + +.emotion-7 { + position: relative; + background-color: #FFFFFF; + padding: 1rem; + -webkit-padding-end: 2.375rem; + padding-inline-end: 2.375rem; + height: auto; + display: block; + width: 100%; +} + +.is-opera-mini .emotion-7 { + position: relative; + background-color: #FFFFFF; + padding: 1rem; + margin-bottom: 1rem; + width: calc(100% - 0.5rem); +} + +@media (min-width: 25rem) { + .is-opera-mini .emotion-7 { + width: calc(50% - 1rem); + } +} + +.emotion-8 { + font-size: 0.9375rem; + line-height: 1.25rem; + font-family: ReithSerif,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 700; + display: inline-block; + vertical-align: middle; + -webkit-text-decoration: none; + text-decoration: none; + overflow-x: hidden; + overflow-y: hidden; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + color: #202224; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-8 { + font-size: 1rem; + line-height: 1.25rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-8 { + font-size: 1rem; + line-height: 1.25rem; + } +} + +.emotion-8:hover, +.emotion-8:focus { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +.emotion-8:visited { + color: #545658; +} + +.emotion-8::before { + bottom: 0; + content: ""; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.emotion-9 { + position: absolute; + top: 50%; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + inset-inline-end: 0.75rem; +} + +.emotion-18 { + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; + margin: 0; +} + +
+
+
+ + Skip content and continue reading + + + Show all links (no images) + + +

+ End of content +

+
+
+
+`; + +exports[`Article Links Block Mid Page Article Links Block it should match a11y snapshot for list with no title 1`] = ` +.emotion-0 { + position: relative; +} + +.emotion-2 { + font-family: ReithSans,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 700; + font-size: 0.875rem; + line-height: 1.125rem; + background-color: #FFFFFF; + border: 0.125rem solid #222222; + color: #222222; + display: block; + left: 0; + line-height: 1; + padding: 0.75rem; + position: absolute; + -webkit-text-decoration: none; + text-decoration: none; + top: 0; + z-index: 10; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-2 { + font-size: 0.875rem; + line-height: 1.125rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-2 { + font-size: 0.8125rem; + line-height: 1rem; + } +} + +.emotion-2:not(:focus):not(:active) { + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; + margin: 0; +} + +.emotion-4 { + background: #F6F6F6; + padding: 0 0.5rem 1rem; + margin: 0; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + overflow-x: auto; + width: 100%; +} + +@media (min-width: 25rem) { + .emotion-4 { + padding: 0 1rem 1rem; + margin: 0 -0.2rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-4 { + padding: 0 1rem 1rem; + } +} + +.emotion-5 { + position: relative; + background-color: #FFFFFF; + padding: 1rem; + -webkit-padding-end: 2.375rem; + padding-inline-end: 2.375rem; + height: auto; + display: block; + width: 100%; +} + +.is-opera-mini .emotion-5 { + position: relative; + background-color: #FFFFFF; + padding: 1rem; + margin-bottom: 1rem; + width: calc(100% - 0.5rem); +} + +@media (min-width: 25rem) { + .is-opera-mini .emotion-5 { + width: calc(50% - 1rem); + } +} + +.emotion-6 { + font-size: 0.9375rem; + line-height: 1.25rem; + font-family: ReithSerif,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 700; + display: inline-block; + vertical-align: middle; + -webkit-text-decoration: none; + text-decoration: none; + overflow-x: hidden; + overflow-y: hidden; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + color: #202224; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-6 { + font-size: 1rem; + line-height: 1.25rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-6 { + font-size: 1rem; + line-height: 1.25rem; + } +} + +.emotion-6:hover, +.emotion-6:focus { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +.emotion-6:visited { + color: #545658; +} + +.emotion-6::before { + bottom: 0; + content: ""; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.emotion-7 { + position: absolute; + top: 50%; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + inset-inline-end: 0.75rem; +} + +.emotion-8 { + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; + margin: 0; +} + + +`; + +exports[`Article Links Block Mid Page Article Links Block it should match a11y snapshot for single card 1`] = ` +.emotion-0 { + position: relative; +} + +.emotion-2 { + font-family: ReithSans,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 700; + font-size: 0.875rem; + line-height: 1.125rem; + background-color: #FFFFFF; + border: 0.125rem solid #222222; + color: #222222; + display: block; + left: 0; + line-height: 1; + padding: 0.75rem; + position: absolute; + -webkit-text-decoration: none; + text-decoration: none; + top: 0; + z-index: 10; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-2 { + font-size: 0.875rem; + line-height: 1.125rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-2 { + font-size: 0.8125rem; + line-height: 1rem; + } +} + +.emotion-2:not(:focus):not(:active) { + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; + margin: 0; +} + +.emotion-4 { + font-size: 0.875rem; + line-height: 1.125rem; + font-family: ReithSans,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 400; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #F6F6F6; + width: 100%; + height: 2rem; + color: #3F3F42; + padding: 0 0.5rem; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-4 { + font-size: 0.875rem; + line-height: 1.125rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-4 { + font-size: 0.8125rem; + line-height: 1rem; + } +} + +@media screen and (forced-colors: active) { + .emotion-4 { + border: solid 0.1875rem transparent; + border-bottom: transparent; + } +} + +@media (max-width: 14.9375rem) { + .emotion-4 { + margin-inline: 0.5rem; + margin: 0; + } +} + +@media (min-width: 25rem) { + .emotion-4 { + margin-inline: 1rem; + padding: 0 1rem; + margin: 0 -0.2rem; + } +} + +.emotion-5 { + background: #F6F6F6; + padding: 0 0.5rem 1rem; + margin: 0; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + overflow-x: auto; + width: 100%; +} + +@media (min-width: 25rem) { + .emotion-5 { + padding: 0 1rem 1rem; + margin: 0 -0.2rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-5 { + padding: 0 1rem 1rem; + } +} + +.emotion-6 { + position: relative; + background-color: #FFFFFF; + padding: 1rem; + -webkit-padding-end: 2.375rem; + padding-inline-end: 2.375rem; + height: auto; + display: block; + width: 100%; +} + +.is-opera-mini .emotion-6 { + position: relative; + background-color: #FFFFFF; + padding: 1rem; + margin-bottom: 1rem; + width: calc(100% - 0.5rem); +} + +@media (min-width: 25rem) { + .is-opera-mini .emotion-6 { + width: calc(50% - 1rem); + } +} + +.emotion-7 { + font-size: 0.9375rem; + line-height: 1.25rem; + font-family: ReithSerif,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 700; + display: inline-block; + vertical-align: middle; + -webkit-text-decoration: none; + text-decoration: none; + overflow-x: hidden; + overflow-y: hidden; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + color: #202224; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-7 { + font-size: 1rem; + line-height: 1.25rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-7 { + font-size: 1rem; + line-height: 1.25rem; + } +} + +.emotion-7:hover, +.emotion-7:focus { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +.emotion-7:visited { + color: #545658; +} + +.emotion-7::before { + bottom: 0; + content: ""; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.emotion-8 { + position: absolute; + top: 50%; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + inset-inline-end: 0.75rem; +} + +.emotion-9 { + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; + margin: 0; +} + +
+
+
+ + Skip content and continue reading + + + Single link + + +

+ End of content +

+
+
+
+`; + +exports[`Article Links Block Mid Page Article Links Block it should match snapshot when in dark ui mode 1`] = ` +.emotion-0 { + position: relative; +} + +.emotion-2 { + font-family: ReithSans,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 700; + font-size: 0.875rem; + line-height: 1.125rem; + background-color: #FFFFFF; + border: 0.125rem solid #222222; + color: #222222; + display: block; + left: 0; + line-height: 1; + padding: 0.75rem; + position: absolute; + -webkit-text-decoration: none; + text-decoration: none; + top: 0; + z-index: 10; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-2 { + font-size: 0.875rem; + line-height: 1.125rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-2 { + font-size: 0.8125rem; + line-height: 1rem; + } +} + +.emotion-2:not(:focus):not(:active) { + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; + margin: 0; +} + +.emotion-4 { + background: #F6F6F6; + padding: 0 0.5rem 1rem; + margin: 0; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + overflow-x: auto; + width: 100%; +} + +@media (min-width: 25rem) { + .emotion-4 { + padding: 0 1rem 1rem; + margin: 0 -0.2rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-4 { + padding: 0 1rem 1rem; + } +} + +.emotion-5 { + position: relative; + background-color: #E6E8EA; + padding: 1rem; + -webkit-padding-end: 2.375rem; + padding-inline-end: 2.375rem; + height: auto; + display: block; + width: 100%; +} + +.is-opera-mini .emotion-5 { + position: relative; + background-color: #E6E8EA; + padding: 1rem; + margin-bottom: 1rem; + width: calc(100% - 0.5rem); +} + +@media (min-width: 25rem) { + .is-opera-mini .emotion-5 { + width: calc(50% - 1rem); + } +} + +.emotion-6 { + font-size: 0.9375rem; + line-height: 1.25rem; + font-family: ReithSerif,Helvetica,Arial,sans-serif; + font-style: normal; + font-weight: 700; + display: inline-block; + vertical-align: middle; + -webkit-text-decoration: none; + text-decoration: none; + overflow-x: hidden; + overflow-y: hidden; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + color: #141414; +} + +@media (min-width: 20rem) and (max-width: 37.4375rem) { + .emotion-6 { + font-size: 1rem; + line-height: 1.25rem; + } +} + +@media (min-width: 37.5rem) { + .emotion-6 { + font-size: 1rem; + line-height: 1.25rem; + } +} + +.emotion-6:hover, +.emotion-6:focus { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +.emotion-6:visited { + color: #545658; +} + +.emotion-6::before { + bottom: 0; + content: ""; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.emotion-7 { + position: absolute; + top: 50%; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + inset-inline-end: 0.75rem; +} + +.emotion-8 { + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; + margin: 0; +} + + +`; diff --git a/src/app/legacy/components/ScrollablePromo/fixtures.js b/src/app/components/ArticleLinksBlock/fixtures.ts similarity index 100% rename from src/app/legacy/components/ScrollablePromo/fixtures.js rename to src/app/components/ArticleLinksBlock/fixtures.ts diff --git a/src/app/legacy/components/ScrollablePromo/helpers/fixtureData.js b/src/app/components/ArticleLinksBlock/helpers/fixtureData.ts similarity index 100% rename from src/app/legacy/components/ScrollablePromo/helpers/fixtureData.js rename to src/app/components/ArticleLinksBlock/helpers/fixtureData.ts diff --git a/src/app/components/ArticleLinksBlock/index.stories.tsx b/src/app/components/ArticleLinksBlock/index.stories.tsx new file mode 100644 index 00000000000..ca2c893654c --- /dev/null +++ b/src/app/components/ArticleLinksBlock/index.stories.tsx @@ -0,0 +1,68 @@ +import ArticleLinksBlock from '.'; +import { + threeLinks, + oneLinkOnly, + oneLinkWithNoTitle, + oneLinkWithTimestamp, + moreThanThreeLinks, + twoLinksWithNoImages, + truncatedTextInSingleLink, + arabicText, +} from './helpers/fixtureData'; +import metadata from './metadata.json'; +import readme from './README.md'; +import { OptimoBlock } from '#app/models/types/optimo'; +import { Direction } from '#app/models/types/global'; +import { GREY_2 } from '../ThemeProvider/palette'; + +interface Props { + blocks: OptimoBlock[]; + dir?: Direction; +} + +const Component = ({ blocks, dir = 'ltr' }: Props) => ( +
+ +
+); + +export default { + title: 'Components/Article Links Block', + Component, + parameters: { + docs: { readme }, + metadata, + }, +}; + +export const ThreeLinks = () => ; + +export const OnlyOneLink = () => ; + +export const OneLinkWithNoTitle = () => ( + +); + +export const MoreThanThreeLinks = () => ( + +); + +export const NoImagesInData = () => ; + +export const TruncatedTextInSingleLink = () => ( + +); + +export const ArabicText = () => ; + +ArabicText.globals = { + service: { service: 'arabic' }, +}; + +export const WithTimestamp = () => ; diff --git a/src/app/components/ArticleLinksBlock/index.styles.tsx b/src/app/components/ArticleLinksBlock/index.styles.tsx new file mode 100644 index 00000000000..14633b0236f --- /dev/null +++ b/src/app/components/ArticleLinksBlock/index.styles.tsx @@ -0,0 +1,54 @@ +import pixelsToRem from '#app/utilities/pixelsToRem'; +import { css, Theme } from '@emotion/react'; + +export default { + promoContainer: ({ palette, mq, spacings }: Theme) => + css({ + background: palette.GREY_2, + padding: `0 ${spacings.FULL}rem ${spacings.DOUBLE}rem`, + margin: 0, + display: 'flex', + overflowX: 'auto', + width: '100%', + [mq.GROUP_2_MIN_WIDTH]: { + padding: `0 ${spacings.DOUBLE}rem ${spacings.DOUBLE}rem`, + margin: '0 -0.2rem', + }, + [mq.GROUP_3_MIN_WIDTH]: { + padding: `0 ${spacings.DOUBLE}rem ${spacings.DOUBLE}rem`, + }, + }), + labelComponent: ({ + isDarkUi, + fontSizes, + fontVariants, + mq, + palette, + spacings, + }: Theme) => + css({ + ...fontSizes.brevier, + ...fontVariants.sansRegular, + display: 'flex', + alignItems: 'center', + backgroundColor: palette.GREY_2, + width: '100%', + height: `${spacings.QUADRUPLE}rem`, + color: isDarkUi ? palette.GREY_2 : palette.SHADOW, + padding: `0 ${spacings.FULL}rem`, + [mq.FORCED_COLOURS]: { + border: `solid ${pixelsToRem(3)}rem transparent`, + borderBottom: 'transparent', + }, + + [mq.GROUP_0_MAX_WIDTH]: { + marginInline: `${spacings.FULL}rem`, + margin: 0, + }, + [mq.GROUP_2_MIN_WIDTH]: { + marginInline: `${spacings.DOUBLE}rem`, + padding: `0 ${spacings.DOUBLE}rem`, + margin: '0 -0.2rem', + }, + }), +}; diff --git a/src/app/components/ArticleLinksBlock/index.test.tsx b/src/app/components/ArticleLinksBlock/index.test.tsx new file mode 100644 index 00000000000..5688de0c8b4 --- /dev/null +++ b/src/app/components/ArticleLinksBlock/index.test.tsx @@ -0,0 +1,166 @@ +import * as viewTracking from '#hooks/useViewTracker'; +import * as clickTracking from '#hooks/useClickTrackerHandler'; +import { render } from '../react-testing-library-with-providers'; +import { + threeLinks, + oneLinkOnly, + oneLinkWithNoTitle, + moreThanThreeLinks, +} from './helpers/fixtureData'; +import ArticleLinksBlock from '.'; +import { edOjA, edOjB } from './fixtures'; +import { MEDIA_ARTICLE_PAGE } from '../../routes/utils/pageTypes'; + +describe('Article Links Block', () => { + describe('Mid Page Article Links Block', () => { + it('should return null if no data is passed', () => { + const { container } = render(); + expect(container).toBeEmptyDOMElement(); + }); + + it('should render max 3 promo items', () => { + const { getAllByRole } = render( + , + ); + expect(getAllByRole('listitem').length).toEqual(3); + }); + + it('should render single promo item', () => { + const { container } = render(); + expect(container.childElementCount).toEqual(1); + }); + + it('should render single promo item with a title', () => { + const { container, getByTestId } = render( + , + ); + expect(container.childElementCount).toEqual(1); + expect(getByTestId('eoj-recommendations-heading')).toBeInTheDocument(); + }); + + it('should render single promo item without a title', () => { + const { container, queryByTestId } = render( + , + ); + expect(container.childElementCount).toEqual(1); + expect( + queryByTestId('eoj-recommendations-heading'), + ).not.toBeInTheDocument(); + }); + + it('should not render a list when there is only one promo', () => { + const { queryByRole } = render( + , + ); + + expect(queryByRole('list')).not.toBeInTheDocument(); + expect(queryByRole('listitem')).not.toBeInTheDocument(); + }); + + it('should render unordered list if more than 1 item', () => { + const { queryByRole, getAllByRole } = render( + , + ); + expect(queryByRole('list')).toBeInTheDocument(); + expect(getAllByRole('listitem').length).toEqual(3); + }); + + describe('event tracking in editorial onward journeys', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should call the view tracking hook with the correct params with one editorial onward journey', () => { + const viewTrackerSpy = jest.spyOn(viewTracking, 'default'); + + render( + , + ); + + expect(viewTrackerSpy).toHaveBeenCalledWith({ + componentName: 'edoj1', + format: 'CHD=edoj', + }); + }); + + it('should call the view tracking hook with the correct params with multiple editorial onward journeys', () => { + const viewTrackerSpy = jest.spyOn(viewTracking, 'default'); + render( + , + ); + render( + , + ); + + expect(viewTrackerSpy).toHaveBeenCalledTimes(4); + expect(viewTrackerSpy).toHaveBeenCalledWith({ + componentName: 'edoj1', + format: 'CHD=edoj', + }); + expect(viewTrackerSpy).toHaveBeenCalledWith({ + componentName: 'edoj2', + format: 'CHD=edoj', + }); + }); + + it('should call the click tracking hook with one editorial onward journey', () => { + const clickTrackerSpy = jest.spyOn(clickTracking, 'default'); + render( + , + ); + + expect(clickTrackerSpy).toHaveBeenCalledWith({ + componentName: 'edoj1', + format: 'CHD=edoj', + }); + }); + + it('should call the click tracking hook with multiple editorial onward journeys', () => { + const clickTrackerSpy = jest.spyOn(clickTracking, 'default'); + render( + , + ); + render( + , + ); + + expect(clickTrackerSpy).toHaveBeenCalledTimes(4); + expect(clickTrackerSpy).toHaveBeenCalledWith({ + componentName: 'edoj1', + format: 'CHD=edoj', + }); + expect(clickTrackerSpy).toHaveBeenCalledWith({ + componentName: 'edoj2', + format: 'CHD=edoj', + }); + }); + }); + + it('it should match a11y snapshot for single card', () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('it should match a11y snapshot for list', () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('it should match a11y snapshot for list with no title', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); + + it('it should match snapshot when in dark ui mode', () => { + const { container } = render( + , + { + pageType: MEDIA_ARTICLE_PAGE, + }, + ); + expect(container).toMatchSnapshot(); + }); + }); +}); diff --git a/src/app/components/ArticleLinksBlock/index.tsx b/src/app/components/ArticleLinksBlock/index.tsx new file mode 100644 index 00000000000..99243a22d87 --- /dev/null +++ b/src/app/components/ArticleLinksBlock/index.tsx @@ -0,0 +1,102 @@ +import { use } from 'react'; +import useViewTracker from '#hooks/useViewTracker'; +import idSanitiser from '#lib/utilities/idSanitiser'; +import { OptimoBlock } from '#app/models/types/optimo'; +import useClickTrackerHandler from '#app/hooks/useClickTrackerHandler'; +import SkipLinkWrapper from '#app/legacy/components/SkipLinkWrapper'; +import { ServiceContext } from '../../contexts/ServiceContext'; +import Promo from './Promo'; +import PromoList from './PromoList'; +import styles from './index.styles'; + +interface ArticleLinksBlockProps { + blocks: OptimoBlock[]; + blockGroupIndex?: number | null; +} + +const ArticleLinksBlock = ({ + blocks, + blockGroupIndex = null, +}: ArticleLinksBlockProps) => { + const { translations, recommendations, service } = use(ServiceContext); + + const eventTrackingData = { + componentName: `edoj${blockGroupIndex}`, + format: 'CHD=edoj', + }; + + const viewTracker = useViewTracker(eventTrackingData); + const clickTracker = useClickTrackerHandler(eventTrackingData); + + if (!blocks || blocks.length === 0) return null; + + const title = + blocks[0]?.type === 'title' + ? // @ts-expect-error - deeply nested + (blocks[0]?.model?.blocks?.[0].model?.blocks?.[0]?.model?.text ?? + undefined) + : undefined; + + const blocksWithoutTitle = + blocks[0]?.type === 'title' ? blocks.slice(1) : blocks; + + const isSingleItem = blocksWithoutTitle.length === 1; + + const ariaLabel = title ? idSanitiser(title) : undefined; + + const a11yAttributes = { + role: 'region', + ...(ariaLabel + ? { 'aria-labelledby': ariaLabel } + : { + 'aria-label': translations?.relatedContent ?? 'Related Content', + }), + }; + + const { skipLink } = recommendations || {}; + + const { text, endTextVisuallyHidden } = skipLink || { + text: 'Skip content and continue reading', + endTextVisuallyHidden: 'End of content', + }; + + const terms = { '%title%': title || 'content' }; + + const endTextId = `end-of-article-links-block`; + + const skipLinkProps = { + endTextId, + terms, + text: text.replace('%title%', terms['%title%']), + endTextVisuallyHidden, + }; + + return ( +
+ + {typeof title === 'string' && title.length > 0 && ( + + {title} + + )} + {isSingleItem ? ( +
+ +
+ ) : ( + + )} +
+
+ ); +}; + +export default ArticleLinksBlock; diff --git a/src/app/components/ArticleLinksBlock/metadata.json b/src/app/components/ArticleLinksBlock/metadata.json new file mode 100644 index 00000000000..1335762526c --- /dev/null +++ b/src/app/components/ArticleLinksBlock/metadata.json @@ -0,0 +1,29 @@ +{ + "alpha": false, + "lastUpdated": { + "day": 18, + "month": "December", + "year": 2025 + }, + "uxAccessibilityDoc": { + "done": false, + "reference": { + "url": "", + "label": "Screen Reader UX" + } + }, + "acceptanceCriteria": { + "done": false, + "reference": { + "url": "", + "label": "Accessibility Acceptance Criteria" + } + }, + "swarm": { + "done": false, + "reference": { + "url": "", + "label": "Accessibility Swarm Notes" + } + } +} diff --git a/src/app/legacy/components/ScrollablePromo/Promo/index.jsx b/src/app/legacy/components/ScrollablePromo/Promo/index.jsx deleted file mode 100644 index b123a3606b7..00000000000 --- a/src/app/legacy/components/ScrollablePromo/Promo/index.jsx +++ /dev/null @@ -1,198 +0,0 @@ -import { use } from 'react'; -import styled from '@emotion/styled'; -import path from 'ramda/src/path'; -import { Link } from '#psammead/psammead-story-promo/src'; -import { - GEL_SPACING, - GEL_SPACING_DBL, - GEL_SPACING_TRPL, -} from '#psammead/gel-foundations/src/spacings'; -import { - GEL_GROUP_0_SCREEN_WIDTH_MIN, - GEL_GROUP_1_SCREEN_WIDTH_MIN, - GEL_GROUP_2_SCREEN_WIDTH_MIN, - GEL_GROUP_3_SCREEN_WIDTH_MIN, - GEL_GROUP_4_SCREEN_WIDTH_MIN, -} from '#psammead/gel-foundations/src/breakpoints'; -import filterForBlockType from '#lib/utilities/blockHandlers'; -import useOperaMiniDetection from '#hooks/useOperaMiniDetection'; -import PromoTimestamp from '#components/Promo/timestamp'; -import LiveLabel from '../../../../components/LiveLabel'; -import { ServiceContext } from '../../../../contexts/ServiceContext'; - -const StyledLink = styled(Link)` - ${({ theme: { fontSizes } }) => fontSizes.pica}; - ${({ theme: { fontVariants } }) => fontVariants.serifBold}; - width: 100%; - text-decoration: none; - - overflow-x: hidden; - overflow-y: hidden; - - ${({ experimentVariant }) => - !experimentVariant && - ` -webkit-line-clamp: 4; - -webkit-box-orient: vertical; - display: -webkit-box; - `} - - &:hover, - &:focus { - text-decoration: underline; - } - - color: ${({ theme }) => - theme.isDarkUi ? theme.palette.GREY_10 : theme.palette.GREY_8}; - &:visited { - color: ${props => props.theme.palette.GREY_6}; - } -`; - -const PromoBox = styled.div` - position: relative; - background-color: ${({ theme }) => - theme.isDarkUi ? theme.palette.GREY_3 : theme.palette.WHITE}; - padding: ${GEL_SPACING_DBL}; - margin-bottom: ${GEL_SPACING_TRPL}; - height: auto; - @media (min-width: ${GEL_GROUP_0_SCREEN_WIDTH_MIN}) { - width: 14.8125rem; - } - @media (min-width: ${GEL_GROUP_3_SCREEN_WIDTH_MIN}) { - width: 11.125rem; - } - @media (min-width: ${GEL_GROUP_4_SCREEN_WIDTH_MIN}) { - width: 12.6875rem; - } - ${({ experimentVariant }) => - experimentVariant && - ` - display: block; - margin-bottom: 0; - @media (min-width: ${GEL_GROUP_0_SCREEN_WIDTH_MIN}) { - width: 11.5rem; - } - @media (min-width: ${GEL_GROUP_1_SCREEN_WIDTH_MIN}) { - width: 17rem; - } - @media (min-width: ${GEL_GROUP_3_SCREEN_WIDTH_MIN}) { - width: 15.5rem; - } - padding: ${GEL_SPACING}; - `} -`; - -const OperaPromoBox = styled.div` - position: relative; - background-color: ${({ theme }) => - theme.isDarkUi ? theme.palette.GREY_3 : theme.palette.WHITE}; - padding: ${GEL_SPACING_DBL}; - margin-bottom: ${GEL_SPACING_DBL}; - width: calc(100% - ${GEL_SPACING}); - @media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}) { - width: calc(100% - ${GEL_SPACING_DBL}); - } -`; - -const TimeStamp = styled(PromoTimestamp)` - margin-top: ${GEL_SPACING}; - color: ${({ theme }) => theme.isDarkUi && theme.palette.GREY_6}; -`; - -const Promo = ({ block, experimentVariant, clickTracker }) => { - const { script, service, serviceDatetimeLocale } = use(ServiceContext); - let title; - let href; - let textBlock; - let aresLinkBlock; - let timestamp; - let isLive; - - switch (experimentVariant) { - case 'top-bar-top-stories': - case 'read-more-a-and-top-stories': { - const overtypedHeadline = block?.headlines?.overtyped ?? ''; - const mainHeadline = block?.headlines?.headline ?? ''; - const headlineBlockText = - block?.headlines?.promoHeadline?.blocks?.[0]?.model?.blocks?.[0]?.model - ?.text ?? ''; - const name = block?.name ?? ''; - - title = - overtypedHeadline || - mainHeadline || - headlineBlockText || - name || - block.headline || - ''; - - const canonicalUrl = block?.locators?.canonicalUrl ?? ''; - const assetUri = block?.locators?.assetUri ?? ''; - const uri = block?.uri ?? ''; - - href = - canonicalUrl || - assetUri || - uri || - (block.destinationUrl - ? `https://www.bbc.com${block.destinationUrl}` - : ''); - isLive = block.isLive; - break; - } - case 'top-bar-most-read': - title = block.title; - href = block.href; - break; - default: - textBlock = filterForBlockType(block?.model?.blocks || {}, 'text'); - aresLinkBlock = filterForBlockType( - block?.model?.blocks || {}, - 'aresLink', - ); - timestamp = path( - ['model', 'blocks', '0', 'model', 'timestamp'], - aresLinkBlock, - ); - href = - path( - ['model', 'blocks', '0', 'model', 'blocks', '0', 'model', 'locator'], - textBlock, - ) || ''; - title = - path( - ['model', 'blocks', '0', 'model', 'blocks', '0', 'model', 'text'], - textBlock, - ) || ''; - break; - } - - const isOperaMini = useOperaMiniDetection(); - - const WrapperPromoBox = isOperaMini ? OperaPromoBox : PromoBox; - - return ( - - - {isLive && } - {title} - - {timestamp && !experimentVariant && ( - - {timestamp} - - )} - - ); -}; - -export default Promo; diff --git a/src/app/legacy/components/ScrollablePromo/Promo/index.test.jsx b/src/app/legacy/components/ScrollablePromo/Promo/index.test.jsx deleted file mode 100644 index 69e4cd67c04..00000000000 --- a/src/app/legacy/components/ScrollablePromo/Promo/index.test.jsx +++ /dev/null @@ -1,136 +0,0 @@ -import { render } from '../../../../components/react-testing-library-with-providers'; -import { - PromoSingleBlock, - oneLinkWithTimestamp, - topStoriesBlocks, - mostReadBlocks, - topStoriesBlocksWithLiveItem, -} from '../helpers/fixtureData'; -import Promo from '.'; -import { ServiceContextProvider } from '../../../../contexts/ServiceContext'; - -const ScrollablePromo = ({ block, experimentVariant }) => ( - - {}} - experimentVariant={experimentVariant} - /> - -); - -describe('ScrollablePromo', () => { - it('should render a link', () => { - const { queryByRole } = render( - , - ); - expect(queryByRole('link')).toBeInTheDocument(); - }); - - it('should extract and render the correct title', () => { - const { getByText } = render(); - expect( - getByText( - 'This is a very long headline. I am creating this for a test purpose. I love creating these type of tests. I really do not know what to write.', - ), - ).toBeTruthy(); - }); - - it('should extract and render the correct href', () => { - const { queryByRole } = render( - , - ); - expect(queryByRole('link').href).toEqual('https://www.bbc.com/mundo'); - }); - - it('should render timestamp if timestamp is available', () => { - const { container } = render( - , - ); - expect(container.getElementsByTagName('time')[0]).toBeInTheDocument(); - }); - - describe('OJ Top Bar Promo', () => { - it('should display Top Stories content when experimentVariant is top-bar-top-stories', () => { - const { container } = render( - , - ); - const expectedHeadline = - topStoriesBlocks[0].headlines.promoHeadline.blocks[0].model.blocks[0] - .model.text; - expect(container).toHaveTextContent(expectedHeadline); - }); - - it('should display Top Stories content when experimentVariant is read-more-a-and-top-stories', () => { - const { container } = render( - , - ); - const expectedHeadline = - topStoriesBlocks[0].headlines.promoHeadline.blocks[0].model.blocks[0] - .model.text; - expect(container).toHaveTextContent(expectedHeadline); - }); - - it('should display Most Read content when experimentVariant is top-bar-most-read', () => { - const { container } = render( - , - ); - const expectedHeadline = mostReadBlocks[0].title; - expect(container).toHaveTextContent(expectedHeadline); - }); - - it('should render a link on Top Stories article headline when experimentVariant is top-bar-top-stories', () => { - const { queryByRole } = render( - , - ); - expect(queryByRole('link')).toBeInTheDocument(); - }); - - it('should render a link on Most Read article headline when experimentVariant is top-bar-most-read', () => { - const { queryByRole } = render( - , - ); - expect(queryByRole('link')).toBeInTheDocument(); - }); - - it('should not display a timestamp when experimentVariant is top-bar-top-stories or top-bar-most-read', () => { - const { queryByTestId } = render( - , - ); - expect(queryByTestId('timestamp')).not.toBeInTheDocument(); - }); - - it('should display a LiveLabel when returning Top Stories', () => { - const { container } = render( - , - ); - expect( - container.querySelector('[class*="liveLabelPulse"]'), - ).toBeInTheDocument(); - expect( - container.querySelector('[class*="liveLabelText"]'), - ).toBeInTheDocument(); - }); - }); -}); diff --git a/src/app/legacy/components/ScrollablePromo/PromoList/index.jsx b/src/app/legacy/components/ScrollablePromo/PromoList/index.jsx deleted file mode 100644 index aa8cb854588..00000000000 --- a/src/app/legacy/components/ScrollablePromo/PromoList/index.jsx +++ /dev/null @@ -1,127 +0,0 @@ -import { use } from 'react'; -import styled from '@emotion/styled'; -import { - GEL_SPACING, - GEL_SPACING_DBL, -} from '#psammead/gel-foundations/src/spacings'; -import { - GEL_GROUP_0_SCREEN_WIDTH_MIN, - GEL_GROUP_2_SCREEN_WIDTH_MIN, - GEL_GROUP_4_SCREEN_WIDTH_MIN, -} from '#psammead/gel-foundations/src/breakpoints'; -import useOperaMiniDetection from '#hooks/useOperaMiniDetection'; -import { ServiceContext } from '../../../../contexts/ServiceContext'; -import Promo from '../Promo'; - -const StandardScrollPromo = styled.ul` - list-style: none; - ${({ dir }) => `padding-${dir === 'ltr' ? 'left' : 'right'}: 0;`} - margin: 0; - display: flex; - overflow-x: scroll; - /* Avoid using smooth scrolling as it causes accessibility issues */ - scroll-behavior: auto; - -webkit-overflow-scrolling: touch; - - /* Hide scrollbar */ - scrollbar-width: none; - -ms-overflow-style: none; - &::-webkit-scrollbar { - display: none; - } -`; - -const OperaScrollPromo = styled.ul` - list-style: none; - ${({ dir }) => `padding-${dir === 'ltr' ? 'left' : 'right'}: 0;`} - margin: 0; -`; - -const StyledList = styled.li` - display: flex; - flex-shrink: 0; - - ${({ dir, experimentVariant }) => - ` - @media (min-width: ${GEL_GROUP_0_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? 'left' : 'right'}: ${GEL_SPACING}; - &:first-child { - margin-${dir === 'ltr' ? 'left' : 'right'}: ${experimentVariant && experimentVariant !== 'off' ? 0 : GEL_SPACING}; - } - &:last-child { - margin-${dir === 'ltr' ? 'right' : 'left'}: ${GEL_SPACING}; - } - } - @media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? `left` : `right`}: ${GEL_SPACING_DBL}; - - &:first-child { - margin-${dir === 'ltr' ? 'left' : 'right'}: ${experimentVariant && experimentVariant !== 'off' ? 0 : GEL_SPACING_DBL}; - } - } - @media (min-width: ${GEL_GROUP_4_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? `left` : `right`}: ${GEL_SPACING_DBL}; - &:first-child { - margin-${dir === 'ltr' ? 'left' : 'right'}: 0; - } - } - `} -`; - -const OperaStyledList = styled.li` - ${({ dir }) => `@media (min-width: ${GEL_GROUP_0_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? 'left' : 'right'}: ${GEL_SPACING}; - } - @media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? `left` : `right`}: ${GEL_SPACING_DBL}; - } - @media (min-width: ${GEL_GROUP_4_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? `left` : `right`}: 0;}`} -`; - -const PromoList = ({ - blocks, - experimentVariant, - viewTracker, - clickTracker, - a11yAttributes, -}) => { - const { dir } = use(ServiceContext); - const isOperaMini = useOperaMiniDetection(); - const listBlocks = - experimentVariant === 'top-bar-most-read' - ? blocks.slice(0, 5) - : blocks.slice(0, 3); - - const ScrollPromo = isOperaMini ? OperaScrollPromo : StandardScrollPromo; - const List = isOperaMini ? OperaStyledList : StyledList; - - return ( - - {listBlocks.map((block, index) => { - return ( - - - - ); - })} - - ); -}; - -export default PromoList; diff --git a/src/app/legacy/components/ScrollablePromo/__snapshots__/index.test.jsx.snap b/src/app/legacy/components/ScrollablePromo/__snapshots__/index.test.jsx.snap deleted file mode 100644 index 93894e197a0..00000000000 --- a/src/app/legacy/components/ScrollablePromo/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,1110 +0,0 @@ -// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing - -exports[`ScrollablePromo Mid Page ScrollablePromo it should match a11y snapshot for list 1`] = ` -@media (max-width: 14.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 15rem) and (max-width: 24.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 25rem) and (max-width: 37.4375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 37.5rem) and (max-width: 62.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 63rem) and (max-width: 79.9375rem) { - .emotion-0 { - margin-left: 20%; - } -} - -@media (min-width: 80rem) { - .emotion-0 { - margin-left: 40%; - } -} - -@supports (display: grid) { - .emotion-0 { - display: block; - width: initial; - margin: 0; - } - - @media (max-width: 14.9375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 15rem) and (max-width: 24.9375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 25rem) and (max-width: 37.4375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 37.5rem) and (max-width: 62.9375rem) { - .emotion-0 { - grid-template-columns: repeat(5, 1fr); - grid-column-end: span 5; - grid-column-start: 1; - } - } - - @media (min-width: 63rem) and (max-width: 79.9375rem) { - .emotion-0 { - grid-template-columns: repeat(5, 1fr); - grid-column-end: span 5; - grid-column-start: 2; - } - } - - @media (min-width: 80rem) { - .emotion-0 { - grid-template-columns: repeat(10, 1fr); - grid-column-end: span 10; - grid-column-start: 5; - } - } -} - -.emotion-2 { - display: block; - font-size: 1.125rem; - line-height: 1.375rem; - font-family: ReithSans,Helvetica,Arial,sans-serif; - font-style: normal; - font-weight: 400; - margin-bottom: 1rem; - color: #3F3F42; -} - -@media (min-width: 20rem) and (max-width: 37.4375rem) { - .emotion-2 { - font-size: 1.25rem; - line-height: 1.5rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-2 { - font-size: 1.5rem; - line-height: 1.75rem; - } -} - -@media (min-width: 0rem) { - .emotion-2 { - margin-left: 0.5rem; - } -} - -@media (min-width: 25rem) { - .emotion-2 { - margin-left: 1rem; - } -} - -@media (min-width: 63rem) { - .emotion-2 { - margin-left: 0; - } -} - -.emotion-4 { - list-style: none; - padding-left: 0; - margin: 0; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - overflow-x: scroll; - scroll-behavior: auto; - -webkit-overflow-scrolling: touch; - scrollbar-width: none; - -ms-overflow-style: none; -} - -.emotion-4::-webkit-scrollbar { - display: none; -} - -.emotion-6 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-shrink: 0; - -ms-flex-negative: 0; - flex-shrink: 0; -} - -@media (min-width: 0rem) { - .emotion-6 { - margin-left: 0.5rem; - } - - .emotion-6:first-child { - margin-left: 0.5rem; - } - - .emotion-6:last-child { - margin-right: 0.5rem; - } -} - -@media (min-width: 25rem) { - .emotion-6 { - margin-left: 1rem; - } - - .emotion-6:first-child { - margin-left: 1rem; - } -} - -@media (min-width: 63rem) { - .emotion-6 { - margin-left: 1rem; - } - - .emotion-6:first-child { - margin-left: 0; - } -} - -.emotion-8 { - position: relative; - background-color: #FFFFFF; - padding: 1rem; - margin-bottom: 1.5rem; - height: auto; -} - -@media (min-width: 0rem) { - .emotion-8 { - width: 14.8125rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-8 { - width: 11.125rem; - } -} - -@media (min-width: 63rem) { - .emotion-8 { - width: 12.6875rem; - } -} - -.emotion-10 { - position: static; - color: #222222; - -webkit-text-decoration: none; - text-decoration: none; - overflow-wrap: break-word; - display: inline-block; - font-size: 0.9375rem; - line-height: 1.25rem; - font-family: ReithSerif,Helvetica,Arial,sans-serif; - font-style: normal; - font-weight: 700; - width: 100%; - -webkit-text-decoration: none; - text-decoration: none; - overflow-x: hidden; - overflow-y: hidden; - -webkit-line-clamp: 4; - -webkit-box-orient: vertical; - display: -webkit-box; - color: #202224; -} - -.emotion-10:before { - bottom: 0; - content: ''; - left: 0; - overflow: hidden; - position: absolute; - right: 0; - top: 0; - white-space: nowrap; - z-index: 1; -} - -.emotion-10:hover, -.emotion-10:focus { - -webkit-text-decoration: underline; - text-decoration: underline; -} - -.emotion-10:visited { - color: #6E6E73; -} - -@media (min-width: 20rem) and (max-width: 37.4375rem) { - .emotion-10 { - font-size: 1rem; - line-height: 1.25rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-10 { - font-size: 1rem; - line-height: 1.25rem; - } -} - -.emotion-10:hover, -.emotion-10:focus { - -webkit-text-decoration: underline; - text-decoration: underline; -} - -.emotion-10:visited { - color: #545658; -} - -
-
- - Show all links (no images) - - -
-
-`; - -exports[`ScrollablePromo Mid Page ScrollablePromo it should match a11y snapshot for list with no title 1`] = ` -@media (max-width: 14.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 15rem) and (max-width: 24.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 25rem) and (max-width: 37.4375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 37.5rem) and (max-width: 62.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 63rem) and (max-width: 79.9375rem) { - .emotion-0 { - margin-left: 20%; - } -} - -@media (min-width: 80rem) { - .emotion-0 { - margin-left: 40%; - } -} - -@supports (display: grid) { - .emotion-0 { - display: block; - width: initial; - margin: 0; - } - - @media (max-width: 14.9375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 15rem) and (max-width: 24.9375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 25rem) and (max-width: 37.4375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 37.5rem) and (max-width: 62.9375rem) { - .emotion-0 { - grid-template-columns: repeat(5, 1fr); - grid-column-end: span 5; - grid-column-start: 1; - } - } - - @media (min-width: 63rem) and (max-width: 79.9375rem) { - .emotion-0 { - grid-template-columns: repeat(5, 1fr); - grid-column-end: span 5; - grid-column-start: 2; - } - } - - @media (min-width: 80rem) { - .emotion-0 { - grid-template-columns: repeat(10, 1fr); - grid-column-end: span 10; - grid-column-start: 5; - } - } -} - -.emotion-2 { - margin-left: 0.5rem; -} - -@media (min-width: 25rem) { - .emotion-2 { - margin-left: 1rem; - } -} - -@media (min-width: 63rem) { - .emotion-2 { - margin-left: 0; - } -} - -.emotion-4 { - position: relative; - background-color: #FFFFFF; - padding: 1rem; - margin-bottom: 1.5rem; - height: auto; -} - -@media (min-width: 0rem) { - .emotion-4 { - width: 14.8125rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-4 { - width: 11.125rem; - } -} - -@media (min-width: 63rem) { - .emotion-4 { - width: 12.6875rem; - } -} - -.emotion-6 { - position: static; - color: #222222; - -webkit-text-decoration: none; - text-decoration: none; - overflow-wrap: break-word; - display: inline-block; - font-size: 0.9375rem; - line-height: 1.25rem; - font-family: ReithSerif,Helvetica,Arial,sans-serif; - font-style: normal; - font-weight: 700; - width: 100%; - -webkit-text-decoration: none; - text-decoration: none; - overflow-x: hidden; - overflow-y: hidden; - -webkit-line-clamp: 4; - -webkit-box-orient: vertical; - display: -webkit-box; - color: #202224; -} - -.emotion-6:before { - bottom: 0; - content: ''; - left: 0; - overflow: hidden; - position: absolute; - right: 0; - top: 0; - white-space: nowrap; - z-index: 1; -} - -.emotion-6:hover, -.emotion-6:focus { - -webkit-text-decoration: underline; - text-decoration: underline; -} - -.emotion-6:visited { - color: #6E6E73; -} - -@media (min-width: 20rem) and (max-width: 37.4375rem) { - .emotion-6 { - font-size: 1rem; - line-height: 1.25rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-6 { - font-size: 1rem; - line-height: 1.25rem; - } -} - -.emotion-6:hover, -.emotion-6:focus { - -webkit-text-decoration: underline; - text-decoration: underline; -} - -.emotion-6:visited { - color: #545658; -} - -
-
- -
-
-`; - -exports[`ScrollablePromo Mid Page ScrollablePromo it should match a11y snapshot for single card 1`] = ` -@media (max-width: 14.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 15rem) and (max-width: 24.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 25rem) and (max-width: 37.4375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 37.5rem) and (max-width: 62.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 63rem) and (max-width: 79.9375rem) { - .emotion-0 { - margin-left: 20%; - } -} - -@media (min-width: 80rem) { - .emotion-0 { - margin-left: 40%; - } -} - -@supports (display: grid) { - .emotion-0 { - display: block; - width: initial; - margin: 0; - } - - @media (max-width: 14.9375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 15rem) and (max-width: 24.9375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 25rem) and (max-width: 37.4375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 37.5rem) and (max-width: 62.9375rem) { - .emotion-0 { - grid-template-columns: repeat(5, 1fr); - grid-column-end: span 5; - grid-column-start: 1; - } - } - - @media (min-width: 63rem) and (max-width: 79.9375rem) { - .emotion-0 { - grid-template-columns: repeat(5, 1fr); - grid-column-end: span 5; - grid-column-start: 2; - } - } - - @media (min-width: 80rem) { - .emotion-0 { - grid-template-columns: repeat(10, 1fr); - grid-column-end: span 10; - grid-column-start: 5; - } - } -} - -.emotion-2 { - display: block; - font-size: 1.125rem; - line-height: 1.375rem; - font-family: ReithSans,Helvetica,Arial,sans-serif; - font-style: normal; - font-weight: 400; - margin-bottom: 1rem; - color: #3F3F42; -} - -@media (min-width: 20rem) and (max-width: 37.4375rem) { - .emotion-2 { - font-size: 1.25rem; - line-height: 1.5rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-2 { - font-size: 1.5rem; - line-height: 1.75rem; - } -} - -@media (min-width: 0rem) { - .emotion-2 { - margin-left: 0.5rem; - } -} - -@media (min-width: 25rem) { - .emotion-2 { - margin-left: 1rem; - } -} - -@media (min-width: 63rem) { - .emotion-2 { - margin-left: 0; - } -} - -.emotion-4 { - margin-left: 0.5rem; -} - -@media (min-width: 25rem) { - .emotion-4 { - margin-left: 1rem; - } -} - -@media (min-width: 63rem) { - .emotion-4 { - margin-left: 0; - } -} - -.emotion-6 { - position: relative; - background-color: #FFFFFF; - padding: 1rem; - margin-bottom: 1.5rem; - height: auto; -} - -@media (min-width: 0rem) { - .emotion-6 { - width: 14.8125rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-6 { - width: 11.125rem; - } -} - -@media (min-width: 63rem) { - .emotion-6 { - width: 12.6875rem; - } -} - -.emotion-8 { - position: static; - color: #222222; - -webkit-text-decoration: none; - text-decoration: none; - overflow-wrap: break-word; - display: inline-block; - font-size: 0.9375rem; - line-height: 1.25rem; - font-family: ReithSerif,Helvetica,Arial,sans-serif; - font-style: normal; - font-weight: 700; - width: 100%; - -webkit-text-decoration: none; - text-decoration: none; - overflow-x: hidden; - overflow-y: hidden; - -webkit-line-clamp: 4; - -webkit-box-orient: vertical; - display: -webkit-box; - color: #202224; -} - -.emotion-8:before { - bottom: 0; - content: ''; - left: 0; - overflow: hidden; - position: absolute; - right: 0; - top: 0; - white-space: nowrap; - z-index: 1; -} - -.emotion-8:hover, -.emotion-8:focus { - -webkit-text-decoration: underline; - text-decoration: underline; -} - -.emotion-8:visited { - color: #6E6E73; -} - -@media (min-width: 20rem) and (max-width: 37.4375rem) { - .emotion-8 { - font-size: 1rem; - line-height: 1.25rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-8 { - font-size: 1rem; - line-height: 1.25rem; - } -} - -.emotion-8:hover, -.emotion-8:focus { - -webkit-text-decoration: underline; - text-decoration: underline; -} - -.emotion-8:visited { - color: #545658; -} - -
-
- - Single link - - -
-
-`; - -exports[`ScrollablePromo Mid Page ScrollablePromo it should match snapshot when in dark ui mode 1`] = ` -@media (max-width: 14.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 15rem) and (max-width: 24.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 25rem) and (max-width: 37.4375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 37.5rem) and (max-width: 62.9375rem) { - .emotion-0 { - margin-left: 0%; - } -} - -@media (min-width: 63rem) and (max-width: 79.9375rem) { - .emotion-0 { - margin-left: 20%; - } -} - -@media (min-width: 80rem) { - .emotion-0 { - margin-left: 40%; - } -} - -@supports (display: grid) { - .emotion-0 { - display: block; - width: initial; - margin: 0; - } - - @media (max-width: 14.9375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 15rem) and (max-width: 24.9375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 25rem) and (max-width: 37.4375rem) { - .emotion-0 { - grid-template-columns: repeat(6, 1fr); - grid-column-end: span 6; - grid-column-start: 1; - } - } - - @media (min-width: 37.5rem) and (max-width: 62.9375rem) { - .emotion-0 { - grid-template-columns: repeat(5, 1fr); - grid-column-end: span 5; - grid-column-start: 1; - } - } - - @media (min-width: 63rem) and (max-width: 79.9375rem) { - .emotion-0 { - grid-template-columns: repeat(5, 1fr); - grid-column-end: span 5; - grid-column-start: 2; - } - } - - @media (min-width: 80rem) { - .emotion-0 { - grid-template-columns: repeat(10, 1fr); - grid-column-end: span 10; - grid-column-start: 5; - } - } -} - -.emotion-2 { - margin-left: 0.5rem; -} - -@media (min-width: 25rem) { - .emotion-2 { - margin-left: 1rem; - } -} - -@media (min-width: 63rem) { - .emotion-2 { - margin-left: 0; - } -} - -.emotion-4 { - position: relative; - background-color: #E6E8EA; - padding: 1rem; - margin-bottom: 1.5rem; - height: auto; -} - -@media (min-width: 0rem) { - .emotion-4 { - width: 14.8125rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-4 { - width: 11.125rem; - } -} - -@media (min-width: 63rem) { - .emotion-4 { - width: 12.6875rem; - } -} - -.emotion-6 { - position: static; - color: #222222; - -webkit-text-decoration: none; - text-decoration: none; - overflow-wrap: break-word; - display: inline-block; - font-size: 0.9375rem; - line-height: 1.25rem; - font-family: ReithSerif,Helvetica,Arial,sans-serif; - font-style: normal; - font-weight: 700; - width: 100%; - -webkit-text-decoration: none; - text-decoration: none; - overflow-x: hidden; - overflow-y: hidden; - -webkit-line-clamp: 4; - -webkit-box-orient: vertical; - display: -webkit-box; - color: #141414; -} - -.emotion-6:before { - bottom: 0; - content: ''; - left: 0; - overflow: hidden; - position: absolute; - right: 0; - top: 0; - white-space: nowrap; - z-index: 1; -} - -.emotion-6:hover, -.emotion-6:focus { - -webkit-text-decoration: underline; - text-decoration: underline; -} - -.emotion-6:visited { - color: #6E6E73; -} - -@media (min-width: 20rem) and (max-width: 37.4375rem) { - .emotion-6 { - font-size: 1rem; - line-height: 1.25rem; - } -} - -@media (min-width: 37.5rem) { - .emotion-6 { - font-size: 1rem; - line-height: 1.25rem; - } -} - -.emotion-6:hover, -.emotion-6:focus { - -webkit-text-decoration: underline; - text-decoration: underline; -} - -.emotion-6:visited { - color: #545658; -} - -
-
- -
-
-`; diff --git a/src/app/legacy/components/ScrollablePromo/index.jsx b/src/app/legacy/components/ScrollablePromo/index.jsx deleted file mode 100644 index 95fbf921f22..00000000000 --- a/src/app/legacy/components/ScrollablePromo/index.jsx +++ /dev/null @@ -1,260 +0,0 @@ -import { use } from 'react'; -import { - GEL_SPACING, - GEL_SPACING_DBL, - GEL_SPACING_QUAD, -} from '#psammead/gel-foundations/src/spacings'; - -import styled from '@emotion/styled'; -import path from 'ramda/src/path'; -import pathOr from 'ramda/src/pathOr'; -import isEmpty from 'ramda/src/isEmpty'; -import tail from 'ramda/src/tail'; -import { - GEL_GROUP_0_SCREEN_WIDTH_MIN, - GEL_GROUP_2_SCREEN_WIDTH_MIN, - GEL_GROUP_3_SCREEN_WIDTH_MAX, - GEL_GROUP_3_SCREEN_WIDTH_MIN, - GEL_GROUP_4_SCREEN_WIDTH_MIN, -} from '#psammead/gel-foundations/src/breakpoints'; -import { GridItemMediumNoMargin } from '#components/Grid'; -import useViewTracker from '#hooks/useViewTracker'; -import useClickTrackerHandler from '#hooks/useClickTrackerHandler'; -import idSanitiser from '#lib/utilities/idSanitiser'; -import { GREY_2 } from '#app/components/ThemeProvider/palette'; -import { ServiceContext } from '../../../contexts/ServiceContext'; -import Promo from './Promo'; -import PromoList from './PromoList'; - -const PromoWrapper = styled.div` - ${({ dir }) => `margin-${dir === 'ltr' ? 'left' : 'right'}: ${GEL_SPACING};`} - @media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}) { - ${({ dir }) => - `margin-${dir === 'ltr' ? 'left' : 'right'}: ${GEL_SPACING_DBL};`} - } - @media (min-width: ${GEL_GROUP_4_SCREEN_WIDTH_MIN}) { - ${({ dir }) => `margin-${dir === 'ltr' ? 'left' : 'right'}: 0;`} - } -`; - -const ScrollablePromoContainer = styled.div` - background: ${GREY_2}; - padding: ${GEL_SPACING}; - display: flex; - overflow-x: auto; - -ms-overflow-style: none; - scrollbar-width: none; - &::-webkit-scrollbar { - display: none; - } - ${({ experimentVariant }) => - experimentVariant && - experimentVariant !== 'off' && - ` - padding: 0 ${GEL_SPACING} ${GEL_SPACING_DBL}; - margin: 0rem; - - @media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}) { - padding: 0 ${GEL_SPACING_DBL} ${GEL_SPACING_DBL}; - margin: 0 -0.2rem; - } - - @media (min-width: ${GEL_GROUP_3_SCREEN_WIDTH_MIN}) { - margin: 0 -0.8rem; - } - - @media (min-width: ${GEL_GROUP_3_SCREEN_WIDTH_MAX}) { - display: none; - } - - width: 100vw; - `} -`; - -const LabelComponent = styled.strong` - display: block; - ${({ theme: { fontSizes } }) => fontSizes.doublePica}; - ${({ theme: { fontVariants } }) => fontVariants.sansRegular}; - margin-bottom: ${GEL_SPACING_DBL}; - color: ${({ theme }) => - theme.isDarkUi ? theme.palette.GREY_2 : theme.palette.SHADOW}; - - ${({ dir }) => - ` - @media (min-width: ${GEL_GROUP_0_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? 'left' : 'right'}: ${GEL_SPACING}; - } - @media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? `left` : `right`}: ${GEL_SPACING_DBL}; - } - @media (min-width: ${GEL_GROUP_4_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? `left` : `right`}: 0; - } -`} -`; - -const LabelComponentOJTopBar = styled(({ ariaLabel, ...props }) => ( - -))` - ${({ theme: { fontSizes } }) => fontSizes.brevier}; - ${({ theme: { fontVariants } }) => fontVariants.sansRegular}; - display: inline-block; - margin-bottom: ${GEL_SPACING_DBL}; - color: ${({ theme }) => - theme.isDarkUi ? theme.palette.GREY_2 : theme.palette.SHADOW}; - - ${({ dir }) => - ` - @media (min-width: ${GEL_GROUP_0_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? 'left' : 'right'}: ${GEL_SPACING}; - } - @media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? `left` : `right`}: ${GEL_SPACING_DBL}; - } - @media (min-width: ${GEL_GROUP_4_SCREEN_WIDTH_MIN}){ - margin-${dir === 'ltr' ? `left` : `right`}: 0; - } - `} - - padding: 0 ${GEL_SPACING}; - - @media (min-width: ${GEL_GROUP_0_SCREEN_WIDTH_MIN}) { - margin: 0rem; - } - - @media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}) { - padding: 0 ${GEL_SPACING_DBL}; - margin: 0 -0.2rem; - } - - @media (min-width: ${GEL_GROUP_3_SCREEN_WIDTH_MIN}) { - margin: 0 -0.8rem; - } - - @media (min-width: ${GEL_GROUP_3_SCREEN_WIDTH_MAX}) { - display: none; - } - - display: flex; - align-items: center; - height: ${GEL_SPACING_QUAD}; - background: ${GREY_2}; - width: 100vw; -`; - -const ScrollablePromo = ({ - blocks, - blockGroupIndex = null, - experimentVariant = null, -}) => { - const { script, service, dir, translations, mostRead } = use(ServiceContext); - - const eventTrackingData = { - componentName: `edoj${blockGroupIndex}`, - format: 'CHD=edoj', - ...(experimentVariant && { - componentName: 'top-bar-oj', - sendOptimizelyEvents: true, - viewThreshold: 0, - }), - }; - - const viewTracker = useViewTracker(eventTrackingData); - const clickTracker = useClickTrackerHandler(eventTrackingData); - - if (!blocks || isEmpty(blocks)) { - return null; - } - - let title; - if ( - ['top-bar-top-stories', 'read-more-a-and-top-stories'].includes( - experimentVariant, - ) - ) { - title = translations.topStoriesTitle || 'Top Stories'; - } else if (experimentVariant === 'top-bar-most-read') { - title = mostRead.header || 'Most Read'; - } else { - title = - blocks[0].type === 'title' && - path( - ['0', 'model', 'blocks', '0', 'model', 'blocks', '0', 'model', 'text'], - blocks, - ); - } - - const blocksWithoutTitle = blocks[0].type === 'title' ? tail(blocks) : blocks; - - const isSingleItem = blocksWithoutTitle.length === 1; - - const ariaLabel = title && idSanitiser(title); - - const a11yAttributes = { - ...(!experimentVariant && { - as: 'section', - role: 'region', - }), - ...(ariaLabel - ? { 'aria-labelledby': ariaLabel } - : { - 'aria-label': pathOr( - 'Related Content', - ['relatedContent'], - translations, - ), - }), - }; - - return experimentVariant ? ( - <> - - {title} - - - - - - - - ) : ( - - {title && ( - - {title} - - )} - {isSingleItem ? ( - - - - ) : ( - - )} - - ); -}; - -export default ScrollablePromo; diff --git a/src/app/legacy/components/ScrollablePromo/index.stories.jsx b/src/app/legacy/components/ScrollablePromo/index.stories.jsx deleted file mode 100644 index de5a43b26fd..00000000000 --- a/src/app/legacy/components/ScrollablePromo/index.stories.jsx +++ /dev/null @@ -1,124 +0,0 @@ -import styled from '@emotion/styled'; -import { ServiceContextProvider } from '#contexts/ServiceContext'; -import ScrollablePromo from '.'; -import { - threeLinks, - oneLinkOnly, - oneLinkWithNoTitle, - oneLinkWithTimestamp, - moreThanThreeLinks, - twoLinksWithNoImages, - truncatedTextInSingleLink, - arabicText, - topStoriesBlocks, - topStoriesBlocksWithLiveItem, - mostReadBlocks, - mostReadBlocksRTL, -} from './helpers/fixtureData'; - -const BackGround = styled.div` - background-color: #f6f6f6; - padding: 2rem; -`; - -const ScrollablePromoComponent = ({ - data, - service, - experimentVariant = null, -}) => ( - - - -); - -export default { - title: 'Components/Scrollable Promo', - ScrollablePromoComponent, -}; - -export const ThreeLinks = (_, { service }) => ( - - - -); - -export const OnlyOneLink = (_, { service }) => ( - - - -); - -export const OneLinkWithNoTitle = (_, { service }) => ( - - - -); - -export const MoreThanThreeLinks = (_, { service }) => ( - - - -); - -export const NoImagesInData = (_, { service }) => ( - - - -); - -export const TruncatedTextInSingleLink = (_, { service }) => ( - - - -); - -export const ArabicText = () => ( - - - -); - -ArabicText.globals = { - service: { service: 'arabic' }, -}; - -export const WithTimestamp = (_, { service }) => ( - - - -); - -export const OJTopBarTopStories = (_, { service }) => ( - -); - -export const OJTopBarTopStoriesWithLiveLabel = (_, { service }) => ( - -); - -export const OJTopBarMostRead = (_, { service }) => ( - -); - -export const OJTopBarMostReadRTL = () => ( - -); diff --git a/src/app/legacy/components/ScrollablePromo/index.test.jsx b/src/app/legacy/components/ScrollablePromo/index.test.jsx deleted file mode 100644 index 63ce2abb127..00000000000 --- a/src/app/legacy/components/ScrollablePromo/index.test.jsx +++ /dev/null @@ -1,249 +0,0 @@ -import * as viewTracking from '#hooks/useViewTracker'; -import * as clickTracking from '#hooks/useClickTrackerHandler'; -import { render } from '../../../components/react-testing-library-with-providers'; -import { - threeLinks, - oneLinkOnly, - oneLinkWithNoTitle, - moreThanThreeLinks, - topStoriesBlocks, - mostReadBlocks, -} from './helpers/fixtureData'; -import ScrollablePromo from '.'; -import { edOjA, edOjB } from './fixtures'; -import { MEDIA_ARTICLE_PAGE } from '../../../routes/utils/pageTypes'; - -describe('ScrollablePromo', () => { - describe('Mid Page ScrollablePromo', () => { - it('should return null if no data is passed', () => { - const { container } = render(); - expect(container).toBeEmptyDOMElement(); - }); - - it('should render max 3 promo items', () => { - const { getAllByRole } = render( - , - ); - expect(getAllByRole('listitem').length).toEqual(3); - }); - - it('should render single promo item', () => { - const { container } = render(); - expect(container.childElementCount).toEqual(1); - }); - - it('should render single promo item with a title', () => { - const { container, getByTestId } = render( - , - ); - expect(container.childElementCount).toEqual(1); - expect(getByTestId('eoj-recommendations-heading')).toBeInTheDocument(); - }); - - it('should render single promo item without a title', () => { - const { container, queryByTestId } = render( - , - ); - expect(container.childElementCount).toEqual(1); - expect( - queryByTestId('eoj-recommendations-heading'), - ).not.toBeInTheDocument(); - }); - - it('should not render a list when there is only one promo', () => { - const { queryByRole } = render(); - - expect(queryByRole('list')).not.toBeInTheDocument(); - expect(queryByRole('listitem')).not.toBeInTheDocument(); - }); - - it('should render unordered list if more than 1 item', () => { - const { queryByRole, getAllByRole } = render( - , - ); - expect(queryByRole('list')).toBeInTheDocument(); - expect(getAllByRole('listitem').length).toEqual(3); - }); - - describe('event tracking in editorial onward journeys', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should call the view tracking hook with the correct params with one editorial onward journey', () => { - const viewTrackerSpy = jest.spyOn(viewTracking, 'default'); - - render( - , - ); - - expect(viewTrackerSpy).toHaveBeenCalledWith({ - componentName: 'edoj1', - format: 'CHD=edoj', - }); - }); - - it('should call the view tracking hook with the correct params with multiple editorial onward journeys', () => { - const viewTrackerSpy = jest.spyOn(viewTracking, 'default'); - render( - , - ); - render( - , - ); - - expect(viewTrackerSpy).toHaveBeenCalledTimes(4); - expect(viewTrackerSpy).toHaveBeenCalledWith({ - componentName: 'edoj1', - format: 'CHD=edoj', - }); - expect(viewTrackerSpy).toHaveBeenCalledWith({ - componentName: 'edoj2', - format: 'CHD=edoj', - }); - }); - - it('should call the click tracking hook with one editorial onward journey', () => { - const clickTrackerSpy = jest.spyOn(clickTracking, 'default'); - render( - , - ); - - expect(clickTrackerSpy).toHaveBeenCalledWith({ - componentName: 'edoj1', - format: 'CHD=edoj', - }); - }); - - it('should call the click tracking hook with multiple editorial onward journeys', () => { - const clickTrackerSpy = jest.spyOn(clickTracking, 'default'); - render( - , - ); - render( - , - ); - - expect(clickTrackerSpy).toHaveBeenCalledTimes(4); - expect(clickTrackerSpy).toHaveBeenCalledWith({ - componentName: 'edoj1', - format: 'CHD=edoj', - }); - expect(clickTrackerSpy).toHaveBeenCalledWith({ - componentName: 'edoj2', - format: 'CHD=edoj', - }); - }); - }); - - it('it should match a11y snapshot for single card', () => { - const { container } = render(); - expect(container).toMatchSnapshot(); - }); - - it('it should match a11y snapshot for list', () => { - const { container } = render(); - expect(container).toMatchSnapshot(); - }); - - it('it should match a11y snapshot for list with no title', () => { - const { container } = render( - , - ); - expect(container).toMatchSnapshot(); - }); - - it('it should match snapshot when in dark ui mode', () => { - const { container } = render( - , - { - pageType: MEDIA_ARTICLE_PAGE, - }, - ); - expect(container).toMatchSnapshot(); - }); - }); - - describe('OJ Top Bar ScrollablePromo', () => { - it('it should display Top Stories label when experimentVariant is top-bar-top-stories', () => { - const { getByText, queryByText } = render( - , - ); - expect(getByText('Top Stories')).toBeVisible(); - expect(queryByText('Popular Reads')).toBeNull(); - }); - - it('it should display Top Stories label when experimentVariant is read-more-a-and-top-stories', () => { - const { getByText, queryByText } = render( - , - ); - expect(getByText('Top Stories')).toBeVisible(); - expect(queryByText('Popular Reads')).toBeNull(); - }); - - it('it should display Most Read label when experimentVariant is top-bar-most-read', () => { - const { getByText, queryByText } = render( - , - ); - expect(getByText('Popular Reads')).toBeVisible(); - expect(queryByText('Top Stories')).toBeNull(); - }); - - it('it should display 3 promo items with Top Stories when experimentVariant is top-bar-top-stories', () => { - const { getAllByRole } = render( - , - ); - expect(getAllByRole('listitem')).toHaveLength(3); - }); - - it('it should display 5 promo items with Most Read when experimentVariant is top-bar-most-read', () => { - const { getAllByRole } = render( - , - ); - expect(getAllByRole('listitem')).toHaveLength(5); - }); - - it('it should display Top Stories content when experimentVariant is top-bar-top-stories', () => { - const { getAllByRole } = render( - , - ); - const expectedFirstHeadline = - topStoriesBlocks[0].headlines.promoHeadline.blocks[0].model.blocks[0] - .model.text; - expect(getAllByRole('listitem')[0]).toHaveTextContent( - expectedFirstHeadline, - ); - }); - - it('it should display Most Read content when experimentVariant is top-bar-most-read', () => { - const { getAllByRole } = render( - , - ); - const expectedFirstHeadline = mostReadBlocks[0].title; - expect(getAllByRole('listitem')[0]).toHaveTextContent( - expectedFirstHeadline, - ); - }); - }); -}); diff --git a/src/app/legacy/containers/Navigation/index.stories.jsx b/src/app/legacy/containers/Navigation/index.stories.jsx index c80af4e4bbe..f3723da0dda 100644 --- a/src/app/legacy/containers/Navigation/index.stories.jsx +++ b/src/app/legacy/containers/Navigation/index.stories.jsx @@ -3,7 +3,7 @@ import { HOME_PAGE } from '#app/routes/utils/pageTypes'; import { topStoriesBlocks, mostReadBlocks, -} from '../../components/ScrollablePromo/helpers/fixtureData'; +} from '../../../components/ArticleLinksBlock/helpers/fixtureData'; import AmpDecorator from '../../../../../.storybook/helpers/ampDecorator'; import Navigation from '.'; diff --git a/src/app/pages/ArticlePage/ArticlePage.tsx b/src/app/pages/ArticlePage/ArticlePage.tsx index b118859846d..b8ccb724345 100644 --- a/src/app/pages/ArticlePage/ArticlePage.tsx +++ b/src/app/pages/ArticlePage/ArticlePage.tsx @@ -41,7 +41,7 @@ import { import { Translations } from '#app/models/types/translations'; import { Recommendation } from '#app/models/types/onwardJourney'; -import ScrollablePromo from '#components/ScrollablePromo'; +import ArticleLinksBlock from '#app/components/ArticleLinksBlock'; import Recommendations from '#app/components/Recommendations'; import ReadTimeArticle from '#app/components/ReadTime'; import PWAPromotionalBanner from '#app/components/PWAPromotionalBanner'; @@ -281,7 +281,7 @@ const ArticlePage = ({ pageData }: { pageData: Article }) => { embedImages: EmbedImages, embedUploader: Uploader, group: gist, - links: ScrollablePromo, + links: ArticleLinksBlock, mpu: getMpuComponent(allowAdvertising), wsoj: getWsojComponent, disclaimer: DisclaimerWithPaddingOverride, diff --git a/src/app/pages/MediaArticlePage/MediaArticlePage.tsx b/src/app/pages/MediaArticlePage/MediaArticlePage.tsx index d04867e6fdc..36e6bffd6a8 100644 --- a/src/app/pages/MediaArticlePage/MediaArticlePage.tsx +++ b/src/app/pages/MediaArticlePage/MediaArticlePage.tsx @@ -24,7 +24,7 @@ import { } from '../../lib/utilities/parseAssetData'; import filterForBlockType from '../../lib/utilities/blockHandlers'; -import ScrollablePromo from '../../legacy/components/ScrollablePromo'; +import ArticleLinksBlock from '../../components/ArticleLinksBlock'; import headings from '../../legacy/containers/Headings'; import visuallyHiddenHeadline from '../../legacy/containers/VisuallyHiddenHeadline'; @@ -121,7 +121,9 @@ const getBylineComponent = ) : null; -const Links = (props: ComponentToRenderProps) => ; +const Links = (props: ComponentToRenderProps) => ( + +); const getImageComponent = (preloadLeadImageToggle: boolean) => (props: ComponentToRenderProps) => ( diff --git a/ws-nextjs-app/cypress/e2e/articlePage/index.cy.ts b/ws-nextjs-app/cypress/e2e/articlePage/index.cy.ts index c4d717f97af..6ec150ee036 100644 --- a/ws-nextjs-app/cypress/e2e/articlePage/index.cy.ts +++ b/ws-nextjs-app/cypress/e2e/articlePage/index.cy.ts @@ -57,9 +57,9 @@ import { assertSocialEmbedComponentView, } from '../specialFeatures/atiAnalytics/assertions/socialEmbed'; import { - assertScrollablePromoComponentClick, - assertScrollablePromoComponentView, -} from '../specialFeatures/atiAnalytics/assertions/scrollablePromo'; + assertArticleLinksBlockComponentClick, + assertArticleLinksBlockComponentView, +} from '../specialFeatures/atiAnalytics/assertions/articleLinksBlock'; import getPathWithSuffix from '../../support/helpers/getPathWithSuffix'; import { assertLiteSiteSummaryComponentToMainSiteClick } from '../specialFeatures/atiAnalytics/assertions/liteSiteSummary'; @@ -376,8 +376,8 @@ const atiAnalyticsTestSuites = [ assertRelatedContentComponentClick, assertTopStoriesComponentView, assertTopStoriesComponentClick, - assertScrollablePromoComponentClick, - assertScrollablePromoComponentView, + assertArticleLinksBlockComponentClick, + assertArticleLinksBlockComponentView, ], }, { diff --git a/ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/assertions/scrollablePromo.ts b/ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/assertions/articleLinksBlock.ts similarity index 69% rename from ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/assertions/scrollablePromo.ts rename to ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/assertions/articleLinksBlock.ts index f3d6524e146..1af709fbd8c 100644 --- a/ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/assertions/scrollablePromo.ts +++ b/ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/assertions/articleLinksBlock.ts @@ -6,9 +6,9 @@ import { } from '../../../../../../cypress/e2e/specialFeatures/atiAnalytics/assertions'; import { AtiAssertionFnProps } from './type'; -const { SCROLLABLE_PROMO } = COMPONENTS; +const { ARTICLE_LINKS_BLOCK } = COMPONENTS; -export const assertScrollablePromoComponentView = ({ +export const assertArticleLinksBlockComponentView = ({ pageIdentifier, path, applicationType, @@ -19,15 +19,15 @@ export const assertScrollablePromoComponentView = ({ cy.visit(path); // This duplicate line of code has been added intentionally to get cypress to scroll to the bottom. - cy.get('[data-e2e="scrollable-promos"]').first().scrollIntoView({ + cy.get('[data-e2e="article-links-block"]').first().scrollIntoView({ duration: 1000, }); - cy.get('[data-e2e="scrollable-promos"]').first().scrollIntoView({ + cy.get('[data-e2e="article-links-block"]').first().scrollIntoView({ duration: 1000, }); assertATIComponentViewEvent({ - component: SCROLLABLE_PROMO, + component: ARTICLE_LINKS_BLOCK, pageIdentifier, applicationType, siteId, @@ -35,7 +35,7 @@ export const assertScrollablePromoComponentView = ({ }); }; -export const assertScrollablePromoComponentClick = ({ +export const assertArticleLinksBlockComponentClick = ({ pageIdentifier, path, applicationType, @@ -45,15 +45,15 @@ export const assertScrollablePromoComponentClick = ({ interceptATIAnalyticsBeacons(); cy.visit(path); - cy.get('[data-e2e="scrollable-promos"]').first().scrollIntoView({ + cy.get('[data-e2e="article-links-block"]').first().scrollIntoView({ duration: 1000, }); // Click on first item - cy.get('[data-e2e="scrollable-promos"]').find('a').first().click(); + cy.get('[data-e2e="article-links-block"]').find('a').first().click(); assertATIComponentClickEvent({ - component: SCROLLABLE_PROMO, + component: ARTICLE_LINKS_BLOCK, pageIdentifier, applicationType, siteId, diff --git a/ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/helpers/index.ts b/ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/helpers/index.ts index f5089b14a3c..a8542b63999 100644 --- a/ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/helpers/index.ts +++ b/ws-nextjs-app/cypress/e2e/specialFeatures/atiAnalytics/helpers/index.ts @@ -28,7 +28,7 @@ const RECENT_AUDIO_EPISODES = 'episodes-audio'; const PODCAST_LINKS = 'third-party'; const LATEST_MEDIA = 'latest'; const RECOMMENDATIONS = 'midarticle-mostread'; -const SCROLLABLE_PROMO = 'edoj'; +const ARTICLE_LINKS_BLOCK = 'edoj'; const BILLBOARD = 'billboard'; const SOCIAL_EMBED = 'social-consent-banner'; const LIVE_MEDIA = 'live-header-media'; @@ -56,7 +56,7 @@ export const COMPONENTS = { RELATED_CONTENT, RELATED_TOPICS, SCROLLABLE_NAVIGATION, - SCROLLABLE_PROMO, + ARTICLE_LINKS_BLOCK, SHARE, SOCIAL_EMBED, TOP_STORIES,