diff --git a/ab-testing/abTests.ts b/ab-testing/abTests.ts index 913dbd4a226..1f336f8fb9f 100644 --- a/ab-testing/abTests.ts +++ b/ab-testing/abTests.ts @@ -44,6 +44,18 @@ const ABTests: ABTest[] = [ groups: ["control", "variant"], shouldForceMetricsCollection: true, }, + { + name: "thefilter-product-element", + description: + "A hold back test to measure uplift of the product element", + owners: ["thefilter.dev@guardian.co.uk"], + status: "ON", + expirationDate: "2025-12-30", + type: "server", + audienceSize: 0 / 100, + groups: ["control", "variant"], + shouldForceMetricsCollection: false, + }, ]; const activeABtests = ABTests.filter((test) => test.status === "ON"); diff --git a/ab-testing/types.ts b/ab-testing/types.ts index dfbfab8dc2e..8502128c9a5 100644 --- a/ab-testing/types.ts +++ b/ab-testing/types.ts @@ -4,7 +4,7 @@ type AudienceSpace = Map; type AllSpace = Map; -type Team = "commercial" | "webex"; +type Team = "commercial" | "webex" | "thefilter"; type TestName = `${Team}-${string}`; diff --git a/dotcom-rendering/docs/development/ab-testing-in-dcr.md b/dotcom-rendering/docs/development/ab-testing-in-dcr.md index 69262a3ba3e..d2772e3df03 100644 --- a/dotcom-rendering/docs/development/ab-testing-in-dcr.md +++ b/dotcom-rendering/docs/development/ab-testing-in-dcr.md @@ -119,7 +119,7 @@ When your PR is merged, the A/B test will be automatically deployed to Fastly an #### Naming Conventions -A/B tests should be prefixed with the team associated with the test, for example `webex-example-test`. This helps to identify the team responsible for the test and is enforce by typescript validation, you can inspect & edit the allowed team name definitions [here](https://github.com/guardian/dotcom-rendering/blob/main/ab-testing/types.ts#L9). +A/B tests should be prefixed with the team associated with the test, for example `webex-example-test`. This helps to identify the team responsible for the test and is enforced by typescript validation, you can inspect & edit the allowed team name definitions [here](https://github.com/guardian/dotcom-rendering/blob/main/ab-testing/types.ts#L9). #### Test Size and Groups @@ -135,7 +135,7 @@ All requests are processed by Fastly at the edge, however, A/B testing of server Ensure that the `type` field is set to either `client` or `server` to indicate the type of test so that server side tests can be cached correctly, and client side tests are not splitting the cache unnecessarily. -There's a limit of the number of concurrent server-side tests that can be run, enforce by the validation script, so it's important to use client-side tests where possible. +There's a limit of the number of concurrent server-side tests that can be run, enforced by the validation script, so it's important to use client-side tests where possible. #### Test Expiration @@ -178,13 +178,13 @@ const someComponent = () => { const abTests = useBetaAB(); // Am I in the test at all? - const isInTest = abTests?.isUserInTest('AbTestTest') ?? false; + const isInTest = abTests?.isUserInTest('webex-example-test') ?? false; const isInControlGroup = - (abTests?.isUserInTestGroup('AbTestTest', 'control') ?? false); + (abTests?.isUserInTestGroup('webex-example-test', 'control') ?? false); const isInVariantGroup = - abTests?.isUserInTestGroup('AbTestTest', 'variant') ?? false; + abTests?.isUserInTestGroup('webex-example-test', 'variant') ?? false; if (isInControlGroup) { return ( @@ -223,16 +223,16 @@ const abTests = useBetaAB(); // Get all of the user's server/client-side A/B test participations const abTestParticipations = abTests?.getParticipations(); // EG. { commercial-dev-client-side-test: 'variant', commercial-dev-server-side-test: 'variant' } -// Is user in the AbTestTest test (any cohort) -const isInTest = abTests?.isUserInTest('AbTestTest') ?? false; +// Is user in the webex-example-test test (any cohort) +const isInTest = abTests?.isUserInTest('webex-example-test') ?? false; -// Is user in the AbTestTest test (control cohort) +// Is user in the webex-example-test test (control cohort) const isInControlGroup = - abTests?.isUserInTestGroup('AbTestTest', 'control') ?? false; + abTests?.isUserInTestGroup('webex-example-test', 'control') ?? false; -// Is user in the AbTestTest test (variant cohort) +// Is user in the webex-example-test test (variant cohort) const isInVariantGroup = - abTests?.isUserInTestGroup('AbTestTest', 'variant') ?? false; + abTests?.isUserInTestGroup('webex-example-test', 'variant') ?? false; ``` #### On the Client diff --git a/dotcom-rendering/src/components/ProductElement.tsx b/dotcom-rendering/src/components/ProductElement.tsx index 7a465580254..c15397e68e5 100644 --- a/dotcom-rendering/src/components/ProductElement.tsx +++ b/dotcom-rendering/src/components/ProductElement.tsx @@ -4,6 +4,7 @@ import type { ReactNode } from 'react'; import type { ArticleFormat } from '../lib/articleFormat'; import { parseHtml } from '../lib/domUtils'; import type { NestedArticleElement } from '../lib/renderElement'; +import { useBetaAB } from '../lib/useAB'; import type { ProductBlockElement } from '../types/content'; import { ProductCardInline } from './ProductCardInline'; import { ProductCardLeftCol } from './ProductCardLeftCol'; @@ -39,12 +40,22 @@ export const ProductElement = ({ format: ArticleFormat; shouldShowLeftColCard: boolean; }) => { + const abTests = useBetaAB(); + const isInHoldBackTestVariant = + abTests?.isUserInTestGroup('thefilter-product-element', 'variant') ?? + false; + const showContent = product.displayType === 'InlineOnly' || product.displayType === 'InlineWithProductCard'; + // In the hold back test variant, if the product element has a display type of ProductCardOnly, + // we should still render the product card. This is because there may not be any suitable + // nested content to render, which could result in some unintended display issues. For the + // InlineWithProductCard display type, we won't render the cards in the hold back test. const showProductCard = product.displayType === 'ProductCardOnly' || - product.displayType === 'InlineWithProductCard'; + (!isInHoldBackTestVariant && + product.displayType === 'InlineWithProductCard'); return ( <> {showContent && ( @@ -52,7 +63,9 @@ export const ProductElement = ({ product={product} format={format} ArticleElementComponent={ArticleElementComponent} - shouldShowLeftColCard={shouldShowLeftColCard} + shouldShowLeftColCard={ + shouldShowLeftColCard && !isInHoldBackTestVariant + } /> )} {showProductCard && (