From fb812b8079be60fffa8e1848e8569269d0b8b0de Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Wed, 16 Sep 2026 15:05:39 +0100 Subject: [PATCH 1/3] Change additionalSizes for article-end header bidding integration and add 0% test --- ab-testing/config/abTests.ts | 13 +++++++++++++ .../src/components/SlotBodyEnd.island.tsx | 10 ++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/ab-testing/config/abTests.ts b/ab-testing/config/abTests.ts index 4e188b70bfd..f3f2af9dbe2 100644 --- a/ab-testing/config/abTests.ts +++ b/ab-testing/config/abTests.ts @@ -333,6 +333,19 @@ const ABTests: ABTest[] = [ ], shouldForceMetricsCollection: true, }, + { + name: "commercial-article-end-header-bidding", + description: + "Test opening up the article-end ad slot in the US region for HeaderBidding", + owners: ["commercial.dev@guardian.co.uk"], + expirationDate: "2026-10-01", + type: "client", + status: "ON", + audienceSize: 0 / 100, + audienceSpace: "B", + groups: ["control", "variant"], + shouldForceMetricsCollection: true, + }, ]; const activeABtests = ABTests.filter((test) => test.status === "ON"); diff --git a/dotcom-rendering/src/components/SlotBodyEnd.island.tsx b/dotcom-rendering/src/components/SlotBodyEnd.island.tsx index 115b9326d88..47d4ce90fce 100644 --- a/dotcom-rendering/src/components/SlotBodyEnd.island.tsx +++ b/dotcom-rendering/src/components/SlotBodyEnd.island.tsx @@ -56,6 +56,7 @@ type Props = { const slotStyles = css` color: ${palette.neutral[7]}; + margin: 12px auto; `; const buildReaderRevenueEpicConfig = ( @@ -130,10 +131,9 @@ export const SlotBodyEnd = ({ const [asyncArticleCount, setAsyncArticleCount] = useState>(); - const showPublicGood = countryCode === 'US'; + const isInUS = countryCode === 'US'; - const showArticleEndSlot = - renderAds && !isLabs && showPublicGood && articleEndSlot; + const showArticleEndSlot = renderAds && !isLabs && isInUS && articleEndSlot; useEffect(() => { setAsyncArticleCount( @@ -238,7 +238,9 @@ export const SlotBodyEnd = ({ new CustomEvent('gu.commercial.slot.fill', { detail: { slotId: 'dfp-ad--article-end', - additionalSizes: { mobile: [adSizes.fluid] }, // Public Good additional ad slot sizes + additionalSizes: { + mobile: [adSizes.mpu], + }, }, }), ); From 6ef0f1a03b21e76011f2f5f76282565b7478739a Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Wed, 16 Sep 2026 15:32:26 +0100 Subject: [PATCH 2/3] Add condition for variant 0% test --- .../src/components/SlotBodyEnd.island.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dotcom-rendering/src/components/SlotBodyEnd.island.tsx b/dotcom-rendering/src/components/SlotBodyEnd.island.tsx index 47d4ce90fce..59e7ab7891b 100644 --- a/dotcom-rendering/src/components/SlotBodyEnd.island.tsx +++ b/dotcom-rendering/src/components/SlotBodyEnd.island.tsx @@ -132,8 +132,17 @@ export const SlotBodyEnd = ({ useState>(); const isInUS = countryCode === 'US'; + const isInArticleEndHeaderBiddingTest = abTests?.isUserInTestGroup( + 'commercial-article-end-header-bidding', + 'variant', + ); - const showArticleEndSlot = renderAds && !isLabs && isInUS && articleEndSlot; + const showArticleEndSlot = + renderAds && + !isLabs && + isInUS && + articleEndSlot && + isInArticleEndHeaderBiddingTest; useEffect(() => { setAsyncArticleCount( From 992962da41dc7db347fddbde9ecc026fc3641ab1 Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Wed, 16 Sep 2026 15:46:54 +0100 Subject: [PATCH 3/3] Update unit tests based on the changes --- .../src/components/SlotBodyEnd.island.test.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dotcom-rendering/src/components/SlotBodyEnd.island.test.tsx b/dotcom-rendering/src/components/SlotBodyEnd.island.test.tsx index 808dff415c6..db5d9b54231 100644 --- a/dotcom-rendering/src/components/SlotBodyEnd.island.test.tsx +++ b/dotcom-rendering/src/components/SlotBodyEnd.island.test.tsx @@ -1,5 +1,6 @@ import { render, waitFor } from '@testing-library/react'; import { pickMessage } from '../lib/messagePicker'; +import { useAB } from '../lib/useAB'; import { useCountryCode } from '../lib/useCountryCode'; import { ConfigProvider } from './ConfigContext'; import { SlotBodyEnd } from './SlotBodyEnd.island'; @@ -34,7 +35,9 @@ jest.mock('../lib/useBraze', () => ({ })); jest.mock('../lib/useAB', () => ({ - useAB: jest.fn().mockReturnValue(null), + useAB: jest.fn().mockReturnValue({ + isUserInTestGroup: jest.fn().mockReturnValue(false), + }), })); jest.mock('../lib/braze/BrazeBannersSystem', () => ({ @@ -95,6 +98,15 @@ const renderSlotBodyEnd = (props: Partial = {}) => const mockPickMessage = jest.mocked(pickMessage); const mockUseCountryCode = jest.mocked(useCountryCode); +const mockUseAB = jest.mocked(useAB); + +const mockInArticleEndHeaderBiddingTest = () => { + mockUseAB.mockReturnValue({ + isUserInTestGroup: (testId: string, groupId: string) => + testId === 'commercial-article-end-header-bidding' && + groupId === 'variant', + } as ReturnType); +}; describe('SlotBodyEnd', () => { afterEach(() => { @@ -134,8 +146,8 @@ describe('SlotBodyEnd', () => { type: 'NoMessageSelected', }); - // showPublicGood requires countryCode === 'US' mockUseCountryCode.mockReturnValue('US'); + mockInArticleEndHeaderBiddingTest(); const { findByTestId } = renderSlotBodyEnd({ renderAds: true, @@ -151,6 +163,7 @@ describe('SlotBodyEnd', () => { }); mockUseCountryCode.mockReturnValue('US'); + mockInArticleEndHeaderBiddingTest(); const dispatchEventSpy = jest.spyOn(document, 'dispatchEvent');