Skip to content

Commit 197ef49

Browse files
committed
Split up load-page functions and add docs
1 parent a4bf28c commit 197ef49

File tree

1 file changed

+71
-20
lines changed

1 file changed

+71
-20
lines changed

dotcom-rendering/playwright/lib/load-page.ts

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,45 +26,83 @@ type LoadPageParams = {
2626
path: string;
2727
} & LoadPageOptions;
2828

29-
const getFrontendUrl = (path: string) => {
29+
/**
30+
* @param path The path for a DCR endpoint path
31+
* e.g. `/Article/https://www.theguardian.com/world/2025/aug/19/the-big-church-move-sweden-kiruna-kyrka`
32+
* @returns The Frontend URL to fetch the JSON payload
33+
* e.g. `https://www.theguardian.com/world/2025/aug/19/the-big-church-move-sweden-kiruna-kyrka.json`
34+
*/
35+
const getFrontendJsonUrl = (path: string) => {
3036
const secondSlashIndex = path.indexOf('/', 1);
3137
const contentUrl = path.substring(secondSlashIndex + 1);
3238
return `${contentUrl}.json`;
3339
};
3440

35-
const getFrontendArticle = async (
36-
url: string,
41+
/**
42+
* @param path The Frontend URL to fetch the JSON payload
43+
* e.g. `https://www.theguardian.com/world/2025/aug/19/the-big-church-move-sweden-kiruna-kyrka`
44+
* @param cookies Cookies to send with the request
45+
* e.g. `GU_EDITION=US`
46+
* @param queryParams Query parameters to append to the request
47+
* e.g. `live=true` for live blogs
48+
* @returns The JSON response from the Frontend URL
49+
*/
50+
const getFrontendJson = async (
51+
path: string,
3752
cookies: Cookie[],
3853
queryParams: LoadPageParams['queryParams'],
39-
): Promise<FEArticle | FEFront> => {
54+
): Promise<unknown> => {
4055
try {
4156
const paramsString = `${new URLSearchParams({
4257
dcr: 'true',
4358
...queryParams,
4459
}).toString()}`;
45-
const frontendUrl = `${getFrontendUrl(url)}?${paramsString}`;
60+
const frontendUrl = `${getFrontendJsonUrl(path)}?${paramsString}`;
4661
const cookie = cookies.map((c) => `${c.name}=${c.value}`).join('; ');
4762
const response = await fetch(frontendUrl, { headers: { cookie } });
4863
if (!response.ok) {
4964
throw new Error(
50-
`Failed to fetch article JSON from ${url}: ${response.statusText}`,
65+
`Failed to fetch from ${path}: ${response.statusText}`,
5166
);
5267
}
53-
if (url.startsWith('/Article')) {
54-
return validateAsFEArticle(await response.json());
55-
} else if (url.startsWith('/Front')) {
56-
return validateAsFEFront(await response.json());
57-
}
58-
throw new Error(`Unsupported URL for fetching article: ${url}`);
68+
return response.json();
5969
} catch (error) {
6070
throw new Error(
61-
`Error fetching or validating article JSON from ${url}: ${
71+
`Error fetching from ${path}: ${
6272
error instanceof Error ? error.message : String(error)
6373
}`,
6474
);
6575
}
6676
};
6777

78+
/**
79+
* Validates the JSON response from the Frontend URL based on the path.
80+
81+
* Add more validation logic here if additional content types are required.
82+
*
83+
* @param path The path for a DCR endpoint, used to determine the content type.
84+
* e.g. `/Article/https://www.theguardian.com/world/2025/aug/19/the-big-church-move-sweden-kiruna-kyrka`
85+
* @param json The JSON response from the Frontend URL
86+
* @returns The validated `FEArticle` or `FEFront` object
87+
*/
88+
const validateJson = (path: string, json: unknown): FEArticle | FEFront => {
89+
if (path.startsWith('/Article')) {
90+
return validateAsFEArticle(json);
91+
} else if (path.startsWith('/Front')) {
92+
return validateAsFEFront(json);
93+
}
94+
throw new Error(`Unsupported URL for validating article: ${path}`);
95+
};
96+
97+
/**
98+
* Constructs a DCR URL for a given path and query parameters.
99+
* @param params The parameters for constructing the DCR URL
100+
* @param params.path The path for a DCR endpoint
101+
* @param params.queryParamsOn Whether to append query parameters to the URL
102+
* @param params.queryParams Query parameters to append to the request
103+
* @returns The DCR URL
104+
* e.g. `http://localhost:9000/Article/https://theguardian.com/sport/live/2022/mar/27/west-indies-v-england-third-test-day-four-live?adtest=fixed-puppies-ci&live=true&force-liveblog-epic=true`
105+
*/
68106
const getDcrUrl = ({
69107
path,
70108
queryParamsOn,
@@ -76,10 +114,17 @@ const getDcrUrl = ({
76114
...queryParams,
77115
}).toString()}`
78116
: '';
79-
80117
return `${ORIGIN}${path}${paramsString}`;
81118
};
82119

120+
/**
121+
* Constructs a DCR POST URL for a given path.
122+
* @param path The path for a DCR endpoint
123+
* e.g. `/Article/https://www.theguardian.com/world/2025/aug/19/the-big-church-move-sweden-kiruna-kyrka`
124+
* @returns The DCR POST URL to send the request to
125+
* e.g. `http://localhost:9000/Article`
126+
* This is used to override the request method to POST in Playwright tests.
127+
*/
83128
const getDcrPostUrl = (path: string) => `${ORIGIN}/${path.split('/')[1]}`;
84129

85130
/**
@@ -120,18 +165,21 @@ const loadPage = async ({
120165
const cookies = await page.context().cookies();
121166

122167
// If overrides exist, but no article fixture we fetch it from Frontend
123-
const frontendArticle = await (overrides.article
168+
const frontendPage = await (overrides.article
124169
? Promise.resolve(overrides.article)
125-
: getFrontendArticle(path, cookies, queryParams));
170+
: validateJson(
171+
path,
172+
await getFrontendJson(path, cookies, queryParams),
173+
));
126174

127175
// Apply the overrides to the article config and switches
128176
const postData = {
129-
...frontendArticle,
177+
...frontendPage,
130178
config: {
131-
...frontendArticle.config,
179+
...frontendPage.config,
132180
...overrides.configOverrides,
133181
switches: {
134-
...frontendArticle.config.switches,
182+
...frontendPage.config.switches,
135183
...overrides.switchOverrides,
136184
},
137185
},
@@ -143,7 +191,7 @@ const loadPage = async ({
143191
queryParams,
144192
});
145193

146-
// Override the request to the DCR URL to use a POST method
194+
// Override any request matching dcrUrl to use a POST method
147195
// with the overridden payload
148196
await page.route(dcrUrl, async (route) => {
149197
await route.continue({
@@ -157,6 +205,9 @@ const loadPage = async ({
157205
});
158206
});
159207

208+
// Initiate the page load
209+
// Add the fragment here as Playwright has an issue when matching urls
210+
// with fragments in the page.route handler
160211
await page.goto(`${dcrUrl}${fragment ?? ''}`, { waitUntil });
161212
};
162213

0 commit comments

Comments
 (0)