Skip to content
Draft
Show file tree
Hide file tree
Changes from 10 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
69 changes: 69 additions & 0 deletions src/app/components/LiteRedirect/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { redirectScript } from '.';

describe('LiteRedirect', () => {
beforeEach(() => {
// I've tried mocking the replace function like this, but it still won't work.
// Object.defineProperty(window, 'location', {
// configurable: true,
// writable: true,
// value: { replace: jest.fn() },
// });
});
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 isLite = false;
const testLitePath = '/testLitePath';

// Strangely enough, this works for mocking the navigator.
// Object.defineProperty(window, 'navigator', {
// writable: true,
// value: {
// connection: {
// effectiveType,
// },
// },
// });

const mockWindow = {
navigator: {
connection: {
effectiveType,
},
},
location: {
replace: jest.fn(),
},
} as unknown as Window;

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

const hasRedirected = Boolean(replaceCallStack);

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

export const redirectScript = (
window: Window,
isLite: boolean,
pathname: string,
) => {
if (!isLite && window?.navigator?.connection?.effectiveType) {
const ect = window.navigator.connection.effectiveType;
const normalisedEct = ect.toLocaleLowerCase();
switch (normalisedEct) {
case 'slow-2g':
case '2g':
case '3g':
window.location.replace(pathname);
break;
default:
break;
}
}
};

export default () => {
const { pathname, isLite, isAmp } = use(RequestContext);
const toLitePath = `${pathname}.lite`;
const innerHTML = `(
window.addEventListener('load', () => {
(${redirectScript.toString()})(window, ${isLite},'${toLitePath}')
})
)`;

return (
!isAmp && (
<Helmet
script={[
{
type: 'text/javascript',
innerHTML,
},
]}
/>
)
);
};
2 changes: 2 additions & 0 deletions src/app/pages/ArticlePage/ArticlePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { Recommendation } from '#app/models/types/onwardJourney';
import ScrollablePromo from '#components/ScrollablePromo';
import Recommendations from '#app/components/Recommendations';
import { ReadTimeArticleExperiment as ReadTime } from '#app/components/ReadTime';
import LiteRedirect from '#app/components/LiteRedirect';
import ElectionBanner from './ElectionBanner';
import ImageWithCaption from '../../components/ImageWithCaption';
import AdContainer from '../../components/Ad';
Expand Down Expand Up @@ -391,6 +392,7 @@ const ArticlePage = ({ pageData }: { pageData: Article }) => {

return (
<div css={styles.pageWrapper}>
<LiteRedirect />
<ATIAnalytics atiData={atiData} />
<ChartbeatAnalytics
sectionName={pageData?.relatedContent?.section?.name}
Expand Down
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
Loading