@@ -1063,6 +1063,96 @@ test.describe("single-fetch", () => {
10631063 expect ( urls ) . toEqual ( [ expect . stringMatching ( / \/ a c t i o n \. d a t a $ / ) ] ) ;
10641064 } ) ;
10651065
1066+ test ( "call-site revalidation opt-out handles parent routes w/o shouldRevalidate" , async ( {
1067+ page,
1068+ } ) => {
1069+ let fixture = await createFixture ( {
1070+ files : {
1071+ "app/root.tsx" : js `
1072+ import { Link, Links, Meta, Outlet, Scripts, useMatches } from "react-router";
1073+
1074+ let count = 0
1075+
1076+ export function loader() {
1077+ return { count: ++count };
1078+ }
1079+
1080+ export default function Root() {
1081+ return (
1082+ <html lang="en">
1083+ <head>
1084+ <Meta />
1085+ <Links />
1086+ </head>
1087+ <body>
1088+ <nav>
1089+ <Link to="/">Home</Link>
1090+ <Link to="/page">Page (default)</Link>
1091+ <Link to="/page?optout" unstable_defaultShouldRevalidate={false}>Page (opt-out)</Link>
1092+ </nav>
1093+ <pre id="data">
1094+ {JSON.stringify(useMatches().map(m => [m.id, m.data]))}
1095+ </pre>
1096+ <Outlet />
1097+ <Scripts />
1098+ </body>
1099+ </html>
1100+ );
1101+ }
1102+ ` ,
1103+ "app/routes/page.tsx" : js `
1104+ let count = 0
1105+
1106+ export function loader() {
1107+ return { count: ++count }
1108+ }
1109+
1110+ export default function Component() {
1111+ return <h2>Page</h2>
1112+ }
1113+ ` ,
1114+ } ,
1115+ } ) ;
1116+
1117+ let urls : string [ ] = [ ] ;
1118+ page . on ( "request" , ( req ) => {
1119+ if ( req . url ( ) . includes ( ".data" ) ) {
1120+ let url = new URL ( req . url ( ) ) ;
1121+ urls . push ( url . pathname + url . search ) ;
1122+ }
1123+ } ) ;
1124+
1125+ console . error = ( ) => { } ;
1126+
1127+ let appFixture = await createAppFixture ( fixture ) ;
1128+ let app = new PlaywrightFixture ( appFixture , page ) ;
1129+ await app . goto ( "/" ) ; // root increments to 1
1130+ expect ( await page . locator ( "#data" ) . innerText ( ) ) . toBe (
1131+ '[["root",{"count":1}],["routes/_index",null]]' ,
1132+ ) ;
1133+
1134+ await app . clickLink ( "/page" ) ; // root increments to 2
1135+ expect ( await page . locator ( "#data" ) . innerText ( ) ) . toBe (
1136+ '[["root",{"count":2}],["routes/page",{"count":1}]]' ,
1137+ ) ;
1138+ expect ( urls ) . toEqual ( [ "/page.data" ] ) ;
1139+ urls . splice ( 0 , urls . length ) ;
1140+
1141+ await app . clickLink ( "/" ) ; // root increments to 3
1142+ expect ( await page . locator ( "#data" ) . innerText ( ) ) . toBe (
1143+ '[["root",{"count":3}],["routes/_index",null]]' ,
1144+ ) ;
1145+ expect ( urls ) . toEqual ( [ "/_root.data" ] ) ;
1146+ urls . splice ( 0 , urls . length ) ;
1147+
1148+ await app . clickLink ( "/page?optout" ) ;
1149+ // root stays at 3, page is a fresh load so increments to 2
1150+ expect ( await page . locator ( "#data" ) . innerText ( ) ) . toBe (
1151+ '[["root",{"count":3}],["routes/page",{"count":2}]]' ,
1152+ ) ;
1153+ expect ( urls ) . toEqual ( [ "/page.data?optout=&_routes=routes%2Fpage" ] ) ;
1154+ } ) ;
1155+
10661156 test ( "returns headers correctly for singular loader and action calls" , async ( ) => {
10671157 let fixture = await createFixture ( {
10681158 files : {
0 commit comments