From 7c15344d630a7f7557f53b42dab23ed1c8b5a66e Mon Sep 17 00:00:00 2001 From: pieh Date: Tue, 20 Aug 2024 17:23:57 +0200 Subject: [PATCH 1/2] test: update assertions for fully rolled out durable cache --- .../cli-before-regional-blobs-support.test.ts | 2 +- tests/e2e/durable-cache.test.ts | 19 -------- tests/e2e/on-demand-app.test.ts | 8 ++-- tests/e2e/page-router.test.ts | 46 +++++++++---------- tests/e2e/simple-app.test.ts | 13 ++++-- tests/e2e/turborepo.test.ts | 8 ++-- tests/integration/cache-handler.test.ts | 4 +- tests/integration/fetch-handler.test.ts | 4 +- tests/integration/page-router.test.ts | 2 +- tests/integration/revalidate-path.test.ts | 8 ++-- tests/integration/revalidate-tags.test.ts | 8 ++-- tests/integration/simple-app.test.ts | 8 ++-- tests/integration/static.test.ts | 2 +- tests/utils/create-e2e-fixture.ts | 6 --- tests/utils/fixture.ts | 4 +- 15 files changed, 60 insertions(+), 82 deletions(-) delete mode 100644 tests/e2e/durable-cache.test.ts diff --git a/tests/e2e/cli-before-regional-blobs-support.test.ts b/tests/e2e/cli-before-regional-blobs-support.test.ts index a19a490053..0e3b310d4e 100644 --- a/tests/e2e/cli-before-regional-blobs-support.test.ts +++ b/tests/e2e/cli-before-regional-blobs-support.test.ts @@ -19,7 +19,7 @@ test('should serve 404 page when requesting non existing page (no matching route expect(await page.textContent('h1')).toBe('404') expect(headers['netlify-cdn-cache-control']).toBe( - 'no-cache, no-store, max-age=0, must-revalidate', + 'no-cache, no-store, max-age=0, must-revalidate, durable', ) expect(headers['cache-control']).toBe('no-cache,no-store,max-age=0,must-revalidate') }) diff --git a/tests/e2e/durable-cache.test.ts b/tests/e2e/durable-cache.test.ts deleted file mode 100644 index 269203ba89..0000000000 --- a/tests/e2e/durable-cache.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { expect } from '@playwright/test' -import { test } from '../utils/playwright-helpers.js' - -// This fixture is deployed to a separate site with the feature flag enabled -test('sets cache-control `durable` directive when feature flag is enabled', async ({ - page, - durableCache, -}) => { - const response = await page.goto(durableCache.url) - const headers = response?.headers() || {} - - const h1 = page.locator('h1') - await expect(h1).toHaveText('Home') - - expect(headers['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000, durable', - ) - expect(headers['cache-control']).toBe('public,max-age=0,must-revalidate') -}) diff --git a/tests/e2e/on-demand-app.test.ts b/tests/e2e/on-demand-app.test.ts index 85b1fb69dd..27870efe47 100644 --- a/tests/e2e/on-demand-app.test.ts +++ b/tests/e2e/on-demand-app.test.ts @@ -76,7 +76,7 @@ test.describe('app router on-demand revalidation', () => { expect(response1?.status()).toBe(200) expect(headers1['x-nextjs-cache']).toBeUndefined() expect(headers1['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const date1 = await page.textContent('[data-testid="date-now"]') @@ -104,7 +104,7 @@ test.describe('app router on-demand revalidation', () => { expect(headers2['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page is cached @@ -134,7 +134,7 @@ test.describe('app router on-demand revalidation', () => { expect(response3?.status()).toBe(200) expect(headers3?.['x-nextjs-cache']).toBeUndefined() expect(headers3['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page has now an updated date @@ -161,7 +161,7 @@ test.describe('app router on-demand revalidation', () => { expect(headers4['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers4['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page is cached diff --git a/tests/e2e/page-router.test.ts b/tests/e2e/page-router.test.ts index a92f0cbcbb..895a2025fb 100644 --- a/tests/e2e/page-router.test.ts +++ b/tests/e2e/page-router.test.ts @@ -111,7 +111,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => { expect(headers1['x-nextjs-cache']).toBeUndefined() expect(headers1['netlify-cache-tag']).toBe(`_n_t_${pagePath}`) expect(headers1['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const date1 = await page.textContent('[data-testid="date-now"]') @@ -139,7 +139,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => { expect(headers1Json['x-nextjs-cache']).toBeUndefined() expect(headers1Json['netlify-cache-tag']).toBe(`_n_t_${pagePath}`) expect(headers1Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data1 = (await response1Json?.json()) || {} expect(data1?.pageProps?.time).toBe(date1) @@ -164,7 +164,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => { expect(headers2['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page is cached @@ -195,7 +195,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => { expect(headers2Json['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data2 = (await response2Json?.json()) || {} @@ -250,7 +250,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => { expect(response3Json?.status()).toBe(200) expect(headers3Json['x-nextjs-cache']).toBeUndefined() expect(headers3Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data3 = (await response3Json?.json()) || {} @@ -341,7 +341,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => { expect(await page.textContent('h1')).toBe('404') expect(headers['netlify-cdn-cache-control']).toBe( - 'no-cache, no-store, max-age=0, must-revalidate', + 'no-cache, no-store, max-age=0, must-revalidate, durable', ) expect(headers['cache-control']).toBe('no-cache,no-store,max-age=0,must-revalidate') }) @@ -357,7 +357,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => { expect(await page.textContent('h1')).toBe('404') expect(headers['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) expect(headers['cache-control']).toBe('public,max-age=0,must-revalidate') }) @@ -401,7 +401,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => { const response = await page.goto(new URL('static/fully-static', pageRouter.url).href) const headers = response?.headers() || {} - expect(headers['netlify-cdn-cache-control']).toBe('max-age=31536000') + expect(headers['netlify-cdn-cache-control']).toBe('max-age=31536000, durable') expect(headers['cache-control']).toBe('public,max-age=0,must-revalidate') }) @@ -487,7 +487,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers1ImplicitLocale['x-nextjs-cache']).toBeUndefined() expect(headers1ImplicitLocale['netlify-cache-tag']).toBe(`_n_t_/en${pagePath}`) expect(headers1ImplicitLocale['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const date1ImplicitLocale = await page.textContent('[data-testid="date-now"]') @@ -513,7 +513,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers1ExplicitLocale['x-nextjs-cache']).toBeUndefined() expect(headers1ExplicitLocale['netlify-cache-tag']).toBe(`_n_t_/en${pagePath}`) expect(headers1ExplicitLocale['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const date1ExplicitLocale = await page.textContent('[data-testid="date-now"]') @@ -545,7 +545,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers1Json['x-nextjs-cache']).toBeUndefined() expect(headers1Json['netlify-cache-tag']).toBe(`_n_t_/en${pagePath}`) expect(headers1Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data1 = (await response1Json?.json()) || {} expect(data1?.pageProps?.time).toBe(date1ImplicitLocale) @@ -573,7 +573,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers2ImplicitLocale['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2ImplicitLocale['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page is cached @@ -603,7 +603,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers2ExplicitLocale['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2ExplicitLocale['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page is cached @@ -634,7 +634,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers2Json['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data2 = (await response2Json?.json()) || {} @@ -728,7 +728,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers3Json['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers3Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data3 = (await response3Json?.json()) || {} @@ -817,7 +817,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(response4Json?.status()).toBe(200) expect(headers4Json['x-nextjs-cache']).toBeUndefined() expect(headers4Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data4 = (await response4Json?.json()) || {} @@ -863,7 +863,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers1['x-nextjs-cache']).toBeUndefined() expect(headers1['netlify-cache-tag']).toBe(`_n_t_/de${pagePath}`) expect(headers1['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const date1 = await page.textContent('[data-testid="date-now"]') @@ -892,7 +892,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers1Json['x-nextjs-cache']).toBeUndefined() expect(headers1Json['netlify-cache-tag']).toBe(`_n_t_/de${pagePath}`) expect(headers1Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data1 = (await response1Json?.json()) || {} expect(data1?.pageProps?.time).toBe(date1) @@ -920,7 +920,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers2['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page is cached @@ -952,7 +952,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers2Json['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data2 = (await response2Json?.json()) || {} @@ -1019,7 +1019,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(headers3Json['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers3Json['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const data3 = (await response3Json?.json()) || {} @@ -1040,7 +1040,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(await page.textContent('h1')).toBe('404') expect(headers['netlify-cdn-cache-control']).toBe( - 'no-cache, no-store, max-age=0, must-revalidate', + 'no-cache, no-store, max-age=0, must-revalidate, durable', ) expect(headers['cache-control']).toBe('no-cache,no-store,max-age=0,must-revalidate') }) @@ -1056,7 +1056,7 @@ test.describe('Page Router with basePath and i18n', () => { expect(await page.textContent('h1')).toBe('404') expect(headers['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) expect(headers['cache-control']).toBe('public,max-age=0,must-revalidate') }) diff --git a/tests/e2e/simple-app.test.ts b/tests/e2e/simple-app.test.ts index a9f440c331..7fc38bb5a7 100644 --- a/tests/e2e/simple-app.test.ts +++ b/tests/e2e/simple-app.test.ts @@ -12,9 +12,12 @@ test('Renders the Home page correctly', async ({ page, simple }) => { await expect(page).toHaveTitle('Simple Next App') - expect(headers['cache-status']).toBe( - '"Next.js"; hit\n"Netlify Durable"; fwd=miss\n"Netlify Edge"; fwd=miss', - ) + expect(headers['cache-status']).toMatch(/^"Next.js"; hit$/m) + expect(headers['cache-status']).toMatch(/^"Netlify Edge"; fwd=miss$/m) + // "Netlify Durable" assertion is skipped because we are asserting index page and there are possible that something else is making similar request to it + // and as a result we can see many possible statuses for it: `fwd=miss`, `fwd=miss; stored`, `hit; ttl=` so there is no point in asserting on that + // "Netlify Edge" status suffers from similar issue, but is less likely to manifest (only if those requests would be handled by same CDN node) and retries + // usually allow to pass the test const h1 = page.locator('h1') await expect(h1).toHaveText('Home') @@ -222,7 +225,7 @@ test('requesting a non existing page route that needs to be fetched from the blo expect(headers['netlify-cdn-cache-control']).toBe( (shouldHavePrivateDirective ? 'private, ' : '') + - 'no-cache, no-store, max-age=0, must-revalidate', + 'no-cache, no-store, max-age=0, must-revalidate, durable', ) expect(headers['cache-control']).toBe( (shouldHavePrivateDirective ? 'private,' : '') + 'no-cache,no-store,max-age=0,must-revalidate', @@ -240,7 +243,7 @@ test('requesting a non existing page route that needs to be fetched from the blo expect(await page.textContent('h1')).toBe('404 Not Found') expect(headers['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) expect(headers['cache-control']).toBe('public,max-age=0,must-revalidate') }) diff --git a/tests/e2e/turborepo.test.ts b/tests/e2e/turborepo.test.ts index 77d8426f9a..9afecccd9d 100644 --- a/tests/e2e/turborepo.test.ts +++ b/tests/e2e/turborepo.test.ts @@ -35,7 +35,7 @@ test.describe('[PNPM] Package manager', () => { expect(response1?.status()).toBe(200) expect(headers1['x-nextjs-cache']).toBeUndefined() expect(headers1['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const date1 = await page.textContent('[data-testid="date-now"]') @@ -65,7 +65,7 @@ test.describe('[PNPM] Package manager', () => { expect(headers2['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page is cached @@ -139,7 +139,7 @@ test.describe('[NPM] Package manager', () => { expect(response1?.status()).toBe(200) expect(headers1['x-nextjs-cache']).toBeUndefined() expect(headers1['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) const date1 = await page.textContent('[data-testid="date-now"]') @@ -169,7 +169,7 @@ test.describe('[NPM] Package manager', () => { expect(headers2['cache-status']).toMatch(/"Next.js"; hit/m) } expect(headers2['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) // the page is cached diff --git a/tests/integration/cache-handler.test.ts b/tests/integration/cache-handler.test.ts index afc308de24..6d37909b2a 100644 --- a/tests/integration/cache-handler.test.ts +++ b/tests/integration/cache-handler.test.ts @@ -88,7 +88,7 @@ describe('page router', () => { ).toEqual( expect.objectContaining({ 'cache-status': '"Next.js"; hit', - 'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate=31536000, durable', }), ) expect( @@ -239,7 +239,7 @@ describe('app router', () => { // It will be hit instead of stale expect.objectContaining({ 'cache-status': '"Next.js"; hit', - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) expect( diff --git a/tests/integration/fetch-handler.test.ts b/tests/integration/fetch-handler.test.ts index 1cdd079849..8d8905968a 100644 --- a/tests/integration/fetch-handler.test.ts +++ b/tests/integration/fetch-handler.test.ts @@ -229,7 +229,7 @@ test('if the fetch call is cached correctly (cached page res ).toEqual( expect.objectContaining({ 'cache-status': '"Next.js"; hit', - 'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate=31536000, durable', }), ) @@ -295,7 +295,7 @@ test('if the fetch call is cached correctly (cached page res ).toEqual( expect.objectContaining({ 'cache-status': '"Next.js"; hit', - 'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate=31536000, durable', }), ) }) diff --git a/tests/integration/page-router.test.ts b/tests/integration/page-router.test.ts index 8561901570..c246a47748 100644 --- a/tests/integration/page-router.test.ts +++ b/tests/integration/page-router.test.ts @@ -121,7 +121,7 @@ test.skipIf(platform === 'win32')( url: '/static/fully-static', }) - expect(response.headers?.['netlify-cdn-cache-control']).toBe('max-age=31536000') + expect(response.headers?.['netlify-cdn-cache-control']).toBe('max-age=31536000, durable') expect(response.headers?.['cache-control']).toBe('public, max-age=0, must-revalidate') }, ) diff --git a/tests/integration/revalidate-path.test.ts b/tests/integration/revalidate-path.test.ts index 0e6f8a2a0d..342872e1e3 100644 --- a/tests/integration/revalidate-path.test.ts +++ b/tests/integration/revalidate-path.test.ts @@ -67,7 +67,7 @@ test('should revalidate a route by path', async (ctx) => { expect(post1.headers, 'a cache hit on the first invocation of a prerendered page').toEqual( expect.objectContaining({ 'cache-status': expect.stringMatching(/"Next.js"; hit/), - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) @@ -82,7 +82,7 @@ test('should revalidate a route by path', async (ctx) => { expect(post1Route2.headers, 'a cache hit on the first invocation of a prerendered page').toEqual( expect.objectContaining({ 'cache-status': expect.stringMatching(/"Next.js"; hit/), - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) @@ -110,7 +110,7 @@ test('should revalidate a route by path', async (ctx) => { expect(post2.headers, 'a cache miss on the on demand revalidated path /1').toEqual( expect.objectContaining({ 'cache-status': '"Next.js"; fwd=miss', - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) expect(post2Date).not.toBe(post1Date) @@ -127,7 +127,7 @@ test('should revalidate a route by path', async (ctx) => { expect(post2Route2.headers, 'a cache miss on the on demand revalidated path /2').toEqual( expect.objectContaining({ 'cache-status': '"Next.js"; fwd=miss', - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) diff --git a/tests/integration/revalidate-tags.test.ts b/tests/integration/revalidate-tags.test.ts index 714a6eae0c..9b48c23956 100644 --- a/tests/integration/revalidate-tags.test.ts +++ b/tests/integration/revalidate-tags.test.ts @@ -67,7 +67,7 @@ test('should revalidate a route by tag', async (ctx) => { expect(post1.headers, 'a cache hit on the first invocation of a prerendered page').toEqual( expect.objectContaining({ 'cache-status': expect.stringMatching(/"Next.js"; hit/), - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) @@ -94,7 +94,7 @@ test('should revalidate a route by tag', async (ctx) => { expect(post2.headers, 'a cache miss on the on demand revalidated page').toEqual( expect.objectContaining({ 'cache-status': '"Next.js"; fwd=miss', - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) expect(post2Date).not.toBe(post1Date) @@ -117,7 +117,7 @@ test('should revalidate a route by tag', async (ctx) => { expect(post3.headers, 'a cache hit on the revalidated and regenerated page').toEqual( expect.objectContaining({ 'cache-status': expect.stringMatching(/"Next.js"; hit/), - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) expect(post3Date).toBe(post2Date) @@ -146,7 +146,7 @@ test('should revalidate a route by tag', async (ctx) => { expect(post4.headers, 'a cache miss on the on demand revalidated page').toEqual( expect.objectContaining({ 'cache-status': '"Next.js"; fwd=miss', - 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000', + 'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000, durable', }), ) expect(post4Date).not.toBe(post3Date) diff --git a/tests/integration/simple-app.test.ts b/tests/integration/simple-app.test.ts index 58ccf8be6d..8d5dfcfdb8 100644 --- a/tests/integration/simple-app.test.ts +++ b/tests/integration/simple-app.test.ts @@ -153,7 +153,9 @@ test('stale-while-revalidate headers should be normalized to await createFixture('simple', ctx) await runPlugin(ctx) const index = await invokeFunction(ctx, { url: '/' }) - expect(index.headers?.['netlify-cdn-cache-control']).toContain('stale-while-revalidate=31536000') + expect(index.headers?.['netlify-cdn-cache-control']).toContain( + 'stale-while-revalidate=31536000, durable', + ) }) test('handlers receive correct site domain', async (ctx) => { @@ -185,7 +187,7 @@ test('cacheable route handler is cached on cdn (revalidate=f const permanentlyCachedResponse = await invokeFunction(ctx, { url: '/api/cached-permanent' }) expect(permanentlyCachedResponse.headers['netlify-cdn-cache-control']).toBe( - 's-maxage=31536000, stale-while-revalidate=31536000', + 's-maxage=31536000, stale-while-revalidate=31536000, durable', ) }) @@ -204,7 +206,7 @@ test('cacheable route handler is cached on cdn (revalidate=1 const secondTimeCachedResponse = await invokeFunction(ctx, { url: '/api/cached-revalidate' }) expect(secondTimeCachedResponse.headers['netlify-cdn-cache-control']).toBe( - 's-maxage=15, stale-while-revalidate=31536000', + 's-maxage=15, stale-while-revalidate=31536000, durable', ) }) diff --git a/tests/integration/static.test.ts b/tests/integration/static.test.ts index 14ded6c943..b4f6d6ade4 100644 --- a/tests/integration/static.test.ts +++ b/tests/integration/static.test.ts @@ -52,7 +52,7 @@ test('requesting a non existing page route that needs to be expect(load(call1.body)('h1').text()).toBe('404') expect(call1.headers, 'a cache hit on the first invocation of a prerendered page').toEqual( expect.objectContaining({ - 'netlify-cdn-cache-control': 'no-cache, no-store, max-age=0, must-revalidate', + 'netlify-cdn-cache-control': 'no-cache, no-store, max-age=0, must-revalidate, durable', }), ) }) diff --git a/tests/utils/create-e2e-fixture.ts b/tests/utils/create-e2e-fixture.ts index f1724c8d6a..9718e28711 100644 --- a/tests/utils/create-e2e-fixture.ts +++ b/tests/utils/create-e2e-fixture.ts @@ -428,10 +428,4 @@ export const fixtureFactories = { publishDirectory: 'apps/site/.next', smoke: true, }), - durableCache: () => - createE2EFixture('simple', { - // https://app.netlify.com/sites/next-runtime-testing-durable-cache - // This site has all the Durable Cache feature flags enabled. - siteId: 'a8ceaa01-86fd-4c9a-8563-3769560d452a', - }), } diff --git a/tests/utils/fixture.ts b/tests/utils/fixture.ts index 461b14a346..18ebb328fd 100644 --- a/tests/utils/fixture.ts +++ b/tests/utils/fixture.ts @@ -336,9 +336,7 @@ export async function uploadBlobs(ctx: FixtureTestContext, blobsDir: string) { ) } -const DEFAULT_FLAGS = { - serverless_functions_nextjs_durable_cache_disable: true, -} +const DEFAULT_FLAGS = {} /** * Execute the function with the provided parameters * @param ctx From 2442411f728bc7becaaf2c5cc0e901ddbc6ca576 Mon Sep 17 00:00:00 2001 From: pieh Date: Wed, 21 Aug 2024 13:55:17 +0200 Subject: [PATCH 2/2] fix: remove feature flag from code as it's fully rolled out --- src/run/handlers/server.ts | 4 +- src/run/headers.test.ts | 124 +++---------------- src/run/headers.ts | 8 +- tests/integration/run/server-handler.test.ts | 56 --------- 4 files changed, 21 insertions(+), 171 deletions(-) delete mode 100644 tests/integration/run/server-handler.test.ts diff --git a/src/run/handlers/server.ts b/src/run/handlers/server.ts index 1037b4777d..d7dd4c5c0a 100644 --- a/src/run/handlers/server.ts +++ b/src/run/handlers/server.ts @@ -112,9 +112,7 @@ export default async (request: Request, context: FutureContext) => { await adjustDateHeader({ headers: response.headers, request, span, tracer, requestContext }) - const useDurableCache = - context.flags.get('serverless_functions_nextjs_durable_cache_disable') !== true - setCacheControlHeaders(response.headers, request, requestContext, useDurableCache) + setCacheControlHeaders(response.headers, request, requestContext) setCacheTagsHeaders(response.headers, requestContext) setVaryHeaders(response.headers, request, nextConfig) setCacheStatusHeader(response.headers) diff --git a/src/run/headers.test.ts b/src/run/headers.test.ts index 4419559e3b..c72d7b7f54 100644 --- a/src/run/headers.test.ts +++ b/src/run/headers.test.ts @@ -194,96 +194,6 @@ describe('headers', () => { describe('setCacheControlHeaders', () => { const defaultUrl = 'https://example.com' - describe('Durable Cache feature flag disabled', () => { - test('should set permanent, non-durable "netlify-cdn-cache-control" if "cache-control" is not set and "requestContext.usedFsRead" is truthy', () => { - const headers = new Headers() - const request = new Request(defaultUrl) - vi.spyOn(headers, 'set') - - const requestContext = createRequestContext() - requestContext.usedFsRead = true - - setCacheControlHeaders(headers, request, requestContext, false) - - expect(headers.set).toHaveBeenNthCalledWith( - 1, - 'cache-control', - 'public, max-age=0, must-revalidate', - ) - expect(headers.set).toHaveBeenNthCalledWith( - 2, - 'netlify-cdn-cache-control', - 'max-age=31536000', - ) - }) - - describe('route handler responses with a specified `revalidate` value', () => { - test('should set non-durable SWC=1yr with 1yr TTL if "{netlify-,}cdn-cache-control" is not present and `revalidate` is `false` (GET)', () => { - const headers = new Headers() - const request = new Request(defaultUrl) - vi.spyOn(headers, 'set') - - const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: false } - setCacheControlHeaders(headers, request, ctx, false) - - expect(headers.set).toHaveBeenCalledTimes(1) - expect(headers.set).toHaveBeenNthCalledWith( - 1, - 'netlify-cdn-cache-control', - 's-maxage=31536000, stale-while-revalidate=31536000', - ) - }) - - test('should set non-durable SWC=1yr with 1yr TTL if "{netlify-,}cdn-cache-control" is not present and `revalidate` is `false` (HEAD)', () => { - const headers = new Headers() - const request = new Request(defaultUrl, { method: 'HEAD' }) - vi.spyOn(headers, 'set') - - const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: false } - setCacheControlHeaders(headers, request, ctx, false) - - expect(headers.set).toHaveBeenCalledTimes(1) - expect(headers.set).toHaveBeenNthCalledWith( - 1, - 'netlify-cdn-cache-control', - 's-maxage=31536000, stale-while-revalidate=31536000', - ) - }) - - test('should set non-durable SWC=1yr with given TTL if "{netlify-,}cdn-cache-control" is not present and `revalidate` is a number (GET)', () => { - const headers = new Headers() - const request = new Request(defaultUrl) - vi.spyOn(headers, 'set') - - const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: 7200 } - setCacheControlHeaders(headers, request, ctx, false) - - expect(headers.set).toHaveBeenCalledTimes(1) - expect(headers.set).toHaveBeenNthCalledWith( - 1, - 'netlify-cdn-cache-control', - 's-maxage=7200, stale-while-revalidate=31536000', - ) - }) - - test('should set non-durable SWC=1yr with 1yr TTL if "{netlify-,}cdn-cache-control" is not present and `revalidate` is a number (HEAD)', () => { - const headers = new Headers() - const request = new Request(defaultUrl, { method: 'HEAD' }) - vi.spyOn(headers, 'set') - - const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: 7200 } - setCacheControlHeaders(headers, request, ctx, false) - - expect(headers.set).toHaveBeenCalledTimes(1) - expect(headers.set).toHaveBeenNthCalledWith( - 1, - 'netlify-cdn-cache-control', - 's-maxage=7200, stale-while-revalidate=31536000', - ) - }) - }) - }) - describe('route handler responses with a specified `revalidate` value', () => { test('should not set any headers if "cdn-cache-control" is present', () => { const givenHeaders = { @@ -294,7 +204,7 @@ describe('headers', () => { vi.spyOn(headers, 'set') const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: false } - setCacheControlHeaders(headers, request, ctx, true) + setCacheControlHeaders(headers, request, ctx) expect(headers.set).toHaveBeenCalledTimes(0) }) @@ -308,7 +218,7 @@ describe('headers', () => { vi.spyOn(headers, 'set') const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: false } - setCacheControlHeaders(headers, request, ctx, true) + setCacheControlHeaders(headers, request, ctx) expect(headers.set).toHaveBeenCalledTimes(0) }) @@ -322,7 +232,7 @@ describe('headers', () => { vi.spyOn(headers, 'set') const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: false } - setCacheControlHeaders(headers, request, ctx, true) + setCacheControlHeaders(headers, request, ctx) expect(headers.set).toHaveBeenCalledTimes(1) expect(headers.set).toHaveBeenNthCalledWith( @@ -341,7 +251,7 @@ describe('headers', () => { vi.spyOn(headers, 'set') const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: false } - setCacheControlHeaders(headers, request, ctx, true) + setCacheControlHeaders(headers, request, ctx) expect(headers.set).toHaveBeenCalledTimes(1) expect(headers.set).toHaveBeenNthCalledWith( @@ -357,7 +267,7 @@ describe('headers', () => { vi.spyOn(headers, 'set') const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: false } - setCacheControlHeaders(headers, request, ctx, true) + setCacheControlHeaders(headers, request, ctx) expect(headers.set).toHaveBeenCalledTimes(1) expect(headers.set).toHaveBeenNthCalledWith( @@ -373,7 +283,7 @@ describe('headers', () => { vi.spyOn(headers, 'set') const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: 7200 } - setCacheControlHeaders(headers, request, ctx, true) + setCacheControlHeaders(headers, request, ctx) expect(headers.set).toHaveBeenCalledTimes(1) expect(headers.set).toHaveBeenNthCalledWith( @@ -389,7 +299,7 @@ describe('headers', () => { vi.spyOn(headers, 'set') const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: 7200 } - setCacheControlHeaders(headers, request, ctx, true) + setCacheControlHeaders(headers, request, ctx) expect(headers.set).toHaveBeenCalledTimes(1) expect(headers.set).toHaveBeenNthCalledWith( @@ -405,7 +315,7 @@ describe('headers', () => { vi.spyOn(headers, 'set') const ctx: RequestContext = { ...createRequestContext(), routeHandlerRevalidate: false } - setCacheControlHeaders(headers, request, ctx, true) + setCacheControlHeaders(headers, request, ctx) expect(headers.set).toHaveBeenCalledTimes(0) }) @@ -416,7 +326,7 @@ describe('headers', () => { const request = new Request(defaultUrl) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenCalledTimes(0) }) @@ -452,7 +362,7 @@ describe('headers', () => { const request = new Request(defaultUrl) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenCalledTimes(0) }) @@ -466,7 +376,7 @@ describe('headers', () => { const request = new Request(defaultUrl) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenCalledTimes(0) }) @@ -479,7 +389,7 @@ describe('headers', () => { const request = new Request(defaultUrl) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenNthCalledWith( 1, @@ -501,7 +411,7 @@ describe('headers', () => { const request = new Request(defaultUrl, { method: 'HEAD' }) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenNthCalledWith( 1, @@ -523,7 +433,7 @@ describe('headers', () => { const request = new Request(defaultUrl, { method: 'POST' }) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenCalledTimes(0) }) @@ -536,7 +446,7 @@ describe('headers', () => { const request = new Request(defaultUrl) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenNthCalledWith(1, 'cache-control', 'public') expect(headers.set).toHaveBeenNthCalledWith( @@ -554,7 +464,7 @@ describe('headers', () => { const request = new Request(defaultUrl) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenNthCalledWith(1, 'cache-control', 'max-age=604800') expect(headers.set).toHaveBeenNthCalledWith( @@ -572,7 +482,7 @@ describe('headers', () => { const request = new Request(defaultUrl) vi.spyOn(headers, 'set') - setCacheControlHeaders(headers, request, createRequestContext(), true) + setCacheControlHeaders(headers, request, createRequestContext()) expect(headers.set).toHaveBeenNthCalledWith( 1, diff --git a/src/run/headers.ts b/src/run/headers.ts index 7d356fd4dc..d12f583cea 100644 --- a/src/run/headers.ts +++ b/src/run/headers.ts @@ -213,9 +213,7 @@ export const setCacheControlHeaders = ( headers: Headers, request: Request, requestContext: RequestContext, - useDurableCache: boolean, ) => { - const durableCacheDirective = useDurableCache ? ', durable' : '' if ( typeof requestContext.routeHandlerRevalidate !== 'undefined' && ['GET', 'HEAD'].includes(request.method) && @@ -227,7 +225,7 @@ export const setCacheControlHeaders = ( // if we are serving already stale response, instruct edge to not attempt to cache that response headers.get('x-nextjs-cache') === 'STALE' ? 'public, max-age=0, must-revalidate' - : `s-maxage=${requestContext.routeHandlerRevalidate === false ? 31536000 : requestContext.routeHandlerRevalidate}, stale-while-revalidate=31536000${durableCacheDirective}` + : `s-maxage=${requestContext.routeHandlerRevalidate === false ? 31536000 : requestContext.routeHandlerRevalidate}, stale-while-revalidate=31536000, durable` headers.set('netlify-cdn-cache-control', cdnCacheControl) return @@ -253,7 +251,7 @@ export const setCacheControlHeaders = ( ...getHeaderValueArray(cacheControl).map((value) => value === 'stale-while-revalidate' ? 'stale-while-revalidate=31536000' : value, ), - ...(useDurableCache ? ['durable'] : []), + 'durable', ].join(', ') headers.set('cache-control', browserCacheControl || 'public, max-age=0, must-revalidate') @@ -269,7 +267,7 @@ export const setCacheControlHeaders = ( ) { // handle CDN Cache Control on static files headers.set('cache-control', 'public, max-age=0, must-revalidate') - headers.set('netlify-cdn-cache-control', `max-age=31536000${durableCacheDirective}`) + headers.set('netlify-cdn-cache-control', `max-age=31536000, durable`) } } diff --git a/tests/integration/run/server-handler.test.ts b/tests/integration/run/server-handler.test.ts deleted file mode 100644 index f649878850..0000000000 --- a/tests/integration/run/server-handler.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { getLogger } from 'lambda-local' -import { v4 } from 'uuid' -import { beforeEach, describe, expect, test, vi } from 'vitest' -import { type FixtureTestContext } from '../../utils/contexts.js' -import { createFixture, invokeFunction, runPlugin } from '../../utils/fixture.js' -import { generateRandomObjectID, startMockBlobStore } from '../../utils/helpers.js' - -// Disable the verbose logging of the lambda-local runtime -getLogger().level = 'alert' - -beforeEach(async (ctx) => { - // set for each test a new deployID and siteID - ctx.deployID = generateRandomObjectID() - ctx.siteID = v4() - vi.stubEnv('SITE_ID', ctx.siteID) - vi.stubEnv('DEPLOY_ID', ctx.deployID) - // hide debug logs in tests - vi.spyOn(console, 'debug').mockImplementation(() => {}) - - await startMockBlobStore(ctx) -}) - -describe('`serverless_functions_nextjs_durable_cache_disable` feature flag', () => { - test('uses durable cache when flag is nil', async (ctx) => { - await createFixture('simple', ctx) - await runPlugin(ctx) - - const { headers } = await invokeFunction(ctx, { - flags: { serverless_functions_nextjs_durable_cache_disable: undefined }, - }) - - expect(headers['netlify-cdn-cache-control']).toContain('durable') - }) - - test('uses durable cache when flag is `false`', async (ctx) => { - await createFixture('simple', ctx) - await runPlugin(ctx) - - const { headers } = await invokeFunction(ctx, { - flags: { serverless_functions_nextjs_durable_cache_disable: false }, - }) - - expect(headers['netlify-cdn-cache-control']).toContain('durable') - }) - - test('does not use durable cache when flag is `true`', async (ctx) => { - await createFixture('simple', ctx) - await runPlugin(ctx) - - const { headers } = await invokeFunction(ctx, { - flags: { serverless_functions_nextjs_durable_cache_disable: true }, - }) - - expect(headers['netlify-cdn-cache-control']).not.toContain('durable') - }) -})