WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit a5c760b

Browse files
authored
Merge pull request #14880 from guardian/ds/force-ab-test-participation-in-development
add force participations to Local AB test participations
2 parents 40eadfe + 0cf0a12 commit a5c760b

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

dotcom-rendering/docs/development/ab-testing-in-dcr.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,20 @@ These links are also in the [frontend admin](https://frontend.gutools.co.uk/anal
255255
- Opt-out on PROD: `https://theguardian.com/ab-tests/opt/out`
256256

257257
You can use the same routes on CODE.
258+
259+
### 6. Forcing yourself into a test locally
260+
261+
Use the opt-in and opt-out URL fragments to force yourself into or out of a test using a query parameter.
262+
263+
When opted-in, the test will override any mvt based assignment and you'll only be in the opted-in test group.
264+
265+
**Opt-in Example**
266+
267+
- Articles: `http://localhost:3030/Article/?ab-commercial-test-example=variant`
268+
- Fronts: `http://localhost:3030/Front/https://www.theguardian.com/international?ab-commercial-test-example=variant`
269+
- Interactives: `http://localhost:3030/Interactive/https://www.theguardian.com/global-development/ng-interactive/2022/jun/09/the-black-sea-blockade-mapping-the-impact-of-war-in-ukraine-on-the-worlds-food-supply-interactive?ab--commercial-test-example=variant`
270+
271+
You can verify that you're in the test by checking:
272+
273+
- Server-side tests: `window.guardian.config.serverSideABTests` in the browser console
274+
- Client-side tests: `window.guardian.modules.abTests.getParticipations()` in the browser console
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { isObject } from '@guardian/libs';
2+
import type { Handler } from 'express';
3+
import { logger } from './logging';
4+
5+
type AbServerSideTestType = {
6+
config: {
7+
serverSideABTests?: Record<string, string>;
8+
};
9+
};
10+
11+
const SAFE_AB_VALUE = /^[a-zA-Z0-9_-]+$/;
12+
const MAX_LENGTH = 100;
13+
14+
export const getABTestsFromQueryParams: Handler = (req, res, next) => {
15+
const body = req.body as AbServerSideTestType | undefined;
16+
try {
17+
if (body?.config && isObject(body.config)) {
18+
const { config } = req.body as AbServerSideTestType;
19+
const queryParamsAb = req.query;
20+
const filteredQuery: Record<string, string> = {};
21+
22+
for (const [key, value] of Object.entries(queryParamsAb)) {
23+
if (!key.startsWith('ab-') || typeof value !== 'string') {
24+
continue;
25+
}
26+
27+
const testId = key.replace(/^ab-/, '');
28+
29+
if (
30+
testId.length > 0 &&
31+
testId.length <= MAX_LENGTH &&
32+
value.length > 0 &&
33+
value.length <= MAX_LENGTH &&
34+
SAFE_AB_VALUE.test(testId) &&
35+
SAFE_AB_VALUE.test(value)
36+
) {
37+
filteredQuery[testId] = value;
38+
} else {
39+
logger.warn(
40+
`Rejected invalid AB test parameter: ${key}=${value}`,
41+
);
42+
}
43+
}
44+
config.serverSideABTests = {
45+
...config.serverSideABTests,
46+
...filteredQuery,
47+
};
48+
}
49+
} catch (error) {
50+
logger.error('Error processing AB test query params', error);
51+
return next();
52+
}
53+
next();
54+
};

dotcom-rendering/src/server/server.dev.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
handleFootballMatchPage,
2222
handleFootballTablesPage,
2323
} from './handler.sportDataPage.web';
24+
import { getABTestsFromQueryParams } from './lib/get-abtests-from-query-params';
2425
import { getContentFromURLMiddleware } from './lib/get-content-from-url';
2526

2627
/** article URLs contain a part that looks like “2022/nov/25” */
@@ -90,6 +91,7 @@ const renderer = Router();
9091
// populates req.body with the content data from a production
9192
// URL if req.params.url is present
9293
renderer.use(getContentFromURLMiddleware);
94+
renderer.use(getABTestsFromQueryParams);
9395
renderer.get('/Article/*url', handleArticle);
9496
renderer.get('/Interactive/*url', handleInteractive);
9597
renderer.get('/Blocks/*url', handleBlocks);

0 commit comments

Comments
 (0)