mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 07:40:59 +00:00
e3541535e2
The iOS app pulls every file of a build into WebKit's cache so it can start offline. It did so four at a time at normal priority, for all 1,900 files of every new build including all 27 translations, and a page opened meanwhile queued behind it: right after a server update, a first visit to Vacay took five to seven seconds. The warm-up now runs two at a time at low priority, takes only the user's language and English, and walks a build once. The day rail in the trip header lit the new day only after the pager's snap had landed and the plan had re-rendered, a second or two after the swipe. The pager now reports the day a swipe heads for as soon as its page is the nearer one, and the rail and its pill move with the finger; the plan still switches when the snap lands.
103 lines
3.8 KiB
TypeScript
103 lines
3.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { keepOfflineShellFresh, manifestFiles } from './offlineShell';
|
|
import { TrekShell } from './trekShell';
|
|
|
|
vi.mock('./trekShell', () => ({ TrekShell: { refreshOfflineCopy: vi.fn() } }));
|
|
|
|
const manifest = {
|
|
'index.html': {
|
|
file: 'assets/index-a1b2c3d4.js',
|
|
css: ['assets/index-e5f6a7b8.css'],
|
|
assets: ['assets/poppins-11223344.woff2'],
|
|
},
|
|
'src/pages/AtlasPage.tsx': { file: 'assets/AtlasPage-99887766.js', css: ['assets/index-e5f6a7b8.css'] },
|
|
_shared: { file: 'assets/shared-55443322.js', assets: 'not-a-list' },
|
|
broken: null,
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.mocked(TrekShell.refreshOfflineCopy).mockReset().mockResolvedValue({ saved: true });
|
|
window.localStorage.clear();
|
|
});
|
|
|
|
describe('manifestFiles', () => {
|
|
it('collects every chunk, stylesheet and asset once', () => {
|
|
expect(manifestFiles(manifest).sort()).toEqual([
|
|
'assets/AtlasPage-99887766.js',
|
|
'assets/index-a1b2c3d4.js',
|
|
'assets/index-e5f6a7b8.css',
|
|
'assets/poppins-11223344.woff2',
|
|
'assets/shared-55443322.js',
|
|
]);
|
|
});
|
|
|
|
it('returns nothing for something that is not a manifest', () => {
|
|
expect(manifestFiles(null)).toEqual([]);
|
|
expect(manifestFiles('x')).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('keepOfflineShellFresh', () => {
|
|
it('refreshes the stored start page and fetches every file of the build', async () => {
|
|
const fetched: string[] = [];
|
|
const fetchImpl = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
const url = String(input);
|
|
if (url === '/asset-manifest.json') {
|
|
expect(init).toEqual({ cache: 'no-store' });
|
|
return new Response(JSON.stringify(manifest));
|
|
}
|
|
fetched.push(url);
|
|
if (url.includes('shared')) throw new Error('offline for a moment');
|
|
return new Response('x');
|
|
}) as unknown as typeof fetch;
|
|
|
|
await keepOfflineShellFresh(fetchImpl);
|
|
|
|
expect(TrekShell.refreshOfflineCopy).toHaveBeenCalled();
|
|
expect(fetched.sort()).toEqual([
|
|
'/assets/AtlasPage-99887766.js',
|
|
'/assets/index-a1b2c3d4.js',
|
|
'/assets/index-e5f6a7b8.css',
|
|
'/assets/poppins-11223344.woff2',
|
|
'/assets/shared-55443322.js',
|
|
]);
|
|
});
|
|
|
|
it('stops after the start page when the build has no manifest', async () => {
|
|
const fetchImpl = vi.fn(async () => new Response('', { status: 404 })) as unknown as typeof fetch;
|
|
await keepOfflineShellFresh(fetchImpl);
|
|
expect(fetchImpl).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('fetches at low priority, only the own language, and once per build', async () => {
|
|
const withLocales = {
|
|
...manifest,
|
|
'../shared/dist/i18n/de/index.mjs': { file: 'assets/de-aaaa1111.js' },
|
|
'../shared/dist/i18n/fr/index.mjs': { file: 'assets/fr-bbbb2222.js' },
|
|
'../shared/dist/i18n/en/index.mjs': { file: 'assets/en-cccc3333.js' },
|
|
};
|
|
const inits: (RequestInit | undefined)[] = [];
|
|
const fetched: string[] = [];
|
|
const fetchImpl = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
const url = String(input);
|
|
if (url === '/asset-manifest.json') return new Response(JSON.stringify(withLocales));
|
|
fetched.push(url);
|
|
inits.push(init);
|
|
return new Response('x');
|
|
}) as unknown as typeof fetch;
|
|
|
|
await keepOfflineShellFresh(fetchImpl, 'de');
|
|
expect(fetched).toContain('/assets/de-aaaa1111.js');
|
|
expect(fetched).toContain('/assets/en-cccc3333.js');
|
|
expect(fetched).not.toContain('/assets/fr-bbbb2222.js');
|
|
expect(inits.every((i) => (i as { priority?: string } | undefined)?.priority === 'low')).toBe(true);
|
|
|
|
const before = fetched.length;
|
|
await keepOfflineShellFresh(fetchImpl, 'de');
|
|
expect(fetched.length).toBe(before);
|
|
|
|
await keepOfflineShellFresh(fetchImpl, 'fr');
|
|
expect(fetched).toContain('/assets/fr-bbbb2222.js');
|
|
});
|
|
});
|