Retire the v2 API cache, bound candidate offers, deflake link leak tests
- Bump the service worker API cache to v3 so activation deletes the v2 cache, whose recipe-candidate responses used the full page URL as candidate_id; test that activation deletes v1 and v2 and keeps v3. - Give candidate offers a 30-minute lifetime, drop expired offers when new ones are stored, and clear a dinner's offers on every hand grounding (candidate, link or manual) and on archive. A candidate search still running when its dinner is cleared stores nothing, so a stale candidate_id gets the same 400 as an unknown one. - Make the link leak assertions in TestDinnerResponsesHideTokenInLinkPath and TestCreateRegularNeverNamesFromLink check phrases a ULID cannot contain, so a dinner id holding "KEY" no longer fails them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+9
-4
@@ -15,12 +15,16 @@ describe('service worker activation', () => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
it('deletes the v1 API cache and keeps the precache, photo and font caches', async () => {
|
||||
// A household on the v1 worker: its API cache held dinners with the
|
||||
// pasted recipe_url; its photos and fonts are not in the precache.
|
||||
it('deletes the v1 and v2 API caches and keeps the current caches', async () => {
|
||||
// A household that ran the v1 and v2 workers: the v1 API cache held
|
||||
// dinners with the pasted recipe_url, the v2 one recipe candidates whose
|
||||
// candidate_id was the full URL. Its photos and fonts are not in the
|
||||
// precache, and the current API cache may already exist.
|
||||
const names = [
|
||||
'mealquest-precache-v1',
|
||||
'mealquest-api-v1',
|
||||
'mealquest-api-v2',
|
||||
'mealquest-api-v3',
|
||||
'mealquest-media-v1',
|
||||
'mealquest-fonts-v1',
|
||||
'other-app-cache',
|
||||
@@ -42,6 +46,7 @@ describe('service worker activation', () => {
|
||||
|
||||
expect(pending).toHaveLength(1)
|
||||
expect(cacheStorage.delete).toHaveBeenCalledWith('mealquest-api-v1')
|
||||
expect(cacheStorage.delete).toHaveBeenCalledTimes(1)
|
||||
expect(cacheStorage.delete).toHaveBeenCalledWith('mealquest-api-v2')
|
||||
expect(cacheStorage.delete).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -147,12 +147,13 @@ describe('cache names', () => {
|
||||
for (const name of Object.values(cacheNames)) expect(name).toMatch(/^mealquest-/)
|
||||
})
|
||||
|
||||
it('retire only the v1 API cache', () => {
|
||||
// v1 API responses held dinners with the pasted recipe_url, which can
|
||||
// carry a personal token; offline, the worker would still serve them.
|
||||
it('retire only the v1 and v2 API caches', () => {
|
||||
// v1 API responses held dinners with the pasted recipe_url and v2 ones
|
||||
// recipe candidates whose candidate_id was the full URL; either can carry
|
||||
// a personal token, and offline the worker would still serve them.
|
||||
// The precache, photos and fonts keep their v1 caches.
|
||||
expect(cacheNames).toEqual({
|
||||
api: 'mealquest-api-v2',
|
||||
api: 'mealquest-api-v3',
|
||||
media: 'mealquest-media-v1',
|
||||
fonts: 'mealquest-fonts-v1',
|
||||
})
|
||||
|
||||
@@ -29,9 +29,10 @@ export interface RouteRequest {
|
||||
// photos and fonts stay available offline.
|
||||
export const cacheVersions = {
|
||||
precache: 'v1',
|
||||
// v2 retires the v1 API cache, whose dinner responses still carried the
|
||||
// pasted recipe_url.
|
||||
api: 'v2',
|
||||
// v2 retired the v1 API cache, whose dinner responses still carried the
|
||||
// pasted recipe_url; v3 retires the v2 API cache, whose recipe-candidate
|
||||
// responses used the full URL as candidate_id.
|
||||
api: 'v3',
|
||||
media: 'v1',
|
||||
fonts: 'v1',
|
||||
} as const
|
||||
|
||||
Reference in New Issue
Block a user