@@ -769,6 +772,9 @@ export const FeatureCard = ({
shouldRaiseZIndexForAbTest={
isLoopAndInLoopClickTestVariant
}
+ headlineTestUuid={
+ headlineTestUuid
+ }
/>
)}
diff --git a/dotcom-rendering/src/components/FlexibleGeneral.tsx b/dotcom-rendering/src/components/FlexibleGeneral.tsx
index 82e2bee2faa..cde38b02a64 100644
--- a/dotcom-rendering/src/components/FlexibleGeneral.tsx
+++ b/dotcom-rendering/src/components/FlexibleGeneral.tsx
@@ -141,6 +141,7 @@ const ImmersiveCardLayout = ({
isImmersive={true}
starRatingSize="medium"
articleMedia={card.articleMedia}
+ headlineTestUuid={card.headlineTestUuid}
/>
diff --git a/dotcom-rendering/src/components/FrontCard.tsx b/dotcom-rendering/src/components/FrontCard.tsx
index ea9bad0d677..930629a12e6 100644
--- a/dotcom-rendering/src/components/FrontCard.tsx
+++ b/dotcom-rendering/src/components/FrontCard.tsx
@@ -59,6 +59,7 @@ export const FrontCard = (props: Props) => {
starRating: trail.starRating,
uniqueId: trail.uniqueId,
webPublicationDate: trail.webPublicationDate,
+ headlineTestUuid: trail.headlineTestUuid,
};
return Card({ ...defaultProps, ...cardProps });
diff --git a/dotcom-rendering/src/components/Masthead/HighlightsCard.tsx b/dotcom-rendering/src/components/Masthead/HighlightsCard.tsx
index 57279975859..786f2a43e41 100644
--- a/dotcom-rendering/src/components/Masthead/HighlightsCard.tsx
+++ b/dotcom-rendering/src/components/Masthead/HighlightsCard.tsx
@@ -37,6 +37,7 @@ export type HighlightsCardProps = {
byline?: string;
isExternalLink: boolean;
starRating?: Rating;
+ headlineTestUuid?: string;
};
const container = css`
@@ -135,6 +136,7 @@ export const HighlightsCard = ({
isExternalLink,
starRating,
articleMedia,
+ headlineTestUuid,
}: HighlightsCardProps) => {
const isMediaCard = isMedia(format);
@@ -154,6 +156,7 @@ export const HighlightsCard = ({
isExternalLink={isExternalLink}
isLoopAndInLoopClickTest={false}
shouldRaiseZIndexForAbTest={false}
+ headlineTestUuid={headlineTestUuid}
/>
diff --git a/dotcom-rendering/src/components/ScrollableFeature.island.tsx b/dotcom-rendering/src/components/ScrollableFeature.island.tsx
index 4a23a22de8f..9df79e8452c 100644
--- a/dotcom-rendering/src/components/ScrollableFeature.island.tsx
+++ b/dotcom-rendering/src/components/ScrollableFeature.island.tsx
@@ -91,6 +91,7 @@ export const ScrollableFeature = ({
showQuotes={card.showQuotedHeadline}
starRatingSize={'small'}
articleMedia={card.articleMedia}
+ headlineTestUuid={card.headlineTestUuid}
/>
))}
diff --git a/dotcom-rendering/src/components/ScrollableHighlights.island.tsx b/dotcom-rendering/src/components/ScrollableHighlights.island.tsx
index e98a44673ed..65f33f9a4c9 100644
--- a/dotcom-rendering/src/components/ScrollableHighlights.island.tsx
+++ b/dotcom-rendering/src/components/ScrollableHighlights.island.tsx
@@ -341,6 +341,7 @@ export const ScrollableHighlights = ({ trails, frontId }: Props) => {
mainMedia={trail.mainMedia}
starRating={trail.starRating}
articleMedia={trail.articleMedia}
+ headlineTestUuid={trail.headlineTestUuid}
/>
)}
diff --git a/dotcom-rendering/src/components/StaticFeatureTwo.tsx b/dotcom-rendering/src/components/StaticFeatureTwo.tsx
index 05d73a0c092..dd8e149d611 100644
--- a/dotcom-rendering/src/components/StaticFeatureTwo.tsx
+++ b/dotcom-rendering/src/components/StaticFeatureTwo.tsx
@@ -80,6 +80,7 @@ export const StaticFeatureTwo = ({
showQuotes={card.showQuotedHeadline}
starRatingSize={'medium'}
articleMedia={card.articleMedia}
+ headlineTestUuid={card.headlineTestUuid}
/>
);
diff --git a/dotcom-rendering/src/components/SupportingContent.tsx b/dotcom-rendering/src/components/SupportingContent.tsx
index 5c5a6f75e4e..db040c2f679 100644
--- a/dotcom-rendering/src/components/SupportingContent.tsx
+++ b/dotcom-rendering/src/components/SupportingContent.tsx
@@ -186,6 +186,7 @@ export const SupportingContent = ({
: verticalSublinkStyles,
]}
data-link-name={`sublinks | ${index + 1}`}
+ data-fronts-test-uuid={subLink.headlineTestUuid}
>
{
});
});
- describe('decideHeadline', () => {
+ describe('getEditorialTestData', () => {
const cardWithNoEditorialTest = {
properties: {
isBreaking: false,
@@ -667,26 +667,31 @@ describe('Enhance Cards', () => {
supportingContent: [cardWithExpiredEditorialTest],
};
- it('returns the default headline if no editorial test exists on the card, page is not in allowed fronts list, and user is not in a test bucket', () => {
+ it('returns undefined if no editorial test exists on the card, page is not in allowed fronts list, and user is not in a test bucket', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithNoEditorialTest,
{},
true,
'invalid-test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
- it('returns the default headline if editorial test exists and page is in allowed fronts list, but user is not in a test bucket', () => {
+ it('returns undefined if editorial test exists and page is in allowed fronts list, but user is not in a test bucket', () => {
expect(
- decideHeadline(cardWithEditorialTest, {}, true, 'test-front'),
- ).toEqual('Headline');
+ getEditorialTestData(
+ cardWithEditorialTest,
+ {},
+ true,
+ 'test-front',
+ ),
+ ).toEqual(undefined);
});
- it('returns the default headline if user is in a test bucket and page is in allowed fronts list, but editorial test does not exist', () => {
+ it('returns undefined if user is in a test bucket and page is in allowed fronts list, but editorial test does not exist', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithNoEditorialTest,
{
'fronts-and-curation-editorial-test': 'a',
@@ -694,12 +699,12 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
- it('returns the default headline if editorial test exists and user is in a test bucket, but page is not in allowed fronts list', () => {
+ it('returns undefined if editorial test exists and user is in a test bucket, but page is not in allowed fronts list', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithEditorialTest,
{
'fronts-and-curation-editorial-test': 'a',
@@ -707,12 +712,12 @@ describe('Enhance Cards', () => {
true,
'invalid-test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
- it('returns the default headline if editorial test exists, page is in allowed fronts list, user is in a variant bucket, but the feature switch is turned off ', () => {
+ it('returns undefined if editorial test exists, page is in allowed fronts list, user is in a variant bucket, but the feature switch is turned off ', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithEditorialTest,
{
'fronts-and-curation-editorial-test': 'a',
@@ -720,12 +725,12 @@ describe('Enhance Cards', () => {
false,
'test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
- it('returns headline A if editorial test exists, page is in allowed fronts list, and user is in bucket A', () => {
+ it('returns headline A & test uuid if editorial test exists, page is in allowed fronts list, and user is in bucket A', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithEditorialTest,
{
'fronts-and-curation-editorial-test': 'a',
@@ -733,12 +738,12 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline A');
+ ).toEqual({ headline: 'Headline A', uuid: 'uuid' });
});
- it('returns headline B if editorial test exists, page is in allowed fronts list, and user is in bucket B', () => {
+ it('returns headline B & test uuid if editorial test exists, page is in allowed fronts list, and user is in bucket B', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithEditorialTest,
{
'fronts-and-curation-editorial-test': 'b',
@@ -746,12 +751,12 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline B');
+ ).toEqual({ headline: 'Headline B', uuid: 'uuid' });
});
- it('returns the default headline if the bucket name does not match a variant meta id', () => {
+ it('returns undefined if the bucket name does not match a variant meta id', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithEditorialTest,
{
'fronts-and-curation-editorial-test': 'c',
@@ -759,12 +764,12 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
- it('returns the default headline if the variant headline is undefined', () => {
+ it('returns undefined if the variant headline is undefined', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithEditorialTestWithUndefinedVariantMeta,
{
'fronts-and-curation-editorial-test': 'a',
@@ -772,12 +777,12 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
- it('returns the default headline if an editorial test has expired', () => {
+ it('returns undefined if an editorial test has expired', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithExpiredEditorialTest,
{
'fronts-and-curation-editorial-test': 'a',
@@ -785,12 +790,12 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
- it('returns the default headline if an editorial test has been manually ended', () => {
+ it('returns undefined if an editorial test has been manually ended', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithManuallyEndedEditorialTest,
{
'fronts-and-curation-editorial-test': 'a',
@@ -798,12 +803,12 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
- it('returns the variant headline if an editorial test is present on a sublink', () => {
+ it('returns the variant headline & test uuid if an editorial test is present on a sublink', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithSublinkWithEditorialTest
.supportingContent[0] as FESupportingContent,
{
@@ -812,12 +817,12 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline A');
+ ).toEqual({ headline: 'Headline A', uuid: 'uuid' });
});
- it('returns the default headline for a sublink if an editorial test is expired on a sublink', () => {
+ it('returns undefined for a sublink if an editorial test is expired on a sublink', () => {
expect(
- decideHeadline(
+ getEditorialTestData(
cardWithSublinkWithExpiredEditorialTest
.supportingContent[0] as FESupportingContent,
{
@@ -826,7 +831,7 @@ describe('Enhance Cards', () => {
true,
'test-front',
),
- ).toEqual('Headline');
+ ).toEqual(undefined);
});
});
});
diff --git a/dotcom-rendering/src/model/enhanceCards.ts b/dotcom-rendering/src/model/enhanceCards.ts
index 97b64535893..5dde8bf48f1 100644
--- a/dotcom-rendering/src/model/enhanceCards.ts
+++ b/dotcom-rendering/src/model/enhanceCards.ts
@@ -62,6 +62,12 @@ const enhanceSupportingContent = (
url: decideUrl(subLink),
kickerText:
!kickerText && supportingContentIsLive ? 'Live' : kickerText,
+ headlineTestUuid: findHeadlineTestUuid(
+ subLink,
+ serverSideABTests,
+ isEditorialABTestingEnabled,
+ pageId,
+ ),
};
});
};
@@ -212,46 +218,99 @@ const findActiveEditorialTest = (
return tests?.find((test) => isActiveEditorialTest(test));
};
+type EditorialTestData = {
+ headline: string;
+ uuid: string;
+};
+
/**
- * Decide the headline to be shown for a given card. If there is an active editorial test on a card,
- * return the variant headline matching the user test group. Otherwise, return the default headline
+ * Centralises the logic used by both the decideHeadline and findHeadlineTestUuid functions. Makes sure that
+ * the the testing switch is enabled, the page is in the test bucket, the test can run on the given front,
+ * and that a valid variant headline is defined before returning the variant headline and test UUID.
*/
-export const decideHeadline = (
+export const getEditorialTestData = (
faciaCard: FEFrontCard | FESupportingContent,
serverSideABTests: Record,
isEditorialABTestingEnabled: boolean,
pageId?: string,
-): string => {
- const defaultHeadline = faciaCard.header.headline;
-
- const testBucket = serverSideABTests['fronts-and-curation-editorial-test'];
-
+): EditorialTestData | undefined => {
const activeEditorialTest = findActiveEditorialTest(
faciaCard.properties.tests,
);
- if (
- !isEditorialABTestingEnabled ||
- isUndefined(testBucket) ||
- !activeEditorialTest
- ) {
- return defaultHeadline;
+ // don't return data if there is no active test on the card or editorial testing is switched off
+ if (!activeEditorialTest || !isEditorialABTestingEnabled) {
+ return undefined;
}
const testCanRunOnPage =
!isUndefined(pageId) &&
activeEditorialTest.frontsThisTestCanRunOn.includes(pageId);
- if (!testCanRunOnPage) return defaultHeadline;
+ // don't return data if test cannot run on the current front
+ if (!testCanRunOnPage) return undefined;
+
+ const testBucket = serverSideABTests['fronts-and-curation-editorial-test'];
+
+ // don't return data if the pageview is not in the editorial test bucket
+ if (isUndefined(testBucket)) {
+ return undefined;
+ }
const variantMeta = activeEditorialTest.variantMeta.find(
(variant) => variant.id.toLowerCase() === testBucket,
);
// make sure the variant headline isn't undefined and that it is of type string
- if (typeof variantMeta?.meta.headline !== 'string') return defaultHeadline;
+ if (typeof variantMeta?.meta.headline !== 'string') return undefined;
+
+ return {
+ headline: variantMeta.meta.headline,
+ uuid: activeEditorialTest.testUuid,
+ };
+};
+
+/**
+ * Decide the headline to be shown for a given card. If there is an active editorial test on a card,
+ * return the variant headline matching the user test group. Otherwise, return the default headline
+ */
+export const decideHeadline = (
+ faciaCard: FEFrontCard | FESupportingContent,
+ serverSideABTests: Record,
+ isEditorialABTestingEnabled: boolean,
+ pageId?: string,
+): string => {
+ const editorialTestData = getEditorialTestData(
+ faciaCard,
+ serverSideABTests,
+ isEditorialABTestingEnabled,
+ pageId,
+ );
+
+ if (isUndefined(editorialTestData)) return faciaCard.header.headline;
+
+ return editorialTestData.headline;
+};
+
+/**
+ * Find the UUID of a headline test if one is running on the card
+ */
+export const findHeadlineTestUuid = (
+ faciaCard: FEFrontCard | FESupportingContent,
+ serverSideABTests: Record,
+ isEditorialABTestingEnabled: boolean,
+ pageId?: string,
+): string | undefined => {
+ const editorialTestData = getEditorialTestData(
+ faciaCard,
+ serverSideABTests,
+ isEditorialABTestingEnabled,
+ pageId,
+ );
+
+ if (isUndefined(editorialTestData)) return undefined;
- return variantMeta.meta.headline;
+ return editorialTestData.uuid;
};
/**
@@ -596,5 +655,11 @@ export const enhanceCards = (
?.allImages[0]?.fields.altText ?? '',
},
}),
+ headlineTestUuid: findHeadlineTestUuid(
+ faciaCard,
+ serverSideABTests,
+ isEditorialABTestingEnabled,
+ pageId,
+ ),
};
});
diff --git a/dotcom-rendering/src/types/front.ts b/dotcom-rendering/src/types/front.ts
index d69e654cd0c..79cc7c114bb 100644
--- a/dotcom-rendering/src/types/front.ts
+++ b/dotcom-rendering/src/types/front.ts
@@ -106,6 +106,7 @@ export type DCRFrontCard = {
uniqueId?: string;
serverTime?: number;
articleMedia?: ArticleMedia;
+ headlineTestUuid?: string;
};
export type DCRSlideshowImage = {
@@ -153,6 +154,7 @@ export type DCRSupportingContent = {
url?: string;
kickerText?: string;
format: ArticleFormat;
+ headlineTestUuid?: string;
};
export type TreatType = {