@@ -435,6 +435,17 @@ implementations.forEach((implementation) => {
435435 }
436436 ]
437437 },
438+ {
439+ id: "throw-external-redirect-server-action",
440+ path: "throw-external-redirect-server-action",
441+ children: [
442+ {
443+ id: "throw-external-redirect-server-action.home",
444+ index: true,
445+ lazy: () => import("./routes/throw-external-redirect-server-action/home"),
446+ }
447+ ]
448+ },
438449 {
439450 id: "side-effect-redirect-server-action",
440451 path: "side-effect-redirect-server-action",
@@ -446,6 +457,17 @@ implementations.forEach((implementation) => {
446457 }
447458 ]
448459 },
460+ {
461+ id: "side-effect-external-redirect-server-action",
462+ path: "side-effect-external-redirect-server-action",
463+ children: [
464+ {
465+ id: "side-effect-external-redirect-server-action.home",
466+ index: true,
467+ lazy: () => import("./routes/side-effect-external-redirect-server-action/home"),
468+ }
469+ ]
470+ },
449471 {
450472 id: "server-function-reference",
451473 path: "server-function-reference",
@@ -986,6 +1008,82 @@ implementations.forEach((implementation) => {
9861008 );
9871009 }
9881010 ` ,
1011+ "src/routes/throw-external-redirect-server-action/home.actions.ts" :js `
1012+ "use server";
1013+ import { redirect } from "react-router";
1014+
1015+ export async function redirectAction(formData: FormData) {
1016+ // Throw a redirect to an external URL
1017+ throw redirect("https://example.com/");
1018+ }
1019+ ` ,
1020+ "src/routes/throw-external-redirect-server-action/home.client.tsx" :js `
1021+ "use client";
1022+
1023+ import { useState } from "react";
1024+
1025+ export function Counter() {
1026+ const [count, setCount] = useState(0);
1027+ return <button type="button" onClick={() => setCount(c => c + 1)} data-count>Count: {count}</button>;
1028+ }
1029+ ` ,
1030+ "src/routes/throw-external-redirect-server-action/home.tsx" :js `
1031+ import { redirectAction } from "./home.actions";
1032+ import { Counter } from "./home.client";
1033+
1034+ export default function HomeRoute(props) {
1035+ return (
1036+ <div>
1037+ <form action={redirectAction}>
1038+ <button type="submit" data-submit>
1039+ Redirect via Server Function
1040+ </button>
1041+ </form>
1042+ <Counter />
1043+ </div>
1044+ );
1045+ }
1046+ ` ,
1047+ "src/routes/side-effect-external-redirect-server-action/home.actions.ts" :js `
1048+ "use server";
1049+ import { redirect } from "react-router";
1050+
1051+ export async function redirectAction() {
1052+ // Perform a side-effect redirect to an external URL
1053+ redirect("https://example.com/", { headers: { "x-test": "test" } });
1054+ return "redirected";
1055+ }
1056+ ` ,
1057+ "src/routes/side-effect-external-redirect-server-action/home.client.tsx" :js `
1058+ "use client";
1059+ import { useState } from "react";
1060+
1061+ export function Counter() {
1062+ const [count, setCount] = useState(0);
1063+ return <button type="button" onClick={() => setCount(c => c + 1)} data-count>Count: {count}</button>;
1064+ }
1065+ ` ,
1066+ "src/routes/side-effect-external-redirect-server-action/home.tsx" :js `
1067+ "use client";
1068+ import {useActionState} from "react";
1069+ import { redirectAction } from "./home.actions";
1070+ import { Counter } from "./home.client";
1071+
1072+ export default function HomeRoute(props) {
1073+ const [state, action] = useActionState(redirectAction, null);
1074+ return (
1075+ <div>
1076+ <form action={action}>
1077+ <button type="submit" data-submit>
1078+ Redirect via Server Function
1079+ </button>
1080+ </form>
1081+ {state && <div data-testid="state">{state}</div>}
1082+ <Counter />
1083+ </div>
1084+ );
1085+ }
1086+ ` ,
9891087
9901088"src/routes/server-function-reference/home.actions.ts" :js `
9911089 "use server";
@@ -1736,6 +1834,33 @@ implementations.forEach((implementation) => {
17361834validateRSCHtml ( await page . content ( ) ) ;
17371835} ) ;
17381836
1837+ test ( "Supports React Server Functions thrown external redirects" , async ( {
1838+ page,
1839+ } ) => {
1840+ // Test is expected to fail currently — skip running it
1841+ // test.skip(true, "Known failing test for external redirect behavior");
1842+
1843+ await page . goto (
1844+ `http://localhost:${ port } /throw-external-redirect-server-action/` ,
1845+ ) ;
1846+
1847+ // Verify initial server render
1848+ await page . waitForSelector ( "[data-count]" ) ;
1849+ expect ( await page . locator ( "[data-count]" ) . textContent ( ) ) . toBe (
1850+ "Count: 0" ,
1851+ ) ;
1852+ await page . click ( "[data-count]" ) ;
1853+ expect ( await page . locator ( "[data-count]" ) . textContent ( ) ) . toBe (
1854+ "Count: 1" ,
1855+ ) ;
1856+
1857+ // Submit the form to trigger server function redirect to external URL
1858+ await page . click ( "[data-submit]" ) ;
1859+
1860+ // We expect the browser to navigate to the external site (example.com)
1861+ await expect ( page ) . toHaveURL ( `https://example.com/` ) ;
1862+ } ) ;
1863+
17391864test ( "Supports React Server Functions side-effect redirects" , async ( {
17401865 page,
17411866} ) => {
@@ -1789,6 +1914,46 @@ implementations.forEach((implementation) => {
17891914validateRSCHtml ( await page . content ( ) ) ;
17901915} ) ;
17911916
1917+ test ( "Supports React Server Functions side-effect external redirects" , async ( {
1918+ page,
1919+ } ) => {
1920+ // Test is expected to fail currently — skip running it
1921+ test . skip ( implementation . name === "parcel" , "Not working in parcel?" ) ;
1922+
1923+ await page . goto (
1924+ `http://localhost:${ port } /side-effect-external-redirect-server-action` ,
1925+ ) ;
1926+
1927+ // Verify initial server render
1928+ await page . waitForSelector ( "[data-count]" ) ;
1929+ expect ( await page . locator ( "[data-count]" ) . textContent ( ) ) . toBe (
1930+ "Count: 0" ,
1931+ ) ;
1932+ await page . click ( "[data-count]" ) ;
1933+ expect ( await page . locator ( "[data-count]" ) . textContent ( ) ) . toBe (
1934+ "Count: 1" ,
1935+ ) ;
1936+
1937+ const responseHeadersPromise = new Promise < Record < string , string > > (
1938+ ( resolve ) => {
1939+ page . addListener ( "response" , ( response ) => {
1940+ if ( response . request ( ) . method ( ) === "POST" ) {
1941+ resolve ( response . headers ( ) ) ;
1942+ }
1943+ } ) ;
1944+ } ,
1945+ ) ;
1946+
1947+ // Submit the form to trigger server function redirect to external URL
1948+ await page . click ( "[data-submit]" ) ;
1949+
1950+ // We expect the browser to navigate to the external site (example.com)
1951+ await expect ( page ) . toHaveURL ( `https://example.com/` ) ;
1952+
1953+ // Optionally assert that the server sent the header
1954+ expect ( ( await responseHeadersPromise ) [ "x-test" ] ) . toBe ( "test" ) ;
1955+ } ) ;
1956+
17921957test ( "Supports React Server Function References" , async ( { page} ) => {
17931958await page . goto ( `http://localhost:${ port } /server-function-reference` ) ;
17941959