Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 2 additions & 14 deletions dotcom-rendering/.storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AB } from '@guardian/ab-core';
import { setCookie, storage } from '@guardian/libs';
import { resets } from '@guardian/source/foundations';
import { palette as sourcePalette } from '@guardian/source/foundations';
Expand All @@ -12,6 +11,7 @@ import { Lazy } from '../src/components/Lazy';
import { Picture } from '../src/components/Picture';
import { rawFontsCss } from '../src/lib/fonts-css';
import { mockFetch } from '../src/lib/mockRESTCalls';
import { ABTests } from '../src/experiments/lib/ab-tests';
import { setABTests } from '../src/lib/useAB';
import { ConfigContextDecorator } from './decorators/configContextDecorator';
import {
Expand Down Expand Up @@ -42,19 +42,7 @@ global.fetch = mockFetch;
// Fix the date to prevent false negatives
MockDate.set('Sat Jan 1 2022 12:00:00 GMT+0000 (Greenwich Mean Time)');

setABTests({
api: new AB({
mvtMaxValue: 1_000_000,
mvtId: 1234,
pageIsSensitive: false,
abTestSwitches: {},
arrayOfTestObjects: [],
serverSideTests: {},
ophanRecord: () => {},
errorReporter: () => {},
}),
participations: {},
});
setABTests(new ABTests({ isServer: true, serverSideABTests: {} }));

// Add base css for the site
const css = `${rawFontsCss}${resets.resetCSS}`;
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ We recommend you update your workspace settings to automatically fix formatting
| <img alt="Chromatic" src="./docs/images/logo-chromatic.jpg" width="350" /> | [Chromatic](https://www.chromatic.com/) is a visual regression testing tool that tests our Storybook components at PR time. |
| <img alt="Jest" src="./docs/images/logo-jest.jpg" width="350" /> | [Jest](https://jestjs.io) is a unit testing tool. You will find Jest tests in the repo with `.test.` filenames. |
| <img alt="Playwright" src="./docs/images/logo-playwright.svg" width="350" /> | [Playwright](https://playwright.dev/) is an integration testing tool that runs tests in the browser. You will find the Playwright tests in the [playwright directory](./playwright). |
| <img alt="AB Testing" src="./docs/images/logo-ab-testing.png" width="350" /> | The [A/B Testing library](https://github.com/guardian/csnx/tree/main/libs/@guardian/ab-core) is an internal NPM Module. There are [docs here](./docs/development/ab-testing-in-dcr.md). |
| <img alt="AB Testing" src="./docs/images/logo-ab-testing.png" width="350" /> | The A/B Testing framework is developed in-house. There are [docs here](./docs/development/ab-testing-in-dcr.md). |
| <img alt="Deno" title="Deno logo, MIT License: https://deno.land/artwork" src="./docs/images/logo-deno.svg" width="350" /> | [Deno](https://deno.land/) is a JavaScript runtime that we've started incorporating into some of our Github Actions workflows. You will only need to install it if you are planning to run the workflow scripts locally. Some installation and troubleshooting instructions can be found in the [Deno scripts folder](../scripts/deno/README.md). |

## Concepts
Expand Down
2 changes: 0 additions & 2 deletions dotcom-rendering/docs/development/ab-testing-in-dcr.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

This documentation covers the updated A/B test framework, developed by commercial-dev to support both client and server side A/B tests in DCR and launched in January 2026. If you're interested in how it works please visit the docs [here](https://github.com/guardian/dotcom-rendering/tree/main/ab-testing).

Instructions for the legacy framework can still be found [here](./legacy-ab-testing-in-dcr.md).

## Creating a new A/B test

### 1. Configure your A/B test
Expand Down
80 changes: 0 additions & 80 deletions dotcom-rendering/docs/development/legacy-ab-testing-in-dcr.md

This file was deleted.

1 change: 0 additions & 1 deletion dotcom-rendering/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"@emotion/cache": "11.14.0",
"@emotion/react": "11.14.0",
"@emotion/server": "11.11.0",
"@guardian/ab-core": "8.0.0",
"@guardian/ab-testing-config": "workspace:ab-testing-config",
"@guardian/braze-components": "22.2.0",
"@guardian/bridget": "8.11.0",
Expand Down
4 changes: 2 additions & 2 deletions dotcom-rendering/src/components/AdmiralScript.island.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { cmp } from '@guardian/consent-manager';
import { getCookie, log } from '@guardian/libs';
import { useEffect } from 'react';
import { getOphan } from '../client/ophan/ophan';
import { useBetaAB } from '../lib/useAB';
import { useAB } from '../lib/useAB';
import { useConfig } from './ConfigContext';

const testName = 'growth-admiral-adblock-detect';
Expand Down Expand Up @@ -210,7 +210,7 @@ const setUpAdmiralEventLogger = (

export const AdmiralScript = () => {
const { renderingTarget } = useConfig();
const abTests = useBetaAB();
const abTests = useAB();
const isInVariantDetectGroup =
abTests?.isUserInTestGroup(testName, 'variant-detect') ?? false;
const variantName = isInVariantDetectGroup
Expand Down
7 changes: 0 additions & 7 deletions dotcom-rendering/src/components/ArticlePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { DecideLayout } from '../layouts/DecideLayout';
import { buildAdTargeting } from '../lib/ad-targeting';
import { ArticleDesign } from '../lib/articleFormat';
import { rootStyles } from '../lib/rootStyles';
import { filterABTestSwitches } from '../model/enhance-switches';
import type { NavType } from '../model/extract-nav';
import type { Article } from '../types/article';
import type { RenderingTarget } from '../types/renderingTarget';
Expand Down Expand Up @@ -132,12 +131,6 @@ export const ArticlePage = (props: WebProps | AppProps) => {
</Island>
<Island priority="critical">
<SetABTests
abTestSwitches={filterABTestSwitches(
frontendData.config.switches,
)}
pageIsSensitive={frontendData.config.isSensitive}
isDev={!!frontendData.config.isDev}
serverSideTests={frontendData.config.abTests}
serverSideABTests={
frontendData.config.serverSideABTests
}
Expand Down
4 changes: 2 additions & 2 deletions dotcom-rendering/src/components/DirectoryPageNav.island.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { grid } from '../grid';
import { getInteractionClient } from '../lib/bridgetApi';
import { generateImageURL } from '../lib/image';
import { useBetaAB } from '../lib/useAB';
import { useAB } from '../lib/useAB';
import { worldCup2026PageIds } from '../lib/worldCup2026';
import {
WorldCup2026Icon,
Expand Down Expand Up @@ -254,7 +254,7 @@ export const DirectoryPageNav = ({ pageId, pageTags }: Props) => {

const isApps = renderingTarget === 'Apps';

const ab = useBetaAB();
const ab = useAB();

const config = configs.find(
(cfg) =>
Expand Down
8 changes: 4 additions & 4 deletions dotcom-rendering/src/components/DirectoryPageNav.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { allModes } from '../../.storybook/modes';
import preview from '../../.storybook/preview';
import { BetaABTests } from '../experiments/lib/beta-ab-tests';
import { setBetaABTests } from '../lib/useAB';
import { ABTests } from '../experiments/lib/ab-tests';
import { setABTests } from '../lib/useAB';
import { ConfigProvider } from './ConfigContext';
import { DirectoryPageNav } from './DirectoryPageNav.island';

const mockAB = new BetaABTests({
const mockAB = new ABTests({
isServer: true,
serverSideABTests: {
'webx-world-cup-2026-subnav': 'enable',
},
});
setBetaABTests(mockAB);
setABTests(mockAB);

const meta = preview.meta({
component: DirectoryPageNav,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
AB_TEST_NAME,
NEWSLETTER_SIGNUP_COMPONENT_ID,
} from '../lib/newsletterSignupTracking';
import { useBetaAB } from '../lib/useAB';
import { useAB } from '../lib/useAB';
import { useIsSignedIn } from '../lib/useAuthStatus';
import { useNewsletterSubscription } from '../lib/useNewsletterSubscription';
import { ConfigProvider } from './ConfigContext';
Expand All @@ -16,7 +16,7 @@ jest.mock('../client/ophan/ophan', () => ({
}));

jest.mock('../lib/useAB', () => ({
useBetaAB: jest.fn(),
useAB: jest.fn(),
}));

jest.mock('../lib/useAuthStatus', () => ({
Expand Down Expand Up @@ -87,7 +87,7 @@ const renderWrapper = (props = {}, renderingTarget: 'Web' | 'Apps' = 'Web') =>
);

const mockAbTests = (isInVariant: boolean) => {
(useBetaAB as jest.Mock).mockReturnValue({
(useAB as jest.Mock).mockReturnValue({
isUserInTestGroup: (_testName: string, group: string) =>
group === 'variant' ? isInVariant : !isInVariant,
});
Expand All @@ -97,7 +97,7 @@ describe('EmailSignUpWrapper', () => {
beforeEach(() => {
jest.resetAllMocks();
// Default: AB API not yet hydrated
(useBetaAB as jest.Mock).mockReturnValue(undefined);
(useAB as jest.Mock).mockReturnValue(undefined);
(useIsSignedIn as jest.Mock).mockReturnValue(false);
(useNewsletterSubscription as jest.Mock).mockReturnValue(false);
});
Expand Down Expand Up @@ -137,7 +137,7 @@ describe('EmailSignUpWrapper', () => {

describe('flag on (showNewNewsletterSignupCard = true)', () => {
it('shows a placeholder when AB API has not hydrated yet', () => {
// useBetaAB returns undefined before hydration — component shows
// useAB returns undefined before hydration — component shows
// Placeholder rather than committing to control or variant early.
// (default set in outer beforeEach, no override needed)
renderWrapper({ showNewNewsletterSignupCard: true });
Expand Down Expand Up @@ -187,7 +187,7 @@ describe('EmailSignUpWrapper', () => {

describe('Apps rendering target', () => {
it('renders the legacy EmailSignup without waiting for AB to resolve', () => {
// useBetaAB remains undefined (AB framework never initialises on Apps)
// useAB remains undefined (AB framework never initialises on Apps)
// but the component should not block on it
renderWrapper({ showNewNewsletterSignupCard: true }, 'Apps');
expect(screen.getByTestId('email-signup')).toBeInTheDocument();
Expand Down Expand Up @@ -280,7 +280,7 @@ describe('EmailSignUpWrapper', () => {
});

it('does not fire a VIEW event while the AB client has not hydrated', () => {
// useBetaAB returns undefined — default set in beforeEach
// useAB returns undefined — default set in beforeEach
renderWrapper({ showNewNewsletterSignupCard: true });

expect(submitComponentEvent).not.toHaveBeenCalled();
Expand Down
4 changes: 2 additions & 2 deletions dotcom-rendering/src/components/EmailSignUpWrapper.island.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
NEWSLETTER_SIGNUP_COMPONENT_ID,
sendNewsletterSignupEvent,
} from '../lib/newsletterSignupTracking';
import { useBetaAB } from '../lib/useAB';
import { useAB } from '../lib/useAB';
import { useIsSignedIn } from '../lib/useAuthStatus';
import { useNewsletterSubscription } from '../lib/useNewsletterSubscription';
import { useConfig } from './ConfigContext';
Expand Down Expand Up @@ -78,7 +78,7 @@ export const EmailSignUpWrapper = ({
const abTestEnabled =
showNewNewsletterSignupCard && renderingTarget === 'Web';

const abTests = useBetaAB();
const abTests = useAB();
const abResolved = abTests !== undefined;

const isVariant =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import type { StoryObj } from '@storybook/react-webpack5';
import { mocked, within } from 'storybook/test';
import preview from '../../.storybook/preview';
import { lazyFetchEmailWithTimeout } from '../lib/fetchEmail';
import { useBetaAB } from '../lib/useAB';
import { useAB } from '../lib/useAB';
import { useIsSignedIn } from '../lib/useAuthStatus';
import { useNewsletterSubscription } from '../lib/useNewsletterSubscription';
import { EmailSignUpWrapper } from './EmailSignUpWrapper.island';

/** Resolves `useBetaAB` as if the AB framework has hydrated, placing the user in control or variant. */
/** Resolves `useAB` as if the AB framework has hydrated, placing the user in control or variant. */
const mockBetaAB = (isInVariant: boolean) => {
mocked(useBetaAB).mockReturnValue({
mocked(useAB).mockReturnValue({
isUserInTestGroup: (_testName: string, group: string) =>
group === 'variant' ? isInVariant : !isInVariant,
isUserInTest: () => true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from 'react';
import { buildXcustParamForAffiliateLink } from '../lib/affiliateLinksUtils';
import { safeParseURL } from '../lib/parse';
import { useBetaAB } from '../lib/useAB';
import { useAB } from '../lib/useAB';

/**
* Add custom parameters to skimlink URLs:
Expand Down Expand Up @@ -44,7 +44,7 @@ const utmKeys = [
];

export const EnhanceAffiliateLinks = () => {
const abTests = useBetaAB();
const abTests = useAB();

// Get users server & client-side AB test participations
const abTestParticipations = abTests?.getParticipations();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import { useBetaAB } from '../lib/useAB';
import { useAB } from '../lib/useAB';
import { EnhanceAffiliateLinks } from './EnhanceAffiliateLinks.island';

// Mock the useAB module
jest.mock('../lib/useAB', () => ({
useBetaAB: jest.fn(),
useAB: jest.fn(),
}));

describe('EnhanceAffiliateLinks', () => {
Expand Down Expand Up @@ -67,7 +67,7 @@ describe('EnhanceAffiliateLinks', () => {
<a href="https://go.skimresources.com/?id=12345">Skimlink</a>
`;

(useBetaAB as jest.Mock).mockReturnValue({
(useAB as jest.Mock).mockReturnValue({
getParticipations: () => ({
test1: 'variantA',
test2: 'variantB',
Expand Down
5 changes: 0 additions & 5 deletions dotcom-rendering/src/components/FrontPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { FrontLayout } from '../layouts/FrontLayout';
import { buildAdTargeting } from '../lib/ad-targeting';
import { ArticleDesign, ArticleDisplay, Pillar } from '../lib/articleFormat';
import { rootStyles } from '../lib/rootStyles';
import { filterABTestSwitches } from '../model/enhance-switches';
import type { NavType } from '../model/extract-nav';
import type { Front } from '../types/front';
import { AdmiralScript } from './AdmiralScript.island';
Expand Down Expand Up @@ -81,10 +80,6 @@ export const FrontPage = ({ front, NAV }: Props) => {
</Island>
<Island priority="critical">
<SetABTests
abTestSwitches={filterABTestSwitches(front.config.switches)}
pageIsSensitive={front.config.isSensitive}
isDev={!!front.config.isDev}
serverSideTests={front.config.abTests}
serverSideABTests={front.config.serverSideABTests}
/>
</Island>
Expand Down
7 changes: 0 additions & 7 deletions dotcom-rendering/src/components/HostedContentPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { HostedGalleryLayout } from '../layouts/HostedGalleryLayout';
import { HostedVideoLayout } from '../layouts/HostedVideoLayout';
import { ArticleDesign } from '../lib/articleFormat';
import { rootStyles } from '../lib/rootStyles';
import { filterABTestSwitches } from '../model/enhance-switches';
import type { Article } from '../types/article';
import type { RenderingTarget } from '../types/renderingTarget';
import { AlreadyVisited } from './AlreadyVisited.island';
Expand Down Expand Up @@ -116,12 +115,6 @@ export const HostedContentPage = (props: WebProps | AppProps) => {

<Island priority="critical">
<SetABTests
abTestSwitches={filterABTestSwitches(
frontendData.config.switches,
)}
pageIsSensitive={frontendData.config.isSensitive}
isDev={!!frontendData.config.isDev}
serverSideTests={frontendData.config.abTests}
serverSideABTests={
frontendData.config.serverSideABTests
}
Expand Down
Loading
Loading