@@ -424,6 +424,39 @@ describe("tryServeStatic (with StaticFileCache)", () => {
424424 expect ( captured . status ) . toBe ( 200 ) ;
425425 } ) ;
426426
427+ it ( "returns 304 when a cached asset has not changed since If-Modified-Since" , async ( ) => {
428+ await writeFile ( clientDir , "conditional.txt" , "cached content" ) ;
429+ const cache = await StaticFileCache . create ( clientDir ) ;
430+ const entry = cache . lookup ( "/conditional.txt" ) ! ;
431+ const req = mockReq ( undefined , {
432+ "if-modified-since" : entry . original . headers [ "Last-Modified" ] ,
433+ } ) ;
434+ const { res, captured } = mockRes ( ) ;
435+
436+ await tryServeStatic ( req , res , clientDir , "/conditional.txt" , true , cache ) ;
437+ await captured . ended ;
438+
439+ expect ( captured . status ) . toBe ( 304 ) ;
440+ expect ( captured . headers [ "Last-Modified" ] ) . toBe ( entry . original . headers [ "Last-Modified" ] ) ;
441+ } ) ;
442+
443+ it ( "honors Cache-Control: no-cache when a cached asset ETag matches" , async ( ) => {
444+ await writeFile ( clientDir , "forced-revalidation.txt" , "cached content" ) ;
445+ const cache = await StaticFileCache . create ( clientDir ) ;
446+ const entry = cache . lookup ( "/forced-revalidation.txt" ) ! ;
447+ const req = mockReq ( undefined , {
448+ "cache-control" : "no-cache" ,
449+ "if-none-match" : entry . etag ,
450+ } ) ;
451+ const { res, captured } = mockRes ( ) ;
452+
453+ await tryServeStatic ( req , res , clientDir , "/forced-revalidation.txt" , true , cache ) ;
454+ await captured . ended ;
455+
456+ expect ( captured . status ) . toBe ( 200 ) ;
457+ expect ( captured . body . toString ( ) ) . toBe ( "cached content" ) ;
458+ } ) ;
459+
427460 it ( "304 response excludes Content-Type per RFC 9110" , async ( ) => {
428461 await writeFile ( clientDir , "_next/static/rfc-aaa111.js" , "rfc content" ) ;
429462
@@ -1026,6 +1059,36 @@ describe("tryServeStatic (with StaticFileCache)", () => {
10261059 expect ( captured . headers . Vary ) . toBe ( "Accept-Encoding" ) ;
10271060 } ) ;
10281061
1062+ it ( "supports If-Modified-Since on the slow path" , async ( ) => {
1063+ await writeFile ( clientDir , "conditional-slow.txt" , "slow content" ) ;
1064+ const stat = await fsp . stat ( path . join ( clientDir , "conditional-slow.txt" ) ) ;
1065+ const req = mockReq ( undefined , {
1066+ "if-modified-since" : new Date ( stat . mtimeMs ) . toUTCString ( ) ,
1067+ } ) ;
1068+ const { res, captured } = mockRes ( ) ;
1069+
1070+ await tryServeStatic ( req , res , clientDir , "/conditional-slow.txt" , true ) ;
1071+ await captured . ended ;
1072+
1073+ expect ( captured . status ) . toBe ( 304 ) ;
1074+ expect ( captured . headers [ "Last-Modified" ] ) . toBe ( new Date ( stat . mtimeMs ) . toUTCString ( ) ) ;
1075+ } ) ;
1076+
1077+ it ( "honors Cache-Control: no-cache on the slow path" , async ( ) => {
1078+ await writeFile ( clientDir , "_next/static/no-cache-slow-abc123.js" , "slow content" ) ;
1079+ const req = mockReq ( undefined , {
1080+ "cache-control" : "no-cache" ,
1081+ "if-none-match" : 'W/"abc123"' ,
1082+ } ) ;
1083+ const { res, captured } = mockRes ( ) ;
1084+
1085+ await tryServeStatic ( req , res , clientDir , "/_next/static/no-cache-slow-abc123.js" , true ) ;
1086+ await captured . ended ;
1087+
1088+ expect ( captured . status ) . toBe ( 200 ) ;
1089+ expect ( captured . body . toString ( ) ) . toBe ( "slow content" ) ;
1090+ } ) ;
1091+
10291092 it ( "slow path 304 omits Vary for non-compressible content (compress=false)" , async ( ) => {
10301093 await writeFile ( clientDir , "photo.jpg" , Buffer . alloc ( 100 , 0xff ) ) ;
10311094
0 commit comments