Skip to content
Draft
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
493f7bd
WS-1400: Add client side redirect
shayneahchoon Nov 11, 2025
717d0bb
Merge branch 'latest' into WS-1400-ECT-HELMET
shayneahchoon Nov 11, 2025
01d4e4d
Merge branch 'latest' into WS-1400-ECT-HELMET
shayneahchoon Nov 12, 2025
c994aba
WS-1533: Update packages with 7 day maturity threshold
shayneahchoon Nov 12, 2025
2bea896
Merge branch 'WS-1400-ECT-HELMET' of github.com:bbc/simorgh into WS-1…
shayneahchoon Nov 12, 2025
70e7ad7
Merge branch 'latest' into WS-1400-ECT-HELMET
shayneahchoon Nov 12, 2025
6359b3a
WS-1533: Update packages with 7 day maturity threshold
shayneahchoon Nov 12, 2025
15f88f5
Merge branch 'WS-1400-ECT-HELMET' of github.com:bbc/simorgh into WS-1…
shayneahchoon Nov 12, 2025
d5c84a4
WS-1533: Update packages with 7 day maturity threshold
shayneahchoon Nov 12, 2025
9bac75e
WS-1533: Update packages with 7 day maturity threshold
shayneahchoon Nov 12, 2025
1e086de
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
4cdf217
Merge branch 'latest' into WS-1400-ECT-HELMET
shayneahchoon Nov 17, 2025
f01ad51
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
a606199
Merge branch 'WS-1400-ECT-HELMET' of github.com:bbc/simorgh into WS-1…
shayneahchoon Nov 17, 2025
4dfd6cc
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
6832436
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
dc3594d
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
aa80aaf
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
2a2be1c
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
e0dbde9
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
5f2df6e
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
97dfa11
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
48451c3
WS-1399: Add client side redirect
shayneahchoon Nov 17, 2025
1571678
Merge branch 'latest' into WS-1400-ECT-HELMET
shayneahchoon Nov 24, 2025
83a1a3b
WS-1737: Add tracking for redirect
shayneahchoon Nov 24, 2025
657b4c2
Merge branch 'WS-1400-ECT-HELMET' of github.com:bbc/simorgh into WS-1…
shayneahchoon Nov 24, 2025
501c8cc
WS-1737: Add tracking for redirect
shayneahchoon Nov 24, 2025
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
72 changes: 72 additions & 0 deletions src/app/components/LiteRedirect/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { redirectScript } from '.';

describe('LiteRedirect', () => {
it.each([
{
effectiveType: 'randomValue',
expectedRedirect: false,
},
{
effectiveType: 'slow-2g',
expectedRedirect: true,
},
{
effectiveType: '2g',
expectedRedirect: true,
},
{
effectiveType: '3g',
expectedRedirect: true,
},
{
effectiveType: '4g',
expectedRedirect: false,
},
])(
`When the client is on $effectiveType then expect redirect should be $expectRedirect`,
({ effectiveType, expectedRedirect }) => {
const mockWindow = {
navigator: {
connection: {
effectiveType,
},
},
location: {
replace: jest.fn(),
href: 'https://www.somepath.com/',
pathname: '/pidgin/articles/czrzwn80zjmo',
},
} as unknown as Window;

redirectScript(mockWindow);
const replaceCallStack = (mockWindow.location.replace as jest.Mock).mock
.calls[0]?.[0];

const hasRedirected = Boolean(replaceCallStack);

expect(hasRedirected).toBe(expectedRedirect);
},
);

it.each(['.amp', '.lite'])('should not redirect for %s', type => {
const mockWindow = {
navigator: {
connection: {
effectiveType: '5g',
},
},
location: {
replace: jest.fn(),
href: `https://www.somepath.com${type}`,
},
} as unknown as Window;

redirectScript(mockWindow);
const replaceCallStack = (mockWindow.location.replace as jest.Mock).mock
.calls[0]?.[0];

const hasRedirected = Boolean(replaceCallStack);

expect(hasRedirected).toBe(false);
});
});
49 changes: 49 additions & 0 deletions src/app/components/LiteRedirect/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { Helmet } from 'react-helmet';

export const redirectScript = (window: Window) => {
const { pathname, href } = window.location;
const isLite = /\.lite$/.test(href);
const isAmp = /\.amp$/.test(href);

const allowList = ['/pidgin/articles/czrzwn80zjmo'];

if (
!isLite &&
!isAmp &&
window?.navigator?.connection?.effectiveType &&
allowList.includes(pathname)
) {
const toLitePath = `${pathname}.lite`;
const ect = window.navigator.connection.effectiveType;
const normalisedEct = ect.toLocaleLowerCase();
switch (normalisedEct) {
case 'slow-2g':
case '2g':
case '3g':
window.location.replace(toLitePath);
break;
default:
break;
}
}
};

export default () => {
const innerHTML = `(
window.addEventListener('load', () => {
(${redirectScript.toString()})(window)
})
)`;

return (
<Helmet
script={[
{
type: 'text/javascript',
innerHTML,
},
]}
/>
);
};
7 changes: 7 additions & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import { ReverbClient } from '#models/types/eventTracking';
import { BumpType, Player } from '#app/components/MediaLoader/types';

declare global {
interface Navigator {
connection?: {
effectiveType?: string;
addEventListener?: (type: string, listener: () => void) => void;
removeEventListener?: (type: string, listener: () => void) => void;
};
}
interface Window {
bbcpage:
| {
Expand Down
2 changes: 2 additions & 0 deletions src/server/Document/Renderers/CanonicalRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import IfAboveIE9 from '#app/legacy/components/IfAboveIE9Comment';
import NO_JS_CLASSNAME from '#app/lib/noJs.const';
import { getProcessEnvAppVariables } from '#app/lib/utilities/getEnvConfig';
import serialiseForScript from '#app/lib/utilities/serialiseForScript';
import LiteRedirect from '#app/components/LiteRedirect';
import { BaseRendererProps } from './types';
import ReverbTemplate from './ReverbTemplate';
import ComponentTracking from './ComponentTracking';
Expand Down Expand Up @@ -97,6 +98,7 @@ export default function CanonicalRenderer({
return (
<html lang="en-GB" className={NO_JS_CLASSNAME} {...htmlAttrs}>
<head>
<LiteRedirect />
<ReverbTemplate nonce={nonce} />
{isApp && <meta name="robots" content="noindex" />}
{title}
Expand Down
2 changes: 2 additions & 0 deletions ws-nextjs-app/pages/_document.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import getPathExtension from '#app/utilities/getPathExtension';
import ReverbTemplate from '#src/server/Document/Renderers/ReverbTemplate';
import { PageTypes } from '#app/models/types/global';
import ComponentTracking from '#src/server/Document/Renderers/ComponentTracking';
import LiteRedirect from '#app/components/LiteRedirect';
import removeSensitiveHeaders from '../utilities/removeSensitiveHeaders';
import derivePageType from '../utilities/derivePageType';

Expand Down Expand Up @@ -189,6 +190,7 @@ export default class AppDocument extends Document<DocProps> {
return (
<Html lang="en-GB" {...htmlAttrs} className={NO_JS_CLASSNAME}>
<Head>
<LiteRedirect />
<ReverbTemplate />
<script
type="text/javascript"
Expand Down
Loading