Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
146 commits
Select commit Hold shift + click to select a range
7f929cf
working offline component
DmitryGron Jul 17, 2025
2cb8b52
update offline page
DmitryGron Jul 21, 2025
d334d98
update
DmitryGron Jul 21, 2025
a886733
updating bundle size
DmitryGron Jul 22, 2025
9be198b
update tests
DmitryGron Jul 22, 2025
624f4b4
update tests
DmitryGron Jul 22, 2025
9c59cbb
update tests
DmitryGron Jul 22, 2025
447450b
update tests
DmitryGron Jul 23, 2025
1fb71dc
update tests
DmitryGron Jul 23, 2025
1dffbf5
update tests
DmitryGron Jul 23, 2025
931818b
Merge branch 'latest' into WS-147-offline-page
DmitryGron Jul 24, 2025
2ee1efc
Merge branch 'latest' into WS-147-offline-page
DmitryGron Jul 24, 2025
ee3b816
Merge branch 'latest' into WS-147-offline-page
DmitryGron Jul 25, 2025
88182c9
Merge branch 'latest' into WS-147-offline-page
DmitryGron Jul 29, 2025
55157ca
Merge branch 'latest' into WS-147-offline-page
DmitryGron Aug 12, 2025
4ac3831
Merge branch 'latest' into WS-147-offline-page
DmitryGron Aug 25, 2025
299c7ce
conflict resolved
jinidev Nov 28, 2025
bddd422
Merge branch 'latest' into WS-147-offline-page
jinidev Nov 28, 2025
049e894
resolving a conflicts
DmitryGron Nov 28, 2025
7b72090
resolving a conflicts
DmitryGron Nov 28, 2025
9e749a4
resolving a conflicts
DmitryGron Nov 28, 2025
1c7d92a
resolving a conflicts
DmitryGron Nov 28, 2025
7b90ce4
WS-1840 updating offline page for nextjs
DmitryGron Dec 1, 2025
2208eca
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron Dec 1, 2025
94efa25
updates
DmitryGron Dec 2, 2025
4ebc7fc
Merge remote-tracking branch 'origin/latest' into WS-1840-offline-pag…
DmitryGron Dec 2, 2025
8cfc3fe
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron Dec 3, 2025
3d1a82b
adding export to VARIANCE
DmitryGron Dec 3, 2025
5832e58
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron Dec 3, 2025
05b114b
updating bundle size
DmitryGron Dec 3, 2025
05530d7
updating due to lint error
DmitryGron Dec 3, 2025
f3528df
updating due to lint error
DmitryGron Dec 3, 2025
c83b4aa
updating due to lint error
DmitryGron Dec 3, 2025
96408a9
Update SW version to v0.3.1 and hash for offline page changes
DmitryGron Dec 3, 2025
256ba1a
Add offline page test snapshots
DmitryGron Dec 3, 2025
3089afe
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron Dec 3, 2025
5a8fc1c
Simplify SW install event - remove unnecessary HTML parsing
DmitryGron Dec 3, 2025
8d7da96
Add resource caching to SW install for offline page functionality
DmitryGron Dec 3, 2025
39b3bcc
Fix offline page: cache-first for scripts/styles + fix fetch event li…
DmitryGron Dec 3, 2025
128659f
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron Dec 3, 2025
20faeb6
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron Dec 4, 2025
27805f5
Remove auto-caching of network responses to prevent cache bloat
DmitryGron Dec 4, 2025
a5f61c5
reverting bundle size config
DmitryGron Dec 4, 2025
44d62a7
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron Dec 4, 2025
68bc941
Fix PWA offline page: dynamically extract service from URL
DmitryGron Dec 4, 2025
168f75a
Revert "Fix PWA offline page: dynamically extract service from URL"
jinidev Dec 4, 2025
0d6ff91
adding offline page PWA + browser
DmitryGron Dec 4, 2025
9f31add
conflict resolved
jinidev Dec 5, 2025
893ef9f
remove emoji
jinidev Dec 5, 2025
f6f171a
adding offline pwa only
DmitryGron Dec 5, 2025
844dd02
conflict reslved
jinidev Dec 5, 2025
29cb53f
service worker changes to render offline page in PWA apps
jinidev Dec 5, 2025
c50e8e2
Merge branch 'latest' of https://github.com/bbc/simorgh into ws-1837-…
jinidev Dec 8, 2025
b7de762
some more changes - cleaned sw.js
jinidev Dec 8, 2025
bb52f0a
Merge branch 'WS-1840-offline-page-nextjs' of https://github.com/bbc/…
jinidev Dec 8, 2025
c78bba5
Merge branch 'WS-1840-offline-page-nextjs' into ws-1837-service-worke…
jinidev Dec 8, 2025
aaf9932
Merge branch 'ws-1837-service-worker-changes' of https://github.com/b…
jinidev Dec 8, 2025
9698791
clean up
jinidev Dec 8, 2025
0a8a0f3
clean up- unwanted files removed
jinidev Dec 8, 2025
b5f11e9
added isPWA to express rendered apps
jinidev Dec 9, 2025
3a65db7
removed hasOfflineFunctionlity variable
jinidev Dec 9, 2025
6e2c15f
resolving errors
DmitryGron Dec 9, 2025
240c0e6
Merge branch 'WS-1840-offline-page-nextjs' into ws-1837-service-worke…
DmitryGron Dec 9, 2025
eaa879e
fixing errors
DmitryGron Dec 9, 2025
518f10b
Added custom hooks
jinidev Dec 10, 2025
c6b0783
some tests fixes
jinidev Dec 10, 2025
e78659b
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 10, 2025
2fc7f2f
Updated sw.js for unit tests fix
jinidev Dec 10, 2025
54cb50b
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 11, 2025
b6c7b86
Added mock navigator setup in tests
jinidev Dec 11, 2025
ef287c7
conflict reso;lved
jinidev Dec 11, 2025
1bbe2d8
tests fix
jinidev Dec 11, 2025
103eac5
Merge branch 'latest' into ws-1837-service-worker-changes
elvinasv Dec 11, 2025
75f7b76
More unit tests fix
jinidev Dec 12, 2025
45ed1a7
lint fixes
jinidev Dec 12, 2025
d258fb7
Merge branch 'latest' into ws-1837-service-worker-changes
DmitryGron Dec 12, 2025
49b64eb
testfixes
jinidev Dec 12, 2025
aed2769
Merge branch 'ws-1837-service-worker-changes' of https://github.com/b…
jinidev Dec 12, 2025
5c229b2
testing sw.js
jinidev Dec 14, 2025
bfc693b
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 14, 2025
969f8eb
testing sw.js -2
jinidev Dec 14, 2025
b32c366
testing sw.js -3
jinidev Dec 14, 2025
48b0f95
testing sw.js-4
jinidev Dec 15, 2025
6354778
conflict resolved
jinidev Dec 15, 2025
8a01bd4
tests fix
jinidev Dec 15, 2025
7cc58e6
more fixes
jinidev Dec 15, 2025
d79da48
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 15, 2025
85222f2
bypass 404, 503 errors in network requests
jinidev Dec 15, 2025
6b6f594
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 16, 2025
367fe0f
fixing lint issues
jinidev Dec 16, 2025
0519711
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 16, 2025
b2d1363
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 16, 2025
a25a504
some changes in sw.js
jinidev Dec 16, 2025
72ee34b
removing nextjs static assets to avoid loop reloadand some other fixes
jinidev Dec 17, 2025
ebfe1d7
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 17, 2025
25c8766
cache was missing
jinidev Dec 17, 2025
ea22129
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 17, 2025
037e91c
revert to latest stable version
jinidev Dec 17, 2025
e3c3bba
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Dec 18, 2025
d91548a
reveiew comments addressed - docparser , default browser behavious, i…
jinidev Dec 18, 2025
e6bd966
more testcases in sw.test.js
jinidev Dec 18, 2025
9fc1803
unit tests for hooks
jinidev Dec 19, 2025
d3f680f
removed pwa_installed variable , removed DOMParser
jinidev Dec 22, 2025
8800ec6
test cases fix
jinidev Dec 22, 2025
938ef05
Updated cache name , updated offlinepage resource caching
jinidev Dec 22, 2025
c8f3781
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Jan 5, 2026
18d4969
updates on fetchng /next/static files
jinidev Jan 5, 2026
b4e6341
conflict resolved
jinidev Jan 8, 2026
91c60fa
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Jan 8, 2026
899169a
conflicts reolved in app.page.tsx
jinidev Jan 8, 2026
e38b747
revert back _app.page.tsx
jinidev Jan 8, 2026
646696f
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Jan 8, 2026
068e4fe
PWA service worker changes into _app.page.tsx
jinidev Jan 8, 2026
674faa8
Merge branch 'latest' into ws-1837-service-worker-changes
elvinasv Jan 8, 2026
2f7ca95
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Jan 8, 2026
78e5cd6
Merge branch 'latest' into ws-1837-service-worker-changes
elvinasv Jan 9, 2026
f513db3
WS-1838: Add PWA Offline page tracking (#13545)
DmitryGron Jan 9, 2026
cfdb08d
sw.js -removed filtering in cachingoffline resource, commented PWASer…
jinidev Jan 9, 2026
df00544
refactor: remove comment; remove redundant cacheOfflinePageAndResourc…
elvinasv Jan 9, 2026
e04576c
Changed scope of sw.js to /sw.js
jinidev Jan 11, 2026
30d97de
updated nextjsconfig for /sw.js scope , removed pwaserviceworker comp
jinidev Jan 11, 2026
efdd97b
reverted scope from/sw.js to /service
jinidev Jan 11, 2026
95f9e61
added scope / in sw registration
jinidev Jan 11, 2026
9288c7f
testing with initial sw.js
jinidev Jan 12, 2026
0db3934
Reverting back to new changes after testing
jinidev Jan 12, 2026
227c73c
refactor: use explicit PWA offline flag
elvinasv Jan 12, 2026
40f570f
refactor: use Service-Worker-Allowed
elvinasv Jan 12, 2026
f5f7537
added trailingSlash config
jinidev Jan 12, 2026
b6ebef6
removed trailingSlash
jinidev Jan 12, 2026
cf189b6
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Jan 13, 2026
7bce52e
feat: add logger
elvinasv Jan 13, 2026
9e3fcca
Merge branch 'ws-1837-service-worker-changes' of github.com:bbc/simor…
elvinasv Jan 13, 2026
6c32f85
refactor: cleanup
elvinasv Jan 13, 2026
dc41ab3
feat: add nofollow noindex for the offline page
elvinasv Jan 13, 2026
0df5fa4
test: update hash
elvinasv Jan 13, 2026
f0b0c4e
chore: fix warning
elvinasv Jan 13, 2026
2518e51
Merge branch 'latest' of github.com:bbc/simorgh into ws-1837-service-…
elvinasv Jan 13, 2026
4ebfba8
Commenting next-config service-worker-allowed
jinidev Jan 13, 2026
8ddbe92
update hash in test
jinidev Jan 13, 2026
6ef497e
refactor: remove console.logs
elvinasv Jan 13, 2026
017d564
Update src/app/hooks/useServiceWorkerRegistration/index.test.tsx
jinidev Jan 14, 2026
bb2970d
Update src/app/hooks/useServiceWorkerRegistration/index.test.tsx
jinidev Jan 14, 2026
aede4d4
Updated test cases for serviceworker.tsx
jinidev Jan 14, 2026
f04b3b4
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Jan 14, 2026
07813fe
Merge branch 'latest' into ws-1837-service-worker-changes
elvinasv Jan 15, 2026
a0f05fe
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev Jan 16, 2026
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
183 changes: 154 additions & 29 deletions public/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,64 @@
/* eslint-disable no-unused-vars */
/* eslint-disable no-undef */
/* eslint-disable no-restricted-globals */
const version = 'v0.3.0';
const cacheName = 'simorghCache_v1';

const service = self.location.pathname.split('/')[1];
const hasOfflinePageFunctionality = false;
const OFFLINE_PAGE = `/${service}/offline`;

self.addEventListener('install', event => {
event.waitUntil(async () => {
const cache = await caches.open(cacheName);
if (hasOfflinePageFunctionality) await cache.add(OFFLINE_PAGE);
});
});

const version = 'v0.3.2';
// Update cache name when changing caching logic / changes in offlinepage.tsx
const cacheName = 'simorghCache_v2';
const pwaClients = new Map();
let isPWADeviceOffline = false;

// --------------------
// Helper Functions
// --------------------
const loggerEnabled = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: We will disable logging or delete this before merging

const logger = (...args) => {
if (!loggerEnabled) return;
// eslint-disable-next-line no-console
console.log(`[SW ${version}]`, ...args);
};

const getServiceFromUrl = url => new URL(url).pathname.split('/')[1];
const getOfflinePageUrl = service => `/${service}/offline`;

const cacheResource = async (cache, url) => {
try {
const response = await fetch(url);
if (response.ok) await cache.put(url, response.clone());
return response;
} catch (err) {
logger(`Failed to cache ${url}:`, err);
return null;
}
};

const cacheOfflinePageAndResources = async service => {
const cache = await caches.open(cacheName);
const offlinePageUrl = new URL(
getOfflinePageUrl(service),
self.location.origin,
).href;

if (await cache.match(offlinePageUrl)) return;

const resp = await cacheResource(cache, offlinePageUrl);
if (!resp || !resp.ok) return;

logger(`Cached offline page for ${service}`);

const html = await resp.text();
const scriptSrcs = [
...html.matchAll(/<script[^>]+src=["']([^"']+)["']/g),
].map(m => m[1]);
const linkHrefs = [...html.matchAll(/<link[^>]+href=["']([^"']+)["']/g)].map(
m => m[1],
);

const resources = [...scriptSrcs, ...linkHrefs].filter(Boolean);

logger(`Caching final offline resources for ${service}:`, resources);
await Promise.allSettled(resources.map(url => cacheResource(cache, url)));
};

const CACHEABLE_FILES = [
// Reverb
Expand All @@ -35,24 +80,60 @@ const CACHEABLE_FILES = [
const WEBP_IMAGE =
/^https:\/\/ichef(\.test)?\.bbci\.co\.uk\/(news|images|ace\/(standard|ws))\/.+.webp$/;

// -------------Install event -------
self.addEventListener('install', () => {
logger(`Installing...`);
self.skipWaiting();
});

// -------Activate Handler-------------
self.addEventListener('activate', event => {
logger(`Activating...`);
event.waitUntil(
(async () => {
const keys = await caches.keys();
await Promise.all(
keys.map(key => key !== cacheName && caches.delete(key)),
);
await self.clients.claim();
})(),
);
});

// -------Message Event-------------
self.addEventListener('message', async event => {
logger('Message received:', event.data);

if (event.data?.type === 'PWA_STATUS') {
const clientId = event.source.id;
const { isPWA } = event.data;

if (isPWA) {
pwaClients.set(clientId, true);
const service = getServiceFromUrl(event.source.url);
await cacheOfflinePageAndResources(service);
}
}
});

// -------Fetch Handler-------------
const fetchEventHandler = async event => {
logger(`[SW FETCH] Request: ${event.request.url}`);
const isRequestForCacheableFile = CACHEABLE_FILES.some(cacheableFile =>
new RegExp(cacheableFile).test(event.request.url),
);

const isRequestForWebpImage = WEBP_IMAGE.test(event.request.url);
const isNavigationMode = event.request.mode === 'navigate';

if (isRequestForWebpImage) {
const req = event.request.clone();

// Inspect the accept header for WebP support

const supportsWebp =
req.headers.has('accept') && req.headers.get('accept').includes('webp');

// if supports webp is false in request header then don't use it
// if accept header doesn't indicate support for webp remove .webp extension

if (!supportsWebp) {
const imageUrlWithoutWebp = req.url.replace('.webp', '');
event.respondWith(
Expand All @@ -73,22 +154,66 @@ const fetchEventHandler = async event => {
return response;
})(),
);
} else if (hasOfflinePageFunctionality && event.request.mode === 'navigate') {
event.respondWith(async () => {
try {
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
} else if (isNavigationMode) {
const { url } = event.request;

event.respondWith(
(async () => {
const client = await self.clients.get(event.clientId);
const isPWA = client && pwaClients.get(client.id);
const cache = await caches.open(cacheName);

// TODO: Used for testing - to be removed
logger('📌 [SW FETCH] Navigation', {
url: event.request.url,
clientId: event.clientId,
isPWA,
client,
event,
pwaClients,
isPWADeviceOffline,
});
try {
// Use preload if available
const preloadResp = await event.preloadResponse;
if (preloadResp) return preloadResp;

const networkResp = await fetch(event.request);
isPWADeviceOffline = false;
return networkResp;
} catch (err) {
// Only show offline page for installed PWA
if (isPWA) {
const service = getServiceFromUrl(url);
const offlineUrl = new URL(
getOfflinePageUrl(service),
self.location.origin,
).href;

const cachedOffline = await cache.match(offlineUrl);
if (cachedOffline) {
isPWADeviceOffline = true;
logger('[SW] Serving cached offline page');
return cachedOffline;
}
}
// fallback to browser default behavior
throw err;
}
const networkResponse = await fetch(event.request);
return networkResponse;
} catch (error) {
})(),
);
} else if (isPWADeviceOffline) {
logger(`[SW v${version}] Serving isPWADeviceOffline ${event.request.url}`);
event.respondWith(
(async () => {
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match(OFFLINE_PAGE);
return cachedResponse;
}
});
const cached = await cache.match(event.request);
if (cached) return cached;
return fetch(event.request);
})(),
);
}

return;
};

Expand Down
2 changes: 2 additions & 0 deletions src/app/components/ATIAnalytics/canonical/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import usePWAInstallTracker from '#app/hooks/usePWAInstallTracker';
import { reverbUrlHelper } from '@bbc/reverb-url-helper';
import useConnectionBackOnlineTracker from '#app/hooks/useConnectionBackOnlineTracker';
import useConnectionTypeTracker from '#app/hooks/useConnectionTypeTracker';
import usePWAOfflineTracking from '#app/hooks/usePWAOfflineTracking';
import { ATIAnalyticsProps } from '../types';
import getNoScriptTrackingPixelUrl from './getNoScriptTrackingPixelUrl';
import sendPageViewBeaconOperaMini from './sendPageViewBeaconOperaMini';
Expand Down Expand Up @@ -47,6 +48,7 @@ const CanonicalATIAnalytics = ({ reverbParams }: ATIAnalyticsProps) => {

useConnectionTypeTracker();
useConnectionBackOnlineTracker();
usePWAOfflineTracking();

const [reverbBeaconConfig] = useState(reverbParams);

Expand Down
107 changes: 47 additions & 60 deletions src/app/components/ServiceWorker/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,79 +1,38 @@
import onClient from '#app/lib/utilities/onClient';
import useServiceWorkerRegistration from '#app/hooks/useServiceWorkerRegistration';
import useSendPWAStatus from '#app/hooks/useSendPWAStatus';
import useIsPWA from '#app/hooks/useIsPWA';
import isLocal from '#app/lib/utilities/isLocal';
import { render } from '../react-testing-library-with-providers';
import { ServiceContext } from '../../contexts/ServiceContext';
import ServiceWorkerContainer from './index';
import { ServiceContext } from '../../contexts/ServiceContext';
import { render } from '../react-testing-library-with-providers';

jest.mock('#app/hooks/useServiceWorkerRegistration', () => jest.fn());
jest.mock('#app/hooks/useSendPWAStatus', () => jest.fn());
jest.mock('#app/hooks/useIsPWA', () => jest.fn());
jest.mock('#app/lib/utilities/isLocal', () => jest.fn());

const contextStub = {
swPath: '/articles/sw.js',
swPath: '/news/sw.js',
service: 'news',
};

const mockServiceWorker = {
register: jest.fn(),
};

jest.mock('#app/lib/utilities/onClient', () =>
jest.fn().mockImplementation(() => true),
);

jest.mock('#app/lib/utilities/isLocal', () =>
jest.fn().mockImplementation(() => true),
);

describe('Service Worker', () => {
const originalNavigator = global.navigator;

afterEach(() => {
jest.resetAllMocks();

global.navigator ??= originalNavigator;
describe('ServiceWorkerContainer', () => {
beforeEach(() => {
jest.clearAllMocks();
(useIsPWA as jest.Mock).mockReturnValue(false);
(isLocal as jest.Mock).mockReturnValue(true);
});

describe('Canonical', () => {
it('is registered when swPath, serviceWorker have values and onClient is true', () => {
// @ts-expect-error need to override the navigator.serviceWorker for testing purposes
global.navigator.serviceWorker = mockServiceWorker;
(onClient as jest.Mock).mockImplementationOnce(() => true);

it('calls service worker registration hook with service', () => {
render(
// @ts-expect-error only require a subset of properties on service context for testing purposes
<ServiceContext.Provider value={{ ...contextStub }}>
<ServiceContext.Provider value={contextStub}>
<ServiceWorkerContainer />
</ServiceContext.Provider>,
);
expect(navigator.serviceWorker.register).toHaveBeenCalledWith(
`/news/articles/sw.js`,
);
});

describe('is not registered', () => {
it.each`
swPath | serviceWorker | isOnClient
${undefined} | ${undefined} | ${true}
${undefined} | ${undefined} | ${false}
${undefined} | ${mockServiceWorker} | ${true}
${undefined} | ${mockServiceWorker} | ${false}
${contextStub.swPath} | ${mockServiceWorker} | ${false}
`(
'when swPath is $swPath, serviceWorker is $serviceWorker and isOnClient is $isOnClient',
({ swPath, serviceWorker, isOnClient }) => {
if (serviceWorker) {
// @ts-expect-error need to override the navigator.serviceWorker for testing purposes
global.navigator.serviceWorker = serviceWorker;
}

(onClient as jest.Mock).mockImplementationOnce(() => isOnClient);

render(
// @ts-expect-error only require a subset of properties on service context for testing purposes
<ServiceContext.Provider value={{ ...contextStub, swPath }}>
<ServiceWorkerContainer />
</ServiceContext.Provider>,
);
expect(navigator.serviceWorker.register).not.toHaveBeenCalled();
},
);
expect(useServiceWorkerRegistration).toHaveBeenCalledWith('news');
});
});

Expand Down Expand Up @@ -120,4 +79,32 @@ describe('Service Worker', () => {
);
});
});

describe('PWA', () => {
it('calls useSendPWAStatus with true when PWA is installed', () => {
(useIsPWA as jest.Mock).mockReturnValue(true);

render(
// @ts-expect-error only require a subset of properties on service context for testing purposes
<ServiceContext.Provider value={contextStub}>
<ServiceWorkerContainer />
</ServiceContext.Provider>,
);

expect(useSendPWAStatus).toHaveBeenCalledWith(true);
});

it('calls useSendPWAStatus with false when PWA is not installed', () => {
(useIsPWA as jest.Mock).mockReturnValue(false);

render(
// @ts-expect-error only require a subset of properties on service context for testing purposes
<ServiceContext.Provider value={contextStub}>
<ServiceWorkerContainer />
</ServiceContext.Provider>,
);

expect(useSendPWAStatus).toHaveBeenCalledWith(false);
});
});
});
Loading
Loading