@@ -841,6 +841,79 @@ test.describe("Middleware", () => {
841841 appFixture . close ( ) ;
842842 } ) ;
843843
844+ test ( "calls clientMiddleware when no loaders exist" , async ( { page } ) => {
845+ let fixture = await createFixture ( {
846+ files : {
847+ "react-router.config.ts" : reactRouterConfig ( {
848+ middleware : true ,
849+ } ) ,
850+ "vite.config.ts" : js `
851+ import { defineConfig } from "vite";
852+ import { reactRouter } from "@react-router/dev/vite";
853+
854+ export default defineConfig({
855+ build: { manifest: true, minify: false },
856+ plugins: [reactRouter()],
857+ });
858+ ` ,
859+ "app/routes/_index.tsx" : js `
860+ import { Link } from 'react-router'
861+
862+ export const unstable_clientMiddleware = [
863+ ({ context }) => {
864+ console.log('running index middleware')
865+ },
866+ ];
867+
868+ export default function Component() {
869+ return (
870+ <>
871+ <h2 data-route>Index</h2>
872+ <Link to="/about">Go to about</Link>
873+ </>
874+ );
875+ }
876+ ` ,
877+ "app/routes/about.tsx" : js `
878+ import { Link } from 'react-router'
879+ export const unstable_clientMiddleware = [
880+ ({ context }) => {
881+ console.log('running about middleware')
882+ },
883+ ];
884+
885+ export default function Component() {
886+ return (
887+ <>
888+ <h2 data-route>About</h2>
889+ <Link to="/">Go to index</Link>
890+ </>
891+ );
892+ }
893+ ` ,
894+ } ,
895+ } ) ;
896+
897+ let appFixture = await createAppFixture ( fixture ) ;
898+
899+ let logs : string [ ] = [ ] ;
900+ page . on ( "console" , ( msg ) => logs . push ( msg . text ( ) ) ) ;
901+
902+ let app = new PlaywrightFixture ( appFixture , page ) ;
903+ await app . goto ( "/" ) ;
904+
905+ ( await page . $ ( 'a[href="/about"]' ) ) ?. click ( ) ;
906+ await page . waitForSelector ( '[data-route]:has-text("About")' ) ;
907+ expect ( logs ) . toEqual ( [ "running about middleware" ] ) ;
908+ logs . splice ( 0 ) ;
909+
910+ ( await page . $ ( 'a[href="/"]' ) ) ?. click ( ) ;
911+ await page . waitForSelector ( '[data-route]:has-text("Index")' ) ;
912+ expect ( logs ) . toEqual ( [ "running index middleware" ] ) ;
913+
914+ appFixture . close ( ) ;
915+ } ) ;
916+
844917 test ( "calls clientMiddleware before/after actions" , async ( { page } ) => {
845918 let fixture = await createFixture ( {
846919 files : {
@@ -1596,6 +1669,94 @@ test.describe("Middleware", () => {
15961669 appFixture . close ( ) ;
15971670 } ) ;
15981671
1672+ test ( "calls middleware when no loaders exist on document, but not data requests" , async ( {
1673+ page,
1674+ } ) => {
1675+ let oldConsoleLog = console . log ;
1676+ let logs : any [ ] = [ ] ;
1677+ console . log = ( ...args ) => logs . push ( args ) ;
1678+
1679+ let fixture = await createFixture ( {
1680+ files : {
1681+ "react-router.config.ts" : reactRouterConfig ( {
1682+ middleware : true ,
1683+ } ) ,
1684+ "vite.config.ts" : js `
1685+ import { defineConfig } from "vite";
1686+ import { reactRouter } from "@react-router/dev/vite";
1687+
1688+ export default defineConfig({
1689+ build: { manifest: true, minify: false },
1690+ plugins: [reactRouter()],
1691+ });
1692+ ` ,
1693+ "app/routes/parent.tsx" : js `
1694+ import { Link, Outlet } from 'react-router'
1695+
1696+ export const unstable_middleware = [
1697+ ({ request }) => {
1698+ console.log('Running parent middleware', new URL(request.url).pathname)
1699+ },
1700+ ];
1701+
1702+ export default function Component() {
1703+ return (
1704+ <>
1705+ <h2>Parent</h2>
1706+ <Link to="/parent/a">Go to A</Link>
1707+ <Link to="/parent/b">Go to B</Link>
1708+ <Outlet/>
1709+ </>
1710+ );
1711+ }
1712+ ` ,
1713+ "app/routes/parent.a.tsx" : js `
1714+ export const unstable_middleware = [
1715+ ({ request }) => {
1716+ console.log('Running A middleware', new URL(request.url).pathname)
1717+ },
1718+ ];
1719+
1720+ export default function Component() {
1721+ return <h3>A</h3>;
1722+ }
1723+ ` ,
1724+ "app/routes/parent.b.tsx" : js `
1725+ export const unstable_middleware = [
1726+ ({ request }) => {
1727+ console.log('Running B middleware', new URL(request.url).pathname)
1728+ },
1729+ ];
1730+
1731+ export default function Component() {
1732+ return <h3>B</h3>;
1733+ }
1734+ ` ,
1735+ } ,
1736+ } ) ;
1737+
1738+ let appFixture = await createAppFixture ( fixture ) ;
1739+
1740+ let app = new PlaywrightFixture ( appFixture , page ) ;
1741+ await app . goto ( "/parent/a" ) ;
1742+ await page . waitForSelector ( 'h2:has-text("Parent")' ) ;
1743+ await page . waitForSelector ( 'h3:has-text("A")' ) ;
1744+ expect ( logs ) . toEqual ( [
1745+ [ "Running parent middleware" , "/parent/a" ] ,
1746+ [ "Running A middleware" , "/parent/a" ] ,
1747+ ] ) ;
1748+
1749+ ( await page . $ ( 'a[href="/parent/b"]' ) ) ?. click ( ) ;
1750+ await page . waitForSelector ( 'h3:has-text("B")' ) ;
1751+ expect ( logs ) . toEqual ( [
1752+ [ "Running parent middleware" , "/parent/a" ] ,
1753+ [ "Running A middleware" , "/parent/a" ] ,
1754+ ] ) ;
1755+
1756+ appFixture . close ( ) ;
1757+ console . log = oldConsoleLog ;
1758+ } ) ;
1759+
15991760 test ( "calls middleware before/after actions" , async ( { page } ) => {
16001761 let fixture = await createFixture ( {
16011762 files : {
0 commit comments