2022-09-19 20:05:28 +02:00
import globOrig from 'glob'
import cheerio from 'cheerio'
import { promisify } from 'util'
2022-12-21 14:16:52 +01:00
import { join } from 'path'
2022-12-19 10:20:01 +01:00
import { createNextDescribe } from 'e2e-utils'
2023-01-25 20:51:53 +01:00
import { check , fetchViaHTTP , normalizeRegEx , waitFor } from 'next-test-utils'
2023-01-23 22:25:00 +01:00
import stripAnsi from 'strip-ansi'
2022-09-19 20:05:28 +02:00
const glob = promisify ( globOrig )
2022-12-19 10:20:01 +01:00
createNextDescribe (
'app-dir static/dynamic handling' ,
{
2022-12-21 14:16:52 +01:00
files : __dirname ,
2023-01-23 22:25:00 +01:00
env : {
NEXT_DEBUG_BUILD : '1' ,
2023-05-10 22:59:48 +02:00
NEXT_PRIVATE_DEBUG_CACHE : '1' ,
2023-02-23 18:33:08 +01:00
. . . ( process . env . CUSTOM_CACHE_HANDLER
? {
CUSTOM_CACHE_HANDLER : process.env.CUSTOM_CACHE_HANDLER ,
}
: { } ) ,
2023-01-23 22:25:00 +01:00
} ,
2022-12-19 10:20:01 +01:00
} ,
2023-02-23 10:19:59 +01:00
( { next , isNextDev : isDev , isNextStart , isNextDeploy } ) = > {
2023-03-08 07:59:06 +01:00
let prerenderManifest
2023-05-08 22:19:41 +02:00
let buildCliOutputIndex = 0
2023-03-08 07:59:06 +01:00
beforeAll ( async ( ) = > {
if ( isNextStart ) {
prerenderManifest = JSON . parse (
await next . readFile ( '.next/prerender-manifest.json' )
)
2023-05-08 22:19:41 +02:00
buildCliOutputIndex = next . cliOutput . length
2023-03-08 07:59:06 +01:00
}
} )
2023-05-23 01:13:02 +02:00
it . each ( [
{
path : '/react-fetch-deduping-node' ,
} ,
{
path : '/react-fetch-deduping-edge' ,
} ,
] ) (
'should correctly de-dupe fetch without next cache $path' ,
async ( { path } ) = > {
for ( let i = 0 ; i < 5 ; i ++ ) {
const res = await next . fetch ( path , {
redirect : 'manual' ,
} )
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const data1 = $ ( '#data-1' ) . text ( )
const data2 = $ ( '#data-2' ) . text ( )
expect ( data1 ) . toBeTruthy ( )
expect ( data1 ) . toBe ( data2 )
await waitFor ( 250 )
}
}
)
2023-05-10 22:59:48 +02:00
it . each ( [
{ pathname : '/unstable-cache-node' } ,
{ pathname : '/unstable-cache-edge' } ,
{ pathname : '/api/unstable-cache-node' } ,
{ pathname : '/api/unstable-cache-edge' } ,
] ) ( 'unstable-cache should work in pages$pathname' , async ( { pathname } ) = > {
let res = await next . fetch ( pathname )
expect ( res . status ) . toBe ( 200 )
const isApi = pathname . startsWith ( '/api' )
let prevData
if ( isApi ) {
prevData = await res . json ( )
} else {
const initialHtml = await res . text ( )
const initial $ = isApi ? undefined : cheerio . load ( initialHtml )
prevData = JSON . parse ( initial $ ( '#props' ) . text ( ) )
}
expect ( prevData . data . random ) . toBeTruthy ( )
await check ( async ( ) = > {
res = await next . fetch ( pathname )
expect ( res . status ) . toBe ( 200 )
let curData
if ( isApi ) {
curData = await res . json ( )
} else {
const curHtml = await res . text ( )
const cur $ = cheerio . load ( curHtml )
curData = JSON . parse ( cur $ ( '#props' ) . text ( ) )
}
2023-05-11 05:42:25 +02:00
try {
expect ( curData . data . random ) . toBeTruthy ( )
expect ( curData . data . random ) . toBe ( prevData . data . random )
} finally {
prevData = curData
}
2023-05-10 22:59:48 +02:00
return 'success'
} , 'success' )
} )
2023-05-02 17:19:02 +02:00
it ( 'should not have cache tags header for non-minimal mode' , async ( ) = > {
for ( const path of [
'/ssr-forced' ,
'/ssr-forced' ,
'/variable-revalidate/revalidate-3' ,
'/variable-revalidate/revalidate-360' ,
'/variable-revalidate/revalidate-360-isr' ,
] ) {
const res = await fetchViaHTTP ( next . url , path , undefined , {
redirect : 'manual' ,
} )
expect ( res . status ) . toBe ( 200 )
expect ( res . headers . get ( 'x-next-cache-tags' ) ) . toBeFalsy ( )
}
} )
2023-03-13 01:05:35 +01:00
if ( isDev ) {
it ( 'should error correctly for invalid params from generateStaticParams' , async ( ) = > {
await next . patchFile (
'app/invalid/[slug]/page.js' ,
`
export function generateStaticParams() {
return [ { slug : { invalid : true } } ]
}
`
)
const html = await next . render ( '/invalid/first' )
await next . deleteFile ( 'app/invalid/[slug]/page.js' )
expect ( html ) . toContain (
'A required parameter (slug) was not provided as a string received object'
)
} )
2023-04-07 19:56:40 +02:00
it ( 'should correctly handle multi-level generateStaticParams when some levels are missing' , async ( ) = > {
const browser = await next . browser ( '/flight/foo/bar' )
const v = ~ ~ ( Math . random ( ) * 1000 )
await browser . eval ( ` document.cookie = "test-cookie= ${ v } " ` )
await browser . elementByCss ( 'button' ) . click ( )
await check ( async ( ) = > {
return await browser . elementByCss ( 'h1' ) . text ( )
} , v . toString ( ) )
} )
2023-03-13 01:05:35 +01:00
}
2023-03-21 18:24:21 +01:00
it ( 'should correctly skip caching POST fetch for POST handler' , async ( ) = > {
const res = await next . fetch ( '/route-handler/post' , {
method : 'POST' ,
} )
expect ( res . status ) . toBe ( 200 )
const data = await res . json ( )
expect ( data ) . toBeTruthy ( )
for ( let i = 0 ; i < 5 ; i ++ ) {
const res2 = await next . fetch ( '/route-handler/post' , {
method : 'POST' ,
} )
expect ( res2 . status ) . toBe ( 200 )
const newData = await res2 . json ( )
expect ( newData ) . toBeTruthy ( )
expect ( newData ) . not . toEqual ( data )
}
} )
2023-04-20 00:12:21 +02:00
if ( ! process . env . CUSTOM_CACHE_HANDLER ) {
it . each ( [
{
type : 'edge route handler' ,
revalidateApi : '/api/revalidate-tag-edge' ,
} ,
{
type : 'node route handler' ,
revalidateApi : '/api/revalidate-tag-node' ,
} ,
] ) (
'it should revalidate tag correctly with $type' ,
async ( { revalidateApi } ) = > {
const initRes = await next . fetch (
'/variable-revalidate/revalidate-360'
)
const html = await initRes . text ( )
const $ = cheerio . load ( html )
const initLayoutData = $ ( '#layout-data' ) . text ( )
const initPageData = $ ( '#page-data' ) . text ( )
const routeHandlerRes = await next . fetch (
'/route-handler/revalidate-360'
)
const initRouteHandlerData = await routeHandlerRes . json ( )
const edgeRouteHandlerRes = await next . fetch (
'/route-handler-edge/revalidate-360'
)
const initEdgeRouteHandlerRes = await edgeRouteHandlerRes . json ( )
expect ( initLayoutData ) . toBeTruthy ( )
expect ( initPageData ) . toBeTruthy ( )
await check ( async ( ) = > {
const revalidateRes = await next . fetch (
` ${ revalidateApi } ?tag=thankyounext `
)
expect ( ( await revalidateRes . json ( ) ) . revalidated ) . toBe ( true )
const newRes = await next . fetch (
'/variable-revalidate/revalidate-360'
)
const newHtml = await newRes . text ( )
const new $ = cheerio . load ( newHtml )
const newLayoutData = new $ ( '#layout-data' ) . text ( )
const newPageData = new $ ( '#page-data' ) . text ( )
const newRouteHandlerRes = await next . fetch (
'/route-handler/revalidate-360'
)
const newRouteHandlerData = await newRouteHandlerRes . json ( )
const newEdgeRouteHandlerRes = await next . fetch (
'/route-handler-edge/revalidate-360'
)
const newEdgeRouteHandlerData = await newEdgeRouteHandlerRes . json ( )
expect ( newLayoutData ) . toBeTruthy ( )
expect ( newPageData ) . toBeTruthy ( )
expect ( newRouteHandlerData ) . toBeTruthy ( )
expect ( newEdgeRouteHandlerData ) . toBeTruthy ( )
expect ( newLayoutData ) . not . toBe ( initLayoutData )
expect ( newPageData ) . not . toBe ( initPageData )
expect ( newRouteHandlerData ) . not . toEqual ( initRouteHandlerData )
expect ( newEdgeRouteHandlerData ) . not . toEqual ( initEdgeRouteHandlerRes )
return 'success'
} , 'success' )
}
)
}
// On-Demand Revalidate has not effect in dev since app routes
// aren't considered static until prerendering
2023-05-02 17:19:02 +02:00
if ( ! ( global as any ) . isNextDev && ! process . env . CUSTOM_CACHE_HANDLER ) {
2023-05-08 22:19:41 +02:00
it ( 'should not revalidate / when revalidate is not used' , async ( ) = > {
let prevData
for ( let i = 0 ; i < 5 ; i ++ ) {
const res = await next . fetch ( '/' )
const html = await res . text ( )
const $ = cheerio . load ( html )
const data = $ ( '#page-data' ) . text ( )
expect ( res . status ) . toBe ( 200 )
if ( prevData ) {
expect ( prevData ) . toBe ( data )
prevData = data
}
await waitFor ( 500 )
}
if ( isNextStart ) {
expect ( next . cliOutput . substring ( buildCliOutputIndex ) ) . not . toContain (
'rendering index'
)
}
} )
2023-04-20 00:12:21 +02:00
it . each ( [
{
type : 'edge route handler' ,
revalidateApi : '/api/revalidate-path-edge' ,
} ,
{
type : 'node route handler' ,
revalidateApi : '/api/revalidate-path-node' ,
} ,
] ) (
'it should revalidate correctly with $type' ,
async ( { revalidateApi } ) = > {
const initRes = await next . fetch (
'/variable-revalidate/revalidate-360-isr'
)
const html = await initRes . text ( )
const $ = cheerio . load ( html )
const initLayoutData = $ ( '#layout-data' ) . text ( )
const initPageData = $ ( '#page-data' ) . text ( )
expect ( initLayoutData ) . toBeTruthy ( )
expect ( initPageData ) . toBeTruthy ( )
await check ( async ( ) = > {
const revalidateRes = await next . fetch (
` ${ revalidateApi } ?path=/variable-revalidate/revalidate-360-isr `
)
expect ( ( await revalidateRes . json ( ) ) . revalidated ) . toBe ( true )
const newRes = await next . fetch (
'/variable-revalidate/revalidate-360-isr'
)
const newHtml = await newRes . text ( )
const new $ = cheerio . load ( newHtml )
const newLayoutData = new $ ( '#layout-data' ) . text ( )
const newPageData = new $ ( '#page-data' ) . text ( )
expect ( newLayoutData ) . toBeTruthy ( )
expect ( newPageData ) . toBeTruthy ( )
expect ( newLayoutData ) . not . toBe ( initLayoutData )
expect ( newPageData ) . not . toBe ( initPageData )
return 'success'
} , 'success' )
}
)
}
2023-04-02 06:15:13 +02:00
// On-Demand Revalidate has not effect in dev
2023-04-11 22:26:49 +02:00
if ( ! ( global as any ) . isNextDev && ! process . env . CUSTOM_CACHE_HANDLER ) {
2023-04-02 06:15:13 +02:00
it ( 'should revalidate all fetches during on-demand revalidate' , async ( ) = > {
2023-05-02 17:19:02 +02:00
const initRes = await next . fetch (
'/variable-revalidate/revalidate-360-isr'
)
2023-04-02 06:15:13 +02:00
const html = await initRes . text ( )
const $ = cheerio . load ( html )
const initLayoutData = $ ( '#layout-data' ) . text ( )
const initPageData = $ ( '#page-data' ) . text ( )
expect ( initLayoutData ) . toBeTruthy ( )
expect ( initPageData ) . toBeTruthy ( )
2023-04-11 22:26:49 +02:00
await check ( async ( ) = > {
2023-04-20 00:12:21 +02:00
const revalidateRes = await next . fetch (
'/api/revalidate-path-node?path=/variable-revalidate/revalidate-360-isr'
)
expect ( ( await revalidateRes . json ( ) ) . revalidated ) . toBe ( true )
const newRes = await next . fetch (
'/variable-revalidate/revalidate-360-isr'
)
2023-04-11 22:26:49 +02:00
const newHtml = await newRes . text ( )
const new $ = cheerio . load ( newHtml )
const newLayoutData = new $ ( '#layout-data' ) . text ( )
const newPageData = new $ ( '#page-data' ) . text ( )
expect ( newLayoutData ) . toBeTruthy ( )
expect ( newPageData ) . toBeTruthy ( )
expect ( newLayoutData ) . not . toBe ( initLayoutData )
expect ( newPageData ) . not . toBe ( initPageData )
return 'success'
} , 'success' )
2023-04-02 06:15:13 +02:00
} )
}
it ( 'should correctly handle fetchCache = "force-no-store"' , async ( ) = > {
const initRes = await next . fetch ( '/force-no-store' )
const html = await initRes . text ( )
const $ = cheerio . load ( html )
const initPageData = $ ( '#page-data' ) . text ( )
expect ( initPageData ) . toBeTruthy ( )
const newRes = await next . fetch ( '/force-no-store' )
const newHtml = await newRes . text ( )
const new $ = cheerio . load ( newHtml )
const newPageData = new $ ( '#page-data' ) . text ( )
expect ( newPageData ) . toBeTruthy ( )
expect ( newPageData ) . not . toBe ( initPageData )
} )
2023-03-20 22:58:39 +01:00
if ( ! process . env . CUSTOM_CACHE_HANDLER ) {
it ( 'should revalidate correctly with config and fetch revalidate' , async ( ) = > {
const initial $ = await next . render $ (
'/variable-config-revalidate/revalidate-3'
)
const initialDate = initial $ ( '#date' ) . text ( )
2023-03-27 22:08:23 +02:00
const initialRandomData = initial $ ( '#random-data' ) . text ( )
2023-03-17 22:00:07 +01:00
2023-03-20 22:58:39 +01:00
expect ( initialDate ) . toBeTruthy ( )
2023-03-27 22:08:23 +02:00
expect ( initialRandomData ) . toBeTruthy ( )
2023-03-17 22:00:07 +01:00
2023-03-27 22:08:23 +02:00
let prevInitialDate
let prevInitialRandomData
2023-03-17 22:00:07 +01:00
2023-03-20 22:58:39 +01:00
// wait for a fresh revalidation
await check ( async ( ) = > {
const $ = await next . render $ (
'/variable-config-revalidate/revalidate-3'
)
2023-03-27 22:08:23 +02:00
prevInitialDate = $ ( '#date' ) . text ( )
prevInitialRandomData = $ ( '#random-data' ) . text ( )
2023-03-17 22:00:07 +01:00
2023-03-27 22:08:23 +02:00
expect ( prevInitialDate ) . not . toBe ( initialDate )
expect ( prevInitialRandomData ) . not . toBe ( initialRandomData )
2023-03-20 22:58:39 +01:00
return 'success'
} , 'success' )
2023-03-17 22:00:07 +01:00
2023-03-20 22:58:39 +01:00
// the date should revalidate first after 3 seconds
2023-03-27 22:08:23 +02:00
// while the fetch data stays in place for 9 seconds
2023-03-20 22:58:39 +01:00
await check ( async ( ) = > {
const $ = await next . render $ (
'/variable-config-revalidate/revalidate-3'
)
2023-03-27 22:08:23 +02:00
const curDate = $ ( '#date' ) . text ( )
const curRandomData = $ ( '#random-data' ) . text ( )
expect ( curDate ) . not . toBe ( prevInitialDate )
2023-04-20 00:12:21 +02:00
expect ( curRandomData ) . not . toBe ( prevInitialRandomData )
2023-03-27 22:08:23 +02:00
2023-04-20 00:12:21 +02:00
prevInitialDate = curDate
prevInitialRandomData = curRandomData
2023-03-20 22:58:39 +01:00
return 'success'
} , 'success' )
} )
}
2023-03-17 22:00:07 +01:00
2023-04-06 20:41:15 +02:00
it ( 'should not cache non-ok statusCode' , async ( ) = > {
2023-04-14 07:00:20 +02:00
await check ( async ( ) = > {
const $ = await next . render $ ( '/variable-revalidate/status-code' )
const origData = JSON . parse ( $ ( '#page-data' ) . text ( ) )
2023-03-14 05:37:22 +01:00
2023-04-14 07:00:20 +02:00
expect ( origData . status ) . toBe ( 404 )
2023-03-14 05:37:22 +01:00
2023-04-14 07:00:20 +02:00
const new $ = await next . render $ ( '/variable-revalidate/status-code' )
const newData = JSON . parse ( new $ ( '#page-data' ) . text ( ) )
expect ( newData . status ) . toBe ( origData . status )
expect ( newData . text ) . not . toBe ( origData . text )
return 'success'
} , 'success' )
2023-03-14 05:37:22 +01:00
} )
2022-12-19 10:20:01 +01:00
if ( isNextStart ) {
it ( 'should output HTML/RSC files for static paths' , async ( ) = > {
const files = (
await glob ( '**/*' , {
cwd : join ( next . testDir , '.next/server/app' ) ,
} )
2023-03-08 07:59:06 +01:00
)
. filter ( ( file ) = > file . match ( /.*\.(js|html|rsc)$/ ) )
. map ( ( file ) = > {
return file . replace (
/partial-gen-params-no-additional-([\w]{1,})\/([\w]{1,})\/([\d]{1,})/ ,
'partial-gen-params-no-additional-$1/$2/RAND'
)
} )
2022-12-19 10:20:01 +01:00
expect ( files ) . toEqual ( [
'(new)/custom/page.js' ,
2023-04-20 00:12:21 +02:00
'api/revalidate-path-edge/route.js' ,
'api/revalidate-path-node/route.js' ,
'api/revalidate-tag-edge/route.js' ,
'api/revalidate-tag-node/route.js' ,
2022-12-19 10:20:01 +01:00
'blog/[author]/[slug]/page.js' ,
'blog/[author]/page.js' ,
'blog/seb.html' ,
'blog/seb.rsc' ,
'blog/seb/second-post.html' ,
'blog/seb/second-post.rsc' ,
'blog/styfle.html' ,
'blog/styfle.rsc' ,
'blog/styfle/first-post.html' ,
'blog/styfle/first-post.rsc' ,
'blog/styfle/second-post.html' ,
'blog/styfle/second-post.rsc' ,
'blog/tim.html' ,
'blog/tim.rsc' ,
'blog/tim/first-post.html' ,
'blog/tim/first-post.rsc' ,
2023-05-11 05:42:25 +02:00
'default-cache/page.js' ,
2023-02-01 12:20:35 +01:00
'dynamic-error/[id]/page.js' ,
2022-12-19 10:20:01 +01:00
'dynamic-no-gen-params-ssr/[slug]/page.js' ,
'dynamic-no-gen-params/[slug]/page.js' ,
2023-05-11 05:42:25 +02:00
'fetch-no-cache/page.js' ,
2023-04-07 19:56:40 +02:00
'flight/[slug]/[slug2]/page.js' ,
2023-05-11 05:42:25 +02:00
'force-cache.html' ,
'force-cache.rsc' ,
'force-cache/page.js' ,
2023-03-23 15:53:51 +01:00
'force-dynamic-catch-all/[slug]/[[...id]]/page.js' ,
2023-01-18 20:24:48 +01:00
'force-dynamic-no-prerender/[id]/page.js' ,
2023-03-21 21:55:04 +01:00
'force-dynamic-prerender/[slug]/page.js' ,
2023-04-02 06:15:13 +02:00
'force-no-store/page.js' ,
2022-12-19 10:20:01 +01:00
'force-static/[slug]/page.js' ,
'force-static/first.html' ,
'force-static/first.rsc' ,
'force-static/page.js' ,
'force-static/second.html' ,
'force-static/second.rsc' ,
2023-03-02 11:14:56 +01:00
'gen-params-dynamic-revalidate/[slug]/page.js' ,
'gen-params-dynamic-revalidate/one.html' ,
'gen-params-dynamic-revalidate/one.rsc' ,
2023-03-01 08:37:12 +01:00
'gen-params-dynamic/[slug]/page.js' ,
2022-12-19 10:20:01 +01:00
'hooks/use-pathname/[slug]/page.js' ,
'hooks/use-pathname/slug.html' ,
'hooks/use-pathname/slug.rsc' ,
'hooks/use-search-params.html' ,
'hooks/use-search-params.rsc' ,
'hooks/use-search-params/force-static.html' ,
'hooks/use-search-params/force-static.rsc' ,
'hooks/use-search-params/force-static/page.js' ,
'hooks/use-search-params/page.js' ,
'hooks/use-search-params/with-suspense.html' ,
'hooks/use-search-params/with-suspense.rsc' ,
'hooks/use-search-params/with-suspense/page.js' ,
2023-05-08 22:19:41 +02:00
'index.html' ,
'index.rsc' ,
'page.js' ,
2023-03-08 07:59:06 +01:00
'partial-gen-params-no-additional-lang/[lang]/[slug]/page.js' ,
'partial-gen-params-no-additional-lang/en/RAND.html' ,
'partial-gen-params-no-additional-lang/en/RAND.rsc' ,
'partial-gen-params-no-additional-lang/en/first.html' ,
'partial-gen-params-no-additional-lang/en/first.rsc' ,
'partial-gen-params-no-additional-lang/en/second.html' ,
'partial-gen-params-no-additional-lang/en/second.rsc' ,
'partial-gen-params-no-additional-lang/fr/RAND.html' ,
'partial-gen-params-no-additional-lang/fr/RAND.rsc' ,
'partial-gen-params-no-additional-lang/fr/first.html' ,
'partial-gen-params-no-additional-lang/fr/first.rsc' ,
'partial-gen-params-no-additional-lang/fr/second.html' ,
'partial-gen-params-no-additional-lang/fr/second.rsc' ,
'partial-gen-params-no-additional-slug/[lang]/[slug]/page.js' ,
'partial-gen-params-no-additional-slug/en/RAND.html' ,
'partial-gen-params-no-additional-slug/en/RAND.rsc' ,
'partial-gen-params-no-additional-slug/en/first.html' ,
'partial-gen-params-no-additional-slug/en/first.rsc' ,
'partial-gen-params-no-additional-slug/en/second.html' ,
'partial-gen-params-no-additional-slug/en/second.rsc' ,
'partial-gen-params-no-additional-slug/fr/RAND.html' ,
'partial-gen-params-no-additional-slug/fr/RAND.rsc' ,
'partial-gen-params-no-additional-slug/fr/first.html' ,
'partial-gen-params-no-additional-slug/fr/first.rsc' ,
'partial-gen-params-no-additional-slug/fr/second.html' ,
'partial-gen-params-no-additional-slug/fr/second.rsc' ,
'partial-gen-params/[lang]/[slug]/page.js' ,
2023-05-23 01:13:02 +02:00
'react-fetch-deduping-edge/page.js' ,
'react-fetch-deduping-node/page.js' ,
2023-04-20 00:12:21 +02:00
'route-handler-edge/revalidate-360/route.js' ,
2023-03-21 18:24:21 +01:00
'route-handler/post/route.js' ,
2023-05-02 17:19:02 +02:00
'route-handler/revalidate-360-isr/route.js' ,
2023-04-20 00:12:21 +02:00
'route-handler/revalidate-360/route.js' ,
2023-05-11 06:44:11 +02:00
'route-handler/static-cookies/route.js' ,
2023-05-01 23:37:17 +02:00
'ssg-draft-mode.html' ,
'ssg-draft-mode.rsc' ,
'ssg-draft-mode/[[...route]]/page.js' ,
'ssg-draft-mode/test-2.html' ,
'ssg-draft-mode/test-2.rsc' ,
'ssg-draft-mode/test.html' ,
'ssg-draft-mode/test.rsc' ,
2022-12-19 10:20:01 +01:00
'ssr-auto/cache-no-store/page.js' ,
'ssr-auto/fetch-revalidate-zero/page.js' ,
'ssr-forced/page.js' ,
2023-01-18 19:24:35 +01:00
'static-to-dynamic-error-forced/[id]/page.js' ,
'static-to-dynamic-error/[id]/page.js' ,
2023-03-17 22:00:07 +01:00
'variable-config-revalidate/revalidate-3.html' ,
'variable-config-revalidate/revalidate-3.rsc' ,
'variable-config-revalidate/revalidate-3/page.js' ,
2023-04-14 07:00:20 +02:00
'variable-revalidate-edge/body/page.js' ,
2023-02-25 01:44:47 +01:00
'variable-revalidate-edge/encoding/page.js' ,
2023-02-22 08:10:25 +01:00
'variable-revalidate-edge/no-store/page.js' ,
2023-02-25 16:50:51 +01:00
'variable-revalidate-edge/post-method-request/page.js' ,
2023-03-07 06:30:29 +01:00
'variable-revalidate-edge/post-method/page.js' ,
2023-02-22 08:10:25 +01:00
'variable-revalidate-edge/revalidate-3/page.js' ,
2023-03-07 06:30:29 +01:00
'variable-revalidate/authorization.html' ,
'variable-revalidate/authorization.rsc' ,
2023-02-23 08:59:38 +01:00
'variable-revalidate/authorization/page.js' ,
2023-03-07 06:30:29 +01:00
'variable-revalidate/cookie.html' ,
'variable-revalidate/cookie.rsc' ,
2023-02-23 08:59:38 +01:00
'variable-revalidate/cookie/page.js' ,
2023-02-25 01:44:47 +01:00
'variable-revalidate/encoding.html' ,
'variable-revalidate/encoding.rsc' ,
'variable-revalidate/encoding/page.js' ,
2022-12-19 10:20:01 +01:00
'variable-revalidate/no-store/page.js' ,
2023-03-07 06:30:29 +01:00
'variable-revalidate/post-method-request/page.js' ,
'variable-revalidate/post-method.html' ,
'variable-revalidate/post-method.rsc' ,
2023-02-25 01:44:47 +01:00
'variable-revalidate/post-method/page.js' ,
2022-12-19 10:20:01 +01:00
'variable-revalidate/revalidate-3.html' ,
'variable-revalidate/revalidate-3.rsc' ,
'variable-revalidate/revalidate-3/page.js' ,
2023-04-20 00:12:21 +02:00
'variable-revalidate/revalidate-360-isr.html' ,
'variable-revalidate/revalidate-360-isr.rsc' ,
'variable-revalidate/revalidate-360-isr/page.js' ,
2023-04-02 06:15:13 +02:00
'variable-revalidate/revalidate-360/page.js' ,
2023-03-14 05:37:22 +01:00
'variable-revalidate/status-code/page.js' ,
2022-12-19 10:20:01 +01:00
] )
} )
2022-10-25 03:58:10 +02:00
2022-12-19 10:20:01 +01:00
it ( 'should have correct prerender-manifest entries' , async ( ) = > {
2023-03-08 07:59:06 +01:00
const curManifest = JSON . parse ( JSON . stringify ( prerenderManifest ) )
2022-09-19 20:05:28 +02:00
2023-03-08 07:59:06 +01:00
for ( const key of Object . keys ( curManifest . dynamicRoutes ) ) {
const item = curManifest . dynamicRoutes [ key ]
2022-12-19 10:20:01 +01:00
if ( item . dataRouteRegex ) {
item . dataRouteRegex = normalizeRegEx ( item . dataRouteRegex )
}
if ( item . routeRegex ) {
item . routeRegex = normalizeRegEx ( item . routeRegex )
}
2023-03-08 07:59:06 +01:00
}
for ( const key of Object . keys ( curManifest . routes ) ) {
const newKey = key . replace (
/partial-gen-params-no-additional-([\w]{1,})\/([\w]{1,})\/([\d]{1,})/ ,
'partial-gen-params-no-additional-$1/$2/RAND'
)
if ( newKey !== key ) {
const route = curManifest . routes [ key ]
delete curManifest . routes [ key ]
curManifest . routes [ newKey ] = {
. . . route ,
dataRoute : ` ${ newKey } .rsc ` ,
}
}
}
2022-09-19 20:05:28 +02:00
2023-03-08 07:59:06 +01:00
expect ( curManifest . version ) . toBe ( 4 )
expect ( curManifest . routes ) . toEqual ( {
2023-05-08 22:19:41 +02:00
'/' : {
initialRevalidateSeconds : false ,
srcRoute : '/' ,
dataRoute : '/index.rsc' ,
} ,
2022-12-19 10:20:01 +01:00
'/blog/tim' : {
initialRevalidateSeconds : 10 ,
srcRoute : '/blog/[author]' ,
dataRoute : '/blog/tim.rsc' ,
} ,
'/blog/seb' : {
initialRevalidateSeconds : 10 ,
srcRoute : '/blog/[author]' ,
dataRoute : '/blog/seb.rsc' ,
} ,
'/blog/styfle' : {
initialRevalidateSeconds : 10 ,
srcRoute : '/blog/[author]' ,
dataRoute : '/blog/styfle.rsc' ,
} ,
'/blog/tim/first-post' : {
initialRevalidateSeconds : false ,
srcRoute : '/blog/[author]/[slug]' ,
dataRoute : '/blog/tim/first-post.rsc' ,
} ,
'/blog/seb/second-post' : {
initialRevalidateSeconds : false ,
srcRoute : '/blog/[author]/[slug]' ,
dataRoute : '/blog/seb/second-post.rsc' ,
} ,
'/blog/styfle/first-post' : {
initialRevalidateSeconds : false ,
srcRoute : '/blog/[author]/[slug]' ,
dataRoute : '/blog/styfle/first-post.rsc' ,
} ,
'/blog/styfle/second-post' : {
initialRevalidateSeconds : false ,
srcRoute : '/blog/[author]/[slug]' ,
dataRoute : '/blog/styfle/second-post.rsc' ,
} ,
2023-05-11 05:42:25 +02:00
'/force-cache' : {
dataRoute : '/force-cache.rsc' ,
initialRevalidateSeconds : 3 ,
srcRoute : '/force-cache' ,
} ,
2022-12-19 10:20:01 +01:00
'/hooks/use-pathname/slug' : {
dataRoute : '/hooks/use-pathname/slug.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/hooks/use-pathname/[slug]' ,
} ,
'/hooks/use-search-params' : {
dataRoute : '/hooks/use-search-params.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/hooks/use-search-params' ,
} ,
'/hooks/use-search-params/force-static' : {
dataRoute : '/hooks/use-search-params/force-static.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/hooks/use-search-params/force-static' ,
} ,
'/hooks/use-search-params/with-suspense' : {
dataRoute : '/hooks/use-search-params/with-suspense.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/hooks/use-search-params/with-suspense' ,
} ,
2023-03-08 07:59:06 +01:00
'/partial-gen-params-no-additional-lang/en/RAND' : {
dataRoute : '/partial-gen-params-no-additional-lang/en/RAND.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-lang/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-lang/en/first' : {
dataRoute : '/partial-gen-params-no-additional-lang/en/first.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-lang/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-lang/en/second' : {
dataRoute : '/partial-gen-params-no-additional-lang/en/second.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-lang/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-lang/fr/RAND' : {
dataRoute : '/partial-gen-params-no-additional-lang/fr/RAND.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-lang/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-lang/fr/first' : {
dataRoute : '/partial-gen-params-no-additional-lang/fr/first.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-lang/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-lang/fr/second' : {
dataRoute : '/partial-gen-params-no-additional-lang/fr/second.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-lang/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-slug/en/RAND' : {
dataRoute : '/partial-gen-params-no-additional-slug/en/RAND.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-slug/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-slug/en/first' : {
dataRoute : '/partial-gen-params-no-additional-slug/en/first.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-slug/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-slug/en/second' : {
dataRoute : '/partial-gen-params-no-additional-slug/en/second.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-slug/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-slug/fr/RAND' : {
dataRoute : '/partial-gen-params-no-additional-slug/fr/RAND.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-slug/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-slug/fr/first' : {
dataRoute : '/partial-gen-params-no-additional-slug/fr/first.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-slug/[lang]/[slug]' ,
} ,
'/partial-gen-params-no-additional-slug/fr/second' : {
dataRoute : '/partial-gen-params-no-additional-slug/fr/second.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/partial-gen-params-no-additional-slug/[lang]/[slug]' ,
} ,
2023-05-01 23:37:17 +02:00
'/ssg-draft-mode' : {
dataRoute : '/ssg-draft-mode.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/ssg-draft-mode/[[...route]]' ,
} ,
'/ssg-draft-mode/test' : {
dataRoute : '/ssg-draft-mode/test.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/ssg-draft-mode/[[...route]]' ,
} ,
'/ssg-draft-mode/test-2' : {
dataRoute : '/ssg-draft-mode/test-2.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/ssg-draft-mode/[[...route]]' ,
} ,
2022-12-19 10:20:01 +01:00
'/force-static/first' : {
dataRoute : '/force-static/first.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/force-static/[slug]' ,
} ,
'/force-static/second' : {
dataRoute : '/force-static/second.rsc' ,
initialRevalidateSeconds : false ,
srcRoute : '/force-static/[slug]' ,
} ,
2023-03-02 11:14:56 +01:00
'/gen-params-dynamic-revalidate/one' : {
dataRoute : '/gen-params-dynamic-revalidate/one.rsc' ,
initialRevalidateSeconds : 3 ,
srcRoute : '/gen-params-dynamic-revalidate/[slug]' ,
} ,
2023-05-02 17:19:02 +02:00
'/route-handler/revalidate-360-isr' : {
dataRoute : null ,
initialHeaders : {
'content-type' : 'application/json' ,
'x-next-cache-tags' :
2023-05-03 02:48:59 +02:00
'thankyounext,/route-handler/revalidate-360-isr/route' ,
2023-05-02 17:19:02 +02:00
} ,
2023-05-08 22:19:41 +02:00
initialRevalidateSeconds : 10 ,
2023-05-02 17:19:02 +02:00
srcRoute : '/route-handler/revalidate-360-isr' ,
} ,
2023-05-11 06:44:11 +02:00
'/route-handler/static-cookies' : {
dataRoute : null ,
initialHeaders : {
'set-cookie' : 'theme=light; Path=/,my_company=ACME; Path=/' ,
'x-next-cache-tags' : '/route-handler/static-cookies/route' ,
} ,
initialRevalidateSeconds : false ,
srcRoute : '/route-handler/static-cookies' ,
} ,
2023-03-17 22:00:07 +01:00
'/variable-config-revalidate/revalidate-3' : {
dataRoute : '/variable-config-revalidate/revalidate-3.rsc' ,
initialRevalidateSeconds : 3 ,
srcRoute : '/variable-config-revalidate/revalidate-3' ,
} ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/authorization' : {
dataRoute : '/variable-revalidate/authorization.rsc' ,
initialRevalidateSeconds : 10 ,
srcRoute : '/variable-revalidate/authorization' ,
2023-02-23 08:59:38 +01:00
} ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/cookie' : {
dataRoute : '/variable-revalidate/cookie.rsc' ,
2023-02-23 08:59:38 +01:00
initialRevalidateSeconds : 3 ,
2023-03-07 06:30:29 +01:00
srcRoute : '/variable-revalidate/cookie' ,
2023-02-23 08:59:38 +01:00
} ,
2023-02-25 01:44:47 +01:00
'/variable-revalidate/encoding' : {
dataRoute : '/variable-revalidate/encoding.rsc' ,
initialRevalidateSeconds : 3 ,
srcRoute : '/variable-revalidate/encoding' ,
} ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/post-method' : {
dataRoute : '/variable-revalidate/post-method.rsc' ,
initialRevalidateSeconds : 10 ,
srcRoute : '/variable-revalidate/post-method' ,
} ,
2022-12-19 10:20:01 +01:00
'/variable-revalidate/revalidate-3' : {
dataRoute : '/variable-revalidate/revalidate-3.rsc' ,
initialRevalidateSeconds : 3 ,
srcRoute : '/variable-revalidate/revalidate-3' ,
} ,
2023-04-20 00:12:21 +02:00
'/variable-revalidate/revalidate-360-isr' : {
dataRoute : '/variable-revalidate/revalidate-360-isr.rsc' ,
2023-04-02 06:15:13 +02:00
initialRevalidateSeconds : 10 ,
2023-04-20 00:12:21 +02:00
srcRoute : '/variable-revalidate/revalidate-360-isr' ,
2023-04-02 06:15:13 +02:00
} ,
2022-12-19 10:20:01 +01:00
} )
2023-03-08 07:59:06 +01:00
expect ( curManifest . dynamicRoutes ) . toEqual ( {
2022-12-19 10:20:01 +01:00
'/blog/[author]/[slug]' : {
routeRegex : normalizeRegEx ( '^/blog/([^/]+?)/([^/]+?)(?:/)?$' ) ,
dataRoute : '/blog/[author]/[slug].rsc' ,
fallback : null ,
dataRouteRegex : normalizeRegEx ( '^/blog/([^/]+?)/([^/]+?)\\.rsc$' ) ,
} ,
'/blog/[author]' : {
dataRoute : '/blog/[author].rsc' ,
dataRouteRegex : normalizeRegEx ( '^\\/blog\\/([^\\/]+?)\\.rsc$' ) ,
fallback : false ,
routeRegex : normalizeRegEx ( '^\\/blog\\/([^\\/]+?)(?:\\/)?$' ) ,
} ,
2023-02-01 12:20:35 +01:00
'/dynamic-error/[id]' : {
dataRoute : '/dynamic-error/[id].rsc' ,
2023-03-08 07:59:06 +01:00
dataRouteRegex : normalizeRegEx (
'^\\/dynamic\\-error\\/([^\\/]+?)\\.rsc$'
) ,
2023-02-01 12:20:35 +01:00
fallback : null ,
2023-03-08 07:59:06 +01:00
routeRegex : normalizeRegEx (
'^\\/dynamic\\-error\\/([^\\/]+?)(?:\\/)?$'
) ,
2023-02-01 12:20:35 +01:00
} ,
2023-03-02 11:14:56 +01:00
'/gen-params-dynamic-revalidate/[slug]' : {
dataRoute : '/gen-params-dynamic-revalidate/[slug].rsc' ,
dataRouteRegex : normalizeRegEx (
'^\\/gen\\-params\\-dynamic\\-revalidate\\/([^\\/]+?)\\.rsc$'
) ,
fallback : null ,
routeRegex : normalizeRegEx (
'^\\/gen\\-params\\-dynamic\\-revalidate\\/([^\\/]+?)(?:\\/)?$'
) ,
} ,
2022-12-19 10:20:01 +01:00
'/hooks/use-pathname/[slug]' : {
dataRoute : '/hooks/use-pathname/[slug].rsc' ,
2023-01-18 19:24:35 +01:00
dataRouteRegex : normalizeRegEx (
'^\\/hooks\\/use\\-pathname\\/([^\\/]+?)\\.rsc$'
) ,
2022-12-19 10:20:01 +01:00
fallback : null ,
2023-01-18 19:24:35 +01:00
routeRegex : normalizeRegEx (
'^\\/hooks\\/use\\-pathname\\/([^\\/]+?)(?:\\/)?$'
) ,
2022-12-19 10:20:01 +01:00
} ,
2023-03-08 07:59:06 +01:00
'/partial-gen-params-no-additional-lang/[lang]/[slug]' : {
dataRoute :
'/partial-gen-params-no-additional-lang/[lang]/[slug].rsc' ,
dataRouteRegex : normalizeRegEx (
'^\\/partial\\-gen\\-params\\-no\\-additional\\-lang\\/([^\\/]+?)\\/([^\\/]+?)\\.rsc$'
) ,
fallback : false ,
routeRegex : normalizeRegEx (
'^\\/partial\\-gen\\-params\\-no\\-additional\\-lang\\/([^\\/]+?)\\/([^\\/]+?)(?:\\/)?$'
) ,
} ,
'/partial-gen-params-no-additional-slug/[lang]/[slug]' : {
dataRoute :
'/partial-gen-params-no-additional-slug/[lang]/[slug].rsc' ,
dataRouteRegex : normalizeRegEx (
'^\\/partial\\-gen\\-params\\-no\\-additional\\-slug\\/([^\\/]+?)\\/([^\\/]+?)\\.rsc$'
) ,
fallback : false ,
routeRegex : normalizeRegEx (
'^\\/partial\\-gen\\-params\\-no\\-additional\\-slug\\/([^\\/]+?)\\/([^\\/]+?)(?:\\/)?$'
) ,
} ,
2023-05-01 23:37:17 +02:00
'/ssg-draft-mode/[[...route]]' : {
dataRoute : '/ssg-draft-mode/[[...route]].rsc' ,
dataRouteRegex : '^\\/ssg\\-draft\\-mode(?:\\/(.+?))?\\.rsc$' ,
fallback : null ,
routeRegex : '^\\/ssg\\-draft\\-mode(?:\\/(.+?))?(?:\\/)?$' ,
} ,
2022-12-19 10:20:01 +01:00
'/force-static/[slug]' : {
dataRoute : '/force-static/[slug].rsc' ,
2023-01-18 19:24:35 +01:00
dataRouteRegex : normalizeRegEx (
'^\\/force\\-static\\/([^\\/]+?)\\.rsc$'
) ,
2022-12-19 10:20:01 +01:00
fallback : null ,
2023-01-18 19:24:35 +01:00
routeRegex : normalizeRegEx (
'^\\/force\\-static\\/([^\\/]+?)(?:\\/)?$'
) ,
2022-12-19 10:20:01 +01:00
} ,
2023-01-18 19:24:35 +01:00
'/static-to-dynamic-error-forced/[id]' : {
dataRoute : '/static-to-dynamic-error-forced/[id].rsc' ,
dataRouteRegex : normalizeRegEx (
'^\\/static\\-to\\-dynamic\\-error\\-forced\\/([^\\/]+?)\\.rsc$'
) ,
fallback : null ,
routeRegex : normalizeRegEx (
'^\\/static\\-to\\-dynamic\\-error\\-forced\\/([^\\/]+?)(?:\\/)?$'
) ,
} ,
2022-12-19 10:20:01 +01:00
} )
} )
2023-01-23 22:25:00 +01:00
it ( 'should output debug info for static bailouts' , async ( ) = > {
const cleanedOutput = stripAnsi ( next . cliOutput )
expect ( cleanedOutput ) . toContain (
'Static generation failed due to dynamic usage on /force-static, reason: headers'
)
expect ( cleanedOutput ) . toContain (
'Static generation failed due to dynamic usage on /ssr-auto/cache-no-store, reason: no-store fetch'
)
} )
2022-12-19 10:20:01 +01:00
}
2022-09-19 20:05:28 +02:00
2023-05-11 05:42:25 +02:00
it ( 'should cache correctly for fetchCache = default-cache' , async ( ) = > {
const res = await next . fetch ( '/default-cache' )
expect ( res . status ) . toBe ( 200 )
let prevHtml = await res . text ( )
let prev $ = cheerio . load ( prevHtml )
await check ( async ( ) = > {
const curRes = await next . fetch ( '/default-cache' )
expect ( curRes . status ) . toBe ( 200 )
const curHtml = await curRes . text ( )
const cur $ = cheerio . load ( curHtml )
try {
expect ( cur $ ( '#data-no-cache' ) . text ( ) ) . not . toBe (
prev $ ( '#data-no-cache' ) . text ( )
)
expect ( cur $ ( '#data-force-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-force-cache' ) . text ( )
)
expect ( cur $ ( '#data-revalidate-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-revalidate-cache' ) . text ( )
)
expect ( cur $ ( '#data-revalidate-and-fetch-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-revalidate-and-fetch-cache' ) . text ( )
)
expect ( cur $ ( '#data-revalidate-and-fetch-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-revalidate-and-fetch-cache' ) . text ( )
)
} finally {
prevHtml = curHtml
prev $ = cur $
}
return 'success'
} , 'success' )
} )
2023-05-19 23:19:56 +02:00
// TODO-APP: investigate flaky test
it . skip ( 'should cache correctly for fetchCache = force-cache' , async ( ) = > {
2023-05-11 05:42:25 +02:00
const res = await next . fetch ( '/force-cache' )
expect ( res . status ) . toBe ( 200 )
let prevHtml = await res . text ( )
let prev $ = cheerio . load ( prevHtml )
await check ( async ( ) = > {
const curRes = await next . fetch ( '/force-cache' )
expect ( curRes . status ) . toBe ( 200 )
const curHtml = await curRes . text ( )
const cur $ = cheerio . load ( curHtml )
expect ( cur $ ( '#data-no-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-no-cache' ) . text ( )
)
expect ( cur $ ( '#data-force-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-force-cache' ) . text ( )
)
expect ( cur $ ( '#data-revalidate-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-revalidate-cache' ) . text ( )
)
expect ( cur $ ( '#data-revalidate-and-fetch-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-revalidate-and-fetch-cache' ) . text ( )
)
expect ( cur $ ( '#data-auto-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-auto-cache' ) . text ( )
)
return 'success'
} , 'success' )
2023-05-19 01:20:05 +02:00
if ( ! isNextDeploy ) {
expect ( next . cliOutput ) . toContain (
'Warning: fetch for https://next-data-api-endpoint.vercel.app/api/random?d4 on /force-cache specified "cache: force-cache" and "revalidate: 3", only one should be specified.'
)
}
2023-05-11 05:42:25 +02:00
} )
it ( 'should cache correctly for cache: no-store' , async ( ) = > {
const res = await next . fetch ( '/fetch-no-cache' )
expect ( res . status ) . toBe ( 200 )
let prevHtml = await res . text ( )
let prev $ = cheerio . load ( prevHtml )
await check ( async ( ) = > {
const curRes = await next . fetch ( '/fetch-no-cache' )
expect ( curRes . status ) . toBe ( 200 )
const curHtml = await curRes . text ( )
const cur $ = cheerio . load ( curHtml )
try {
expect ( cur $ ( '#data-no-cache' ) . text ( ) ) . not . toBe (
prev $ ( '#data-no-cache' ) . text ( )
)
expect ( cur $ ( '#data-force-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-force-cache' ) . text ( )
)
expect ( cur $ ( '#data-revalidate-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-revalidate-cache' ) . text ( )
)
expect ( cur $ ( '#data-revalidate-and-fetch-cache' ) . text ( ) ) . toBe (
prev $ ( '#data-revalidate-and-fetch-cache' ) . text ( )
)
expect ( cur $ ( '#data-auto-cache' ) . text ( ) ) . not . toBe (
prev $ ( '#data-auto-cache' ) . text ( )
)
} finally {
prevHtml = curHtml
prev $ = cur $
}
return 'success'
} , 'success' )
} )
2023-01-25 20:51:53 +01:00
if ( isDev ) {
it ( 'should bypass fetch cache with cache-control: no-cache' , async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
'/variable-revalidate/revalidate-3'
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
const res2 = await fetchViaHTTP (
next . url ,
'/variable-revalidate/revalidate-3' ,
undefined ,
{
headers : {
'cache-control' : 'no-cache' ,
} ,
}
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . not . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . not . toBe ( pageData )
} )
} else {
2023-01-18 19:24:35 +01:00
it ( 'should not error with dynamic server usage with force-static' , async ( ) = > {
const res = await next . fetch (
'/static-to-dynamic-error-forced/static-bailout-1'
)
const outputIndex = next . cliOutput . length
const html = await res . text ( )
expect ( res . status ) . toBe ( 200 )
expect ( html ) . toContain ( '/static-to-dynamic-error-forced' )
expect ( html ) . toMatch ( /id:.*?static-bailout-1/ )
if ( isNextStart ) {
2023-01-23 22:25:00 +01:00
expect ( stripAnsi ( next . cliOutput ) . substring ( outputIndex ) ) . not . toMatch (
/Page changed from static to dynamic at runtime \/static-to-dynamic-error-forced\/static-bailout-1, reason: cookies/
2023-01-18 19:24:35 +01:00
)
}
} )
2023-02-01 12:20:35 +01:00
it ( 'should properly error when dynamic = "error" page uses dynamic' , async ( ) = > {
const res = await next . fetch ( '/dynamic-error/static-bailout-1' )
const outputIndex = next . cliOutput . length
expect ( res . status ) . toBe ( 500 )
if ( isNextStart ) {
expect ( stripAnsi ( next . cliOutput ) . substring ( outputIndex ) ) . not . toMatch (
/Page with dynamic = "error" encountered dynamic data method on \/dynamic-error\/static-bailout-1/
)
}
} )
2023-01-18 19:24:35 +01:00
}
2023-03-08 07:59:06 +01:00
it ( 'should handle partial-gen-params with default dynamicParams correctly' , async ( ) = > {
const res = await next . fetch ( '/partial-gen-params/en/first' )
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const params = JSON . parse ( $ ( '#params' ) . text ( ) )
expect ( params ) . toEqual ( { lang : 'en' , slug : 'first' } )
} )
it ( 'should handle partial-gen-params with layout dynamicParams = false correctly' , async ( ) = > {
for ( const { path , status , params } of [
// these checks don't work with custom memory only
// cache handler
. . . ( process . env . CUSTOM_CACHE_HANDLER
? [ ]
: [
{
path : '/partial-gen-params-no-additional-lang/en/first' ,
status : 200 ,
params : { lang : 'en' , slug : 'first' } ,
} ,
] ) ,
{
path : '/partial-gen-params-no-additional-lang/de/first' ,
status : 404 ,
params : { } ,
} ,
{
path : '/partial-gen-params-no-additional-lang/en/non-existent' ,
status : 404 ,
params : { } ,
} ,
] ) {
const res = await next . fetch ( path )
expect ( res . status ) . toBe ( status )
const html = await res . text ( )
const $ = cheerio . load ( html )
const curParams = JSON . parse ( $ ( '#params' ) . text ( ) || '{}' )
expect ( curParams ) . toEqual ( params )
}
} )
it ( 'should handle partial-gen-params with page dynamicParams = false correctly' , async ( ) = > {
for ( const { path , status , params } of [
// these checks don't work with custom memory only
// cache handler
. . . ( process . env . CUSTOM_CACHE_HANDLER
? [ ]
: [
{
path : '/partial-gen-params-no-additional-slug/en/first' ,
status : 200 ,
params : { lang : 'en' , slug : 'first' } ,
} ,
] ) ,
{
path : '/partial-gen-params-no-additional-slug/de/first' ,
status : 404 ,
params : { } ,
} ,
{
path : '/partial-gen-params-no-additional-slug/en/non-existent' ,
status : 404 ,
params : { } ,
} ,
] ) {
const res = await next . fetch ( path )
expect ( res . status ) . toBe ( status )
const html = await res . text ( )
const $ = cheerio . load ( html )
const curParams = JSON . parse ( $ ( '#params' ) . text ( ) || '{}' )
expect ( curParams ) . toEqual ( params )
}
} )
// fetch cache in generateStaticParams needs fs for persistence
// so doesn't behave as expected with custom in memory only
// cache handler
if ( ! process . env . CUSTOM_CACHE_HANDLER ) {
it ( 'should honor fetch cache in generateStaticParams' , async ( ) = > {
const initialRes = await next . fetch (
` /partial-gen-params-no-additional-lang/en/first `
)
expect ( initialRes . status ) . toBe ( 200 )
// we can't read prerender-manifest from deployment
if ( isNextDeploy ) return
let langFetchSlug
let slugFetchSlug
if ( isDev ) {
await check ( ( ) = > {
const matches = stripAnsi ( next . cliOutput ) . match (
/partial-gen-params fetch ([\d]{1,})/
)
if ( matches [ 1 ] ) {
langFetchSlug = matches [ 1 ]
slugFetchSlug = langFetchSlug
}
return langFetchSlug ? 'success' : next . cliOutput
} , 'success' )
} else {
// the fetch cache can potentially be a miss since
// the generateStaticParams are executed parallel
// in separate workers so parse value from
// prerender-manifest
const routes = Object . keys ( prerenderManifest . routes )
for ( const route of routes ) {
const langSlug = route . match (
/partial-gen-params-no-additional-lang\/en\/([\d]{1,})/
) ? . [ 1 ]
if ( langSlug ) {
langFetchSlug = langSlug
}
const slugSlug = route . match (
/partial-gen-params-no-additional-slug\/en\/([\d]{1,})/
) ? . [ 1 ]
if ( slugSlug ) {
slugFetchSlug = slugSlug
}
}
}
require ( 'console' ) . log ( { langFetchSlug , slugFetchSlug } )
for ( const { pathname , slug } of [
{
pathname : '/partial-gen-params-no-additional-lang/en' ,
slug : langFetchSlug ,
} ,
{
pathname : '/partial-gen-params-no-additional-slug/en' ,
slug : slugFetchSlug ,
} ,
] ) {
const res = await next . fetch ( ` ${ pathname } / ${ slug } ` )
expect ( res . status ) . toBe ( 200 )
expect (
JSON . parse (
cheerio
. load ( await res . text ( ) ) ( '#params' )
. text ( )
)
) . toEqual ( { lang : 'en' , slug } )
}
} )
}
2023-01-25 20:51:53 +01:00
it ( 'should honor fetch cache correctly' , async ( ) = > {
2023-02-23 08:59:38 +01:00
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
'/variable-revalidate/revalidate-3'
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
const res2 = await fetchViaHTTP (
next . url ,
'/variable-revalidate/revalidate-3'
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
return 'success'
} , 'success' )
2023-05-22 22:54:15 +02:00
if ( isNextStart ) {
expect ( next . cliOutput ) . toContain (
` Page "/variable-revalidate-edge/revalidate-3" is using runtime = 'edge' which is currently incompatible with dynamic = 'force-static'. Please remove either "runtime" or "force-static" for correct behavior `
)
}
2023-02-23 08:59:38 +01:00
} )
it ( 'should honor fetch cache correctly (edge)' , async ( ) = > {
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
'/variable-revalidate-edge/revalidate-3'
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
2023-02-23 10:19:59 +01:00
// the test cache handler is simple and doesn't share
// state across workers so not guaranteed to have cache hit
if ( ! ( isNextDeploy && process . env . CUSTOM_CACHE_HANDLER ) ) {
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
2023-02-23 08:59:38 +01:00
2023-02-23 10:19:59 +01:00
const res2 = await fetchViaHTTP (
next . url ,
'/variable-revalidate-edge/revalidate-3'
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
2023-02-23 08:59:38 +01:00
2023-02-23 10:19:59 +01:00
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
}
2023-02-23 08:59:38 +01:00
return 'success'
} , 'success' )
} )
2023-01-25 20:51:53 +01:00
2023-02-23 08:59:38 +01:00
it ( 'should cache correctly with authorization header and revalidate' , async ( ) = > {
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/authorization'
2023-02-23 08:59:38 +01:00
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
2023-02-22 08:10:25 +01:00
2023-02-23 08:59:38 +01:00
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
const res2 = await fetchViaHTTP (
next . url ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/authorization'
2023-02-23 08:59:38 +01:00
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
return 'success'
} , 'success' )
} )
2023-02-25 16:50:51 +01:00
it ( 'should not cache correctly with POST method request init' , async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
'/variable-revalidate-edge/post-method-request'
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
2023-03-07 21:51:37 +01:00
const pageData2 = $ ( '#page-data2' ) . text ( )
2023-02-25 16:50:51 +01:00
for ( let i = 0 ; i < 3 ; i ++ ) {
const res2 = await fetchViaHTTP (
next . url ,
'/variable-revalidate-edge/post-method-request'
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
2023-03-07 21:51:37 +01:00
expect ( $2 ( '#page-data2' ) . text ( ) ) . not . toBe ( pageData2 )
2023-02-25 16:50:51 +01:00
}
} )
it ( 'should cache correctly with post method and revalidate' , async ( ) = > {
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/post-method'
2023-02-25 16:50:51 +01:00
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
const dataBody1 = $ ( '#data-body1' ) . text ( )
const dataBody2 = $ ( '#data-body2' ) . text ( )
const dataBody3 = $ ( '#data-body3' ) . text ( )
const dataBody4 = $ ( '#data-body4' ) . text ( )
expect ( dataBody1 ) . not . toBe ( dataBody2 )
expect ( dataBody2 ) . not . toBe ( dataBody3 )
expect ( dataBody3 ) . not . toBe ( dataBody4 )
const res2 = await fetchViaHTTP (
next . url ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/post-method'
2023-02-25 16:50:51 +01:00
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
expect ( $2 ( '#data-body1' ) . text ( ) ) . toBe ( dataBody1 )
expect ( $2 ( '#data-body2' ) . text ( ) ) . toBe ( dataBody2 )
expect ( $2 ( '#data-body3' ) . text ( ) ) . toBe ( dataBody3 )
return 'success'
} , 'success' )
} )
it ( 'should cache correctly with post method and revalidate edge' , async ( ) = > {
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate-edge/post-method'
2023-02-25 16:50:51 +01:00
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
const dataBody1 = $ ( '#data-body1' ) . text ( )
const dataBody2 = $ ( '#data-body2' ) . text ( )
const dataBody3 = $ ( '#data-body3' ) . text ( )
const dataBody4 = $ ( '#data-body4' ) . text ( )
const res2 = await fetchViaHTTP (
next . url ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate-edge/post-method'
2023-02-25 16:50:51 +01:00
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
expect ( $2 ( '#data-body1' ) . text ( ) ) . toBe ( dataBody1 )
expect ( $2 ( '#data-body2' ) . text ( ) ) . toBe ( dataBody2 )
expect ( $2 ( '#data-body3' ) . text ( ) ) . toBe ( dataBody3 )
expect ( $2 ( '#data-body4' ) . text ( ) ) . toBe ( dataBody4 )
return 'success'
} , 'success' )
} )
2023-02-25 01:44:47 +01:00
it ( 'should cache correctly with POST method and revalidate' , async ( ) = > {
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/post-method'
2023-02-25 01:44:47 +01:00
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
const res2 = await fetchViaHTTP (
next . url ,
2023-03-07 06:30:29 +01:00
'/variable-revalidate/post-method'
2023-02-25 01:44:47 +01:00
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
return 'success'
} , 'success' )
} )
2023-02-23 08:59:38 +01:00
it ( 'should cache correctly with cookie header and revalidate' , async ( ) = > {
await check ( async ( ) = > {
2023-03-07 06:30:29 +01:00
const res = await fetchViaHTTP ( next . url , '/variable-revalidate/cookie' )
2023-02-23 08:59:38 +01:00
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
2023-03-07 06:30:29 +01:00
const res2 = await fetchViaHTTP ( next . url , '/variable-revalidate/cookie' )
2023-02-22 08:10:25 +01:00
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
2023-02-23 08:59:38 +01:00
return 'success'
} , 'success' )
2023-02-22 08:10:25 +01:00
} )
2023-02-25 01:44:47 +01:00
it ( 'should cache correctly with utf8 encoding' , async ( ) = > {
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
'/variable-revalidate/encoding'
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
expect ( JSON . parse ( pageData ) . jp ) . toBe (
'超鬼畜! 激辛ボム兵スピンジャンプ Bomb Spin Jump'
)
const res2 = await fetchViaHTTP (
next . url ,
'/variable-revalidate/encoding'
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
return 'success'
} , 'success' )
} )
it ( 'should cache correctly with utf8 encoding edge' , async ( ) = > {
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
'/variable-revalidate-edge/encoding'
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
expect ( JSON . parse ( pageData ) . jp ) . toBe (
'超鬼畜! 激辛ボム兵スピンジャンプ Bomb Spin Jump'
)
const res2 = await fetchViaHTTP (
next . url ,
2023-02-25 03:03:09 +01:00
'/variable-revalidate-edge/encoding'
2023-02-25 01:44:47 +01:00
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
2023-04-14 07:00:20 +02:00
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
return 'success'
} , 'success' )
} )
it ( 'should cache correctly handle JSON body' , async ( ) = > {
await check ( async ( ) = > {
const res = await fetchViaHTTP (
next . url ,
'/variable-revalidate-edge/body'
)
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
const layoutData = $ ( '#layout-data' ) . text ( )
const pageData = $ ( '#page-data' ) . text ( )
expect ( pageData ) . toBe ( '{"hello":"world"}' )
const res2 = await fetchViaHTTP (
next . url ,
'/variable-revalidate-edge/body'
)
expect ( res2 . status ) . toBe ( 200 )
const html2 = await res2 . text ( )
const $2 = cheerio . load ( html2 )
expect ( $2 ( '#layout-data' ) . text ( ) ) . toBe ( layoutData )
2023-02-25 01:44:47 +01:00
expect ( $2 ( '#page-data' ) . text ( ) ) . toBe ( pageData )
return 'success'
} , 'success' )
} )
2023-05-01 23:37:17 +02:00
it ( 'should not throw Dynamic Server Usage error when using generateStaticParams with draftMode' , async ( ) = > {
const browserOnIndexPage = await next . browser ( '/ssg-draft-mode' )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
const content = await browserOnIndexPage
2023-05-01 23:37:17 +02:00
. elementByCss ( '#draft-mode' )
2022-12-19 10:20:01 +01:00
. text ( )
2022-09-19 20:05:28 +02:00
2023-05-02 21:45:28 +02:00
expect ( content ) . toBe ( '{"isEnabled":false}' )
2022-12-19 10:20:01 +01:00
} )
it ( 'should force SSR correctly for headers usage' , async ( ) = > {
2023-01-05 16:31:03 +01:00
const res = await next . fetch ( '/force-static' , {
2022-12-19 10:20:01 +01:00
headers : {
Cookie : 'myCookie=cookieValue' ,
another : 'header' ,
2022-12-01 05:28:05 +01:00
} ,
2022-09-19 20:05:28 +02:00
} )
2022-12-19 10:20:01 +01:00
expect ( res . status ) . toBe ( 200 )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
const html = await res . text ( )
const $ = cheerio . load ( html )
2022-12-01 05:28:05 +01:00
2022-12-19 10:20:01 +01:00
expect ( JSON . parse ( $ ( '#headers' ) . text ( ) ) ) . toIncludeAllMembers ( [
'cookie' ,
'another' ,
] )
expect ( JSON . parse ( $ ( '#cookies' ) . text ( ) ) ) . toEqual ( [
{
name : 'myCookie' ,
value : 'cookieValue' ,
} ,
] )
2022-12-01 05:28:05 +01:00
2022-12-19 10:20:01 +01:00
const firstTime = $ ( '#now' ) . text ( )
2022-12-01 05:28:05 +01:00
2022-12-19 10:20:01 +01:00
if ( ! ( global as any ) . isNextDev ) {
const res2 = await next . fetch ( '/force-static' )
expect ( res2 . status ) . toBe ( 200 )
2022-11-18 18:47:44 +01:00
2022-12-19 10:20:01 +01:00
const $2 = cheerio . load ( await res2 . text ( ) )
expect ( firstTime ) . not . toBe ( $2 ( '#now' ) . text ( ) )
}
} )
2022-11-18 18:47:44 +01:00
2023-03-21 21:55:04 +01:00
it ( 'should allow dynamic routes to access cookies' , async ( ) = > {
for ( const slug of [ 'books' , 'frameworks' ] ) {
for ( let i = 0 ; i < 2 ; i ++ ) {
let $ = await next . render $ (
` /force-dynamic-prerender/ ${ slug } ` ,
{ } ,
{ headers : { cookie : 'session=value' } }
)
expect ( $ ( '#slug' ) . text ( ) ) . toBe ( slug )
expect ( $ ( '#cookie-result' ) . text ( ) ) . toBe ( 'has cookie' )
$ = await next . render $ ( ` /force-dynamic-prerender/ ${ slug } ` )
expect ( $ ( '#slug' ) . text ( ) ) . toBe ( slug )
expect ( $ ( '#cookie-result' ) . text ( ) ) . toBe ( 'no cookie' )
}
}
} )
2023-03-01 08:37:12 +01:00
it ( 'should not error with generateStaticParams and dynamic data' , async ( ) = > {
const res = await next . fetch ( '/gen-params-dynamic/one' )
const html = await res . text ( )
expect ( res . status ) . toBe ( 200 )
expect ( html ) . toContain ( 'gen-params-dynamic/[slug]' )
expect ( html ) . toContain ( 'one' )
const data = cheerio . load ( html ) ( '#data' ) . text ( )
for ( let i = 0 ; i < 5 ; i ++ ) {
const res2 = await next . fetch ( '/gen-params-dynamic/one' )
expect ( res2 . status ) . toBe ( 200 )
expect (
cheerio
. load ( await res2 . text ( ) ) ( '#data' )
. text ( )
) . not . toBe ( data )
}
} )
2023-03-23 15:53:51 +01:00
it ( 'should not error with force-dynamic and catch-all routes' , async ( ) = > {
// Regression test for https://github.com/vercel/next.js/issues/45603
const res = await next . fetch ( '/force-dynamic-catch-all/slug/a' )
const html = await res . text ( )
expect ( res . status ) . toBe ( 200 )
expect ( html ) . toContain ( 'Dynamic catch-all route' )
} )
2023-03-02 11:14:56 +01:00
it ( 'should not error with generateStaticParams and authed data on revalidate' , async ( ) = > {
const res = await next . fetch ( '/gen-params-dynamic-revalidate/one' )
const html = await res . text ( )
expect ( res . status ) . toBe ( 200 )
expect ( html ) . toContain ( 'gen-params-dynamic/[slug]' )
expect ( html ) . toContain ( 'one' )
const initData = cheerio . load ( html ) ( '#data' ) . text ( )
await check ( async ( ) = > {
const res2 = await next . fetch ( '/gen-params-dynamic-revalidate/one' )
expect ( res2 . status ) . toBe ( 200 )
const $ = cheerio . load ( await res2 . text ( ) )
expect ( $ ( '#data' ) . text ( ) ) . toBeTruthy ( )
expect ( $ ( '#data' ) . text ( ) ) . not . toBe ( initData )
return 'success'
} , 'success' )
} )
2023-04-02 06:15:13 +02:00
if ( ! process . env . CUSTOM_CACHE_HANDLER ) {
it ( 'should honor dynamic = "force-static" correctly' , async ( ) = > {
const res = await next . fetch ( '/force-static/first' )
expect ( res . status ) . toBe ( 200 )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
const html = await res . text ( )
const $ = cheerio . load ( html )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
expect ( JSON . parse ( $ ( '#params' ) . text ( ) ) ) . toEqual ( { slug : 'first' } )
expect ( JSON . parse ( $ ( '#headers' ) . text ( ) ) ) . toEqual ( [ ] )
expect ( JSON . parse ( $ ( '#cookies' ) . text ( ) ) ) . toEqual ( [ ] )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
const firstTime = $ ( '#now' ) . text ( )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
if ( ! ( global as any ) . isNextDev ) {
const res2 = await next . fetch ( '/force-static/first' )
expect ( res2 . status ) . toBe ( 200 )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
const $2 = cheerio . load ( await res2 . text ( ) )
expect ( firstTime ) . toBe ( $2 ( '#now' ) . text ( ) )
}
} )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
it ( 'should honor dynamic = "force-static" correctly (lazy)' , async ( ) = > {
const res = await next . fetch ( '/force-static/random' )
expect ( res . status ) . toBe ( 200 )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
const html = await res . text ( )
const $ = cheerio . load ( html )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
expect ( JSON . parse ( $ ( '#params' ) . text ( ) ) ) . toEqual ( { slug : 'random' } )
expect ( JSON . parse ( $ ( '#headers' ) . text ( ) ) ) . toEqual ( [ ] )
expect ( JSON . parse ( $ ( '#cookies' ) . text ( ) ) ) . toEqual ( [ ] )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
const firstTime = $ ( '#now' ) . text ( )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
if ( ! ( global as any ) . isNextDev ) {
const res2 = await next . fetch ( '/force-static/random' )
expect ( res2 . status ) . toBe ( 200 )
2022-11-18 18:47:44 +01:00
2023-04-02 06:15:13 +02:00
const $2 = cheerio . load ( await res2 . text ( ) )
expect ( firstTime ) . toBe ( $2 ( '#now' ) . text ( ) )
}
} )
}
2022-09-19 20:05:28 +02:00
2023-02-23 10:19:59 +01:00
// since we aren't leveraging fs cache with custom handler
// then these will 404 as they are cache misses
if ( ! ( isNextStart && process . env . CUSTOM_CACHE_HANDLER ) ) {
it ( 'should handle dynamicParams: false correctly' , async ( ) = > {
const validParams = [ 'tim' , 'seb' , 'styfle' ]
2022-09-19 20:05:28 +02:00
2023-02-23 10:19:59 +01:00
for ( const param of validParams ) {
const res = await next . fetch ( ` /blog/ ${ param } ` , {
redirect : 'manual' ,
} )
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
2022-09-19 20:05:28 +02:00
2023-02-23 10:19:59 +01:00
expect ( JSON . parse ( $ ( '#params' ) . text ( ) ) ) . toEqual ( {
author : param ,
} )
expect ( $ ( '#page' ) . text ( ) ) . toBe ( '/blog/[author]' )
}
const invalidParams = [ 'timm' , 'non-existent' ]
2022-12-19 10:20:01 +01:00
2023-02-23 10:19:59 +01:00
for ( const param of invalidParams ) {
const invalidRes = await next . fetch ( ` /blog/ ${ param } ` , {
redirect : 'manual' ,
} )
expect ( invalidRes . status ) . toBe ( 404 )
expect ( await invalidRes . text ( ) ) . toContain ( 'page could not be found' )
}
} )
}
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
it ( 'should work with forced dynamic path' , async ( ) = > {
for ( const slug of [ 'first' , 'second' ] ) {
2023-01-05 16:31:03 +01:00
const res = await next . fetch ( ` /dynamic-no-gen-params-ssr/ ${ slug } ` , {
redirect : 'manual' ,
} )
2022-12-19 10:20:01 +01:00
expect ( res . status ) . toBe ( 200 )
expect ( await res . text ( ) ) . toContain ( ` ${ slug } ` )
}
} )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
it ( 'should work with dynamic path no generateStaticParams' , async ( ) = > {
for ( const slug of [ 'first' , 'second' ] ) {
2023-01-05 16:31:03 +01:00
const res = await next . fetch ( ` /dynamic-no-gen-params/ ${ slug } ` , {
redirect : 'manual' ,
} )
2022-12-19 10:20:01 +01:00
expect ( res . status ) . toBe ( 200 )
expect ( await res . text ( ) ) . toContain ( ` ${ slug } ` )
}
} )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
it ( 'should handle dynamicParams: true correctly' , async ( ) = > {
const paramsToCheck = [
{
author : 'tim' ,
slug : 'first-post' ,
} ,
{
author : 'seb' ,
slug : 'second-post' ,
} ,
{
author : 'styfle' ,
slug : 'first-post' ,
} ,
{
author : 'new-author' ,
slug : 'first-post' ,
} ,
]
for ( const params of paramsToCheck ) {
2023-01-05 16:31:03 +01:00
const res = await next . fetch ( ` /blog/ ${ params . author } / ${ params . slug } ` , {
redirect : 'manual' ,
} )
2022-12-19 10:20:01 +01:00
expect ( res . status ) . toBe ( 200 )
const html = await res . text ( )
const $ = cheerio . load ( html )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
expect ( JSON . parse ( $ ( '#params' ) . text ( ) ) ) . toEqual ( params )
expect ( $ ( '#page' ) . text ( ) ) . toBe ( '/blog/[author]/[slug]' )
}
2022-09-19 20:05:28 +02:00
} )
2023-02-23 10:19:59 +01:00
// since we aren't leveraging fs cache with custom handler
// then these will 404 as they are cache misses
if ( ! ( isNextStart && process . env . CUSTOM_CACHE_HANDLER ) ) {
it ( 'should navigate to static path correctly' , async ( ) = > {
const browser = await next . browser ( '/blog/tim' )
await browser . eval ( 'window.beforeNav = 1' )
expect (
await browser . eval ( 'document.documentElement.innerHTML' )
) . toContain ( '/blog/[author]' )
await browser . elementByCss ( '#author-2' ) . click ( )
await check ( async ( ) = > {
const params = JSON . parse (
await browser . elementByCss ( '#params' ) . text ( )
)
return params . author === 'seb' ? 'found' : params
} , 'found' )
2022-10-18 09:44:30 +02:00
2023-02-23 10:19:59 +01:00
expect ( await browser . eval ( 'window.beforeNav' ) ) . toBe ( 1 )
await browser . elementByCss ( '#author-1-post-1' ) . click ( )
2022-10-18 09:44:30 +02:00
2023-02-23 10:19:59 +01:00
await check ( async ( ) = > {
const params = JSON . parse (
await browser . elementByCss ( '#params' ) . text ( )
)
return params . author === 'tim' && params . slug === 'first-post'
? 'found'
: params
} , 'found' )
2022-10-18 09:44:30 +02:00
2023-02-23 10:19:59 +01:00
expect ( await browser . eval ( 'window.beforeNav' ) ) . toBe ( 1 )
await browser . back ( )
2022-10-18 09:44:30 +02:00
2023-02-23 10:19:59 +01:00
await check ( async ( ) = > {
const params = JSON . parse (
await browser . elementByCss ( '#params' ) . text ( )
)
return params . author === 'seb' ? 'found' : params
} , 'found' )
2022-10-18 09:44:30 +02:00
2023-02-23 10:19:59 +01:00
expect ( await browser . eval ( 'window.beforeNav' ) ) . toBe ( 1 )
} )
}
2022-10-18 09:44:30 +02:00
2022-12-19 10:20:01 +01:00
it ( 'should ssr dynamically when detected automatically with fetch cache option' , async ( ) = > {
const pathname = '/ssr-auto/cache-no-store'
2023-01-05 16:31:03 +01:00
const initialRes = await next . fetch ( pathname , {
2022-12-19 10:20:01 +01:00
redirect : 'manual' ,
} )
expect ( initialRes . status ) . toBe ( 200 )
const initialHtml = await initialRes . text ( )
const initial $ = cheerio . load ( initialHtml )
2022-10-18 09:44:30 +02:00
2022-12-19 10:20:01 +01:00
expect ( initial $ ( '#page' ) . text ( ) ) . toBe ( pathname )
const initialDate = initial $ ( '#date' ) . text ( )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
expect ( initialHtml ) . toContain ( 'Example Domain' )
2022-09-19 20:05:28 +02:00
2023-01-05 16:31:03 +01:00
const secondRes = await next . fetch ( pathname , {
2022-12-19 10:20:01 +01:00
redirect : 'manual' ,
} )
expect ( secondRes . status ) . toBe ( 200 )
const secondHtml = await secondRes . text ( )
const second $ = cheerio . load ( secondHtml )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
expect ( second $ ( '#page' ) . text ( ) ) . toBe ( pathname )
const secondDate = second $ ( '#date' ) . text ( )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
expect ( secondHtml ) . toContain ( 'Example Domain' )
expect ( secondDate ) . not . toBe ( initialDate )
} )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
it ( 'should render not found pages correctly and fallback to the default one' , async ( ) = > {
2023-01-05 16:31:03 +01:00
const res = await next . fetch ( ` /blog/shu/hi ` , {
2022-12-19 10:20:01 +01:00
redirect : 'manual' ,
} )
expect ( res . status ) . toBe ( 404 )
const html = await res . text ( )
expect ( html ) . toInclude ( '"noindex"' )
expect ( html ) . toInclude ( 'This page could not be found.' )
2022-09-19 20:05:28 +02:00
} )
2022-12-19 10:20:01 +01:00
// TODO-APP: support fetch revalidate case for dynamic rendering
it . skip ( 'should ssr dynamically when detected automatically with fetch revalidate option' , async ( ) = > {
const pathname = '/ssr-auto/fetch-revalidate-zero'
2023-01-05 16:31:03 +01:00
const initialRes = await next . fetch ( pathname , {
2022-12-19 10:20:01 +01:00
redirect : 'manual' ,
} )
expect ( initialRes . status ) . toBe ( 200 )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
const initialHtml = await initialRes . text ( )
const initial $ = cheerio . load ( initialHtml )
2022-09-19 20:05:28 +02:00
2022-12-19 10:20:01 +01:00
expect ( initial $ ( '#page' ) . text ( ) ) . toBe ( pathname )
const initialDate = initial $ ( '#date' ) . text ( )
2022-10-25 01:21:28 +02:00
2022-12-19 10:20:01 +01:00
expect ( initialHtml ) . toContain ( 'Example Domain' )
2022-10-25 03:58:10 +02:00
2023-01-05 16:31:03 +01:00
const secondRes = await next . fetch ( pathname , {
2022-12-19 10:20:01 +01:00
redirect : 'manual' ,
2022-12-12 12:53:38 +01:00
} )
2022-12-19 10:20:01 +01:00
expect ( secondRes . status ) . toBe ( 200 )
2022-12-12 12:53:38 +01:00
2022-12-19 10:20:01 +01:00
const secondHtml = await secondRes . text ( )
const second $ = cheerio . load ( secondHtml )
2022-10-25 03:58:10 +02:00
2022-12-19 10:20:01 +01:00
expect ( second $ ( '#page' ) . text ( ) ) . toBe ( pathname )
const secondDate = second $ ( '#date' ) . text ( )
2022-10-25 03:58:10 +02:00
2022-12-19 10:20:01 +01:00
expect ( secondHtml ) . toContain ( 'Example Domain' )
expect ( secondDate ) . not . toBe ( initialDate )
} )
2022-12-12 12:53:38 +01:00
2022-12-19 10:20:01 +01:00
it ( 'should ssr dynamically when forced via config' , async ( ) = > {
2023-01-05 16:31:03 +01:00
const initialRes = await next . fetch ( '/ssr-forced' , {
2022-12-19 10:20:01 +01:00
redirect : 'manual' ,
} )
expect ( initialRes . status ) . toBe ( 200 )
2022-12-12 12:53:38 +01:00
2022-12-19 10:20:01 +01:00
const initialHtml = await initialRes . text ( )
const initial $ = cheerio . load ( initialHtml )
2022-12-12 12:53:38 +01:00
2022-12-19 10:20:01 +01:00
expect ( initial $ ( '#page' ) . text ( ) ) . toBe ( '/ssr-forced' )
const initialDate = initial $ ( '#date' ) . text ( )
2023-01-05 16:31:03 +01:00
const secondRes = await next . fetch ( '/ssr-forced' , {
2022-12-19 10:20:01 +01:00
redirect : 'manual' ,
2022-12-12 12:53:38 +01:00
} )
2022-12-19 10:20:01 +01:00
expect ( secondRes . status ) . toBe ( 200 )
2022-12-12 12:53:38 +01:00
2022-12-19 10:20:01 +01:00
const secondHtml = await secondRes . text ( )
const second $ = cheerio . load ( secondHtml )
expect ( second $ ( '#page' ) . text ( ) ) . toBe ( '/ssr-forced' )
const secondDate = second $ ( '#date' ) . text ( )
expect ( secondDate ) . not . toBe ( initialDate )
} )
describe ( 'useSearchParams' , ( ) = > {
describe ( 'client' , ( ) = > {
it ( 'should bailout to client rendering - without suspense boundary' , async ( ) = > {
const browser = await next . browser (
'/hooks/use-search-params?first=value&second=other&third'
2022-10-27 02:24:38 +02:00
)
2022-10-25 03:58:10 +02:00
2022-12-19 10:20:01 +01:00
expect ( await browser . elementByCss ( '#params-first' ) . text ( ) ) . toBe (
'value'
)
expect ( await browser . elementByCss ( '#params-second' ) . text ( ) ) . toBe (
'other'
)
expect ( await browser . elementByCss ( '#params-third' ) . text ( ) ) . toBe ( '' )
2022-10-27 02:24:38 +02:00
expect ( await browser . elementByCss ( '#params-not-real' ) . text ( ) ) . toBe (
'N/A'
)
} )
2022-10-25 03:58:10 +02:00
2022-12-12 12:53:38 +01:00
it ( 'should bailout to client rendering - with suspense boundary' , async ( ) = > {
2022-12-19 10:20:01 +01:00
const browser = await next . browser (
'/hooks/use-search-params/with-suspense?first=value&second=other&third'
)
expect ( await browser . elementByCss ( '#params-first' ) . text ( ) ) . toBe (
'value'
)
expect ( await browser . elementByCss ( '#params-second' ) . text ( ) ) . toBe (
'other'
)
expect ( await browser . elementByCss ( '#params-third' ) . text ( ) ) . toBe ( '' )
expect ( await browser . elementByCss ( '#params-not-real' ) . text ( ) ) . toBe (
'N/A'
2022-12-12 12:53:38 +01:00
)
} )
2022-10-25 03:58:10 +02:00
2022-12-12 12:53:38 +01:00
it . skip ( 'should have empty search params on force-static' , async ( ) = > {
2022-12-19 10:20:01 +01:00
const browser = await next . browser (
2022-12-12 12:53:38 +01:00
'/hooks/use-search-params/force-static?first=value&second=other&third'
)
2022-10-25 03:58:10 +02:00
2022-12-19 10:20:01 +01:00
expect ( await browser . elementByCss ( '#params-first' ) . text ( ) ) . toBe ( 'N/A' )
expect ( await browser . elementByCss ( '#params-second' ) . text ( ) ) . toBe (
'N/A'
)
expect ( await browser . elementByCss ( '#params-third' ) . text ( ) ) . toBe ( 'N/A' )
expect ( await browser . elementByCss ( '#params-not-real' ) . text ( ) ) . toBe (
'N/A'
)
await browser . elementById ( 'to-use-search-params' ) . click ( )
await browser . waitForElementByCss ( '#hooks-use-search-params' )
2022-10-25 03:58:10 +02:00
2022-12-19 10:20:01 +01:00
// Should not be empty after navigating to another page with useSearchParams
expect ( await browser . elementByCss ( '#params-first' ) . text ( ) ) . toBe ( '1' )
expect ( await browser . elementByCss ( '#params-second' ) . text ( ) ) . toBe ( '2' )
expect ( await browser . elementByCss ( '#params-third' ) . text ( ) ) . toBe ( '3' )
expect ( await browser . elementByCss ( '#params-not-real' ) . text ( ) ) . toBe (
'N/A'
)
2022-12-12 12:53:38 +01:00
} )
2022-12-19 10:20:01 +01:00
// TODO-APP: re-enable after investigating rewrite params
if ( ! ( global as any ) . isNextDeploy ) {
it ( 'should have values from canonical url on rewrite' , async ( ) = > {
const browser = await next . browser (
'/rewritten-use-search-params?first=a&second=b&third=c'
)
expect ( await browser . elementByCss ( '#params-first' ) . text ( ) ) . toBe ( 'a' )
expect ( await browser . elementByCss ( '#params-second' ) . text ( ) ) . toBe (
'b'
)
expect ( await browser . elementByCss ( '#params-third' ) . text ( ) ) . toBe ( 'c' )
expect ( await browser . elementByCss ( '#params-not-real' ) . text ( ) ) . toBe (
'N/A'
)
} )
}
2022-10-25 03:58:10 +02:00
} )
2022-12-19 10:20:01 +01:00
// Don't run these tests in dev mode since they won't be statically generated
if ( ! isDev ) {
describe ( 'server response' , ( ) = > {
it ( 'should bailout to client rendering - without suspense boundary' , async ( ) = > {
const res = await next . fetch ( '/hooks/use-search-params' )
const html = await res . text ( )
expect ( html ) . toInclude ( '<html id="__next_error__">' )
} )
it ( 'should bailout to client rendering - with suspense boundary' , async ( ) = > {
const res = await next . fetch (
'/hooks/use-search-params/with-suspense'
)
const html = await res . text ( )
expect ( html ) . toInclude ( '<p>search params suspense</p>' )
} )
it . skip ( 'should have empty search params on force-static' , async ( ) = > {
const res = await next . fetch (
'/hooks/use-search-params/force-static?first=value&second=other&third'
)
const html = await res . text ( )
// Shouild not bail out to client rendering
expect ( html ) . not . toInclude ( '<p>search params suspense</p>' )
// Use empty search params instead
const $ = cheerio . load ( html )
expect ( $ ( '#params-first' ) . text ( ) ) . toBe ( 'N/A' )
expect ( $ ( '#params-second' ) . text ( ) ) . toBe ( 'N/A' )
expect ( $ ( '#params-third' ) . text ( ) ) . toBe ( 'N/A' )
expect ( $ ( '#params-not-real' ) . text ( ) ) . toBe ( 'N/A' )
} )
} )
}
} )
2022-10-27 02:24:38 +02:00
2022-12-19 10:20:01 +01:00
// TODO: needs updating as usePathname should not bail
describe . skip ( 'usePathname' , ( ) = > {
if ( isDev ) {
it ( 'should bail out to client rendering during SSG' , async ( ) = > {
const res = await next . fetch ( '/hooks/use-pathname/slug' )
const html = await res . text ( )
expect ( html ) . toInclude ( '<html id="__next_error__">' )
} )
}
it ( 'should have the correct values' , async ( ) = > {
const browser = await next . browser ( '/hooks/use-pathname/slug' )
expect ( await browser . elementByCss ( '#pathname' ) . text ( ) ) . toBe (
'/hooks/use-pathname/slug'
)
2022-10-27 02:24:38 +02:00
} )
2022-11-10 18:24:31 +01:00
2022-12-19 10:20:01 +01:00
it ( 'should have values from canonical url on rewrite' , async ( ) = > {
const browser = await next . browser ( '/rewritten-use-pathname' )
2022-12-12 12:53:38 +01:00
2022-12-19 10:20:01 +01:00
expect ( await browser . elementByCss ( '#pathname' ) . text ( ) ) . toBe (
'/rewritten-use-pathname'
)
} )
2022-12-12 12:53:38 +01:00
} )
2022-12-19 10:20:01 +01:00
it ( 'should keep querystring on static page' , async ( ) = > {
const browser = await next . browser ( '/blog/tim?message=hello-world' )
const checkUrl = async ( ) = >
expect ( await browser . url ( ) ) . toBe (
next . url + '/blog/tim?message=hello-world'
)
2022-12-12 12:53:38 +01:00
2022-12-19 10:20:01 +01:00
checkUrl ( )
await waitFor ( 1000 )
checkUrl ( )
2022-11-10 18:24:31 +01:00
} )
2023-02-23 10:19:59 +01:00
if ( process . env . CUSTOM_CACHE_HANDLER && ! isNextDeploy ) {
it ( 'should have logs from cache-handler' , ( ) = > {
expect ( next . cliOutput ) . toContain ( 'initialized custom cache-handler' )
expect ( next . cliOutput ) . toContain ( 'cache-handler get' )
expect ( next . cliOutput ) . toContain ( 'cache-handler set' )
} )
}
2022-12-12 12:53:38 +01:00
}
2022-12-19 10:20:01 +01:00
)