diff --git a/.changeset/six-ways-carry.md b/.changeset/six-ways-carry.md new file mode 100644 index 0000000000..3f965a1e7b --- /dev/null +++ b/.changeset/six-ways-carry.md @@ -0,0 +1,5 @@ +--- +"react-router": patch +--- + +Preserve `statusText` on the `ErrorResponse` instance when throwing `data()` from a route handler diff --git a/contributors.yml b/contributors.yml index 821d13e030..992ac57d28 100644 --- a/contributors.yml +++ b/contributors.yml @@ -456,3 +456,4 @@ - zeromask1337 - zheng-chuang - zxTomw +- keshavjoshi-ca diff --git a/packages/react-router/__tests__/router/instrumentation-test.ts b/packages/react-router/__tests__/router/instrumentation-test.ts index 27374f6875..54518a8562 100644 --- a/packages/react-router/__tests__/router/instrumentation-test.ts +++ b/packages/react-router/__tests__/router/instrumentation-test.ts @@ -1283,7 +1283,9 @@ describe("instrumentation", () => { let A = await t.navigate("/page"); expect(spy).toHaveBeenNthCalledWith(1, "outer-start"); expect(spy).toHaveBeenNthCalledWith(2, "inner-start"); - await A.loaders.page.reject(data({ message: "hello" }, { status: 418 })); + await A.loaders.page.reject( + data({ message: "hello" }, { status: 418, statusText: "I'm a teapot" }), + ); expect(spy).toHaveBeenNthCalledWith(3, "inner-end"); expect(spy).toHaveBeenNthCalledWith(4, "outer-end"); expect(t.router.state).toMatchObject({ @@ -1291,7 +1293,9 @@ describe("instrumentation", () => { location: { pathname: "/page" }, loaderData: {}, errors: { - page: new ErrorResponseImpl(418, "", { message: "hello" }), + page: new ErrorResponseImpl(418, "I'm a teapot", { + message: "hello", + }), }, }); }); diff --git a/packages/react-router/__tests__/router/router-test.ts b/packages/react-router/__tests__/router/router-test.ts index df63df71b3..b598f7cadd 100644 --- a/packages/react-router/__tests__/router/router-test.ts +++ b/packages/react-router/__tests__/router/router-test.ts @@ -5,7 +5,7 @@ import type { AgnosticDataRouteObject, AgnosticRouteObject, } from "../../lib/router/utils"; -import { ErrorResponseImpl } from "../../lib/router/utils"; +import { data, ErrorResponseImpl } from "../../lib/router/utils"; import { urlMatch } from "./utils/custom-matchers"; import { @@ -1915,6 +1915,33 @@ describe("a router", () => { }); }); + it("handles thrown data() values as ErrorResponse's", async () => { + let t = setup({ + routes: TASK_ROUTES, + initialEntries: ["/"], + hydrationData: { + loaderData: { + root: "ROOT_DATA", + index: "INDEX_DATA", + }, + }, + }); + + let nav = await t.navigate("/tasks"); + await nav.loaders.tasks.reject( + data("broken", { status: 400, statusText: "Bad Request" }), + ); + expect(t.router.state).toMatchObject({ + navigation: IDLE_NAVIGATION, + loaderData: { + root: "ROOT_DATA", + }, + errors: { + tasks: new ErrorResponseImpl(400, "Bad Request", "broken"), + }, + }); + }); + it("sends proper arguments to actions", async () => { let t = setup({ routes: TASK_ROUTES, diff --git a/packages/react-router/lib/router/router.ts b/packages/react-router/lib/router/router.ts index 23155b7582..0cee95df0a 100644 --- a/packages/react-router/lib/router/router.ts +++ b/packages/react-router/lib/router/router.ts @@ -6212,11 +6212,7 @@ async function convertDataStrategyResultToDataResult( // Convert thrown data() to ErrorResponse instances return { type: ResultType.error, - error: new ErrorResponseImpl( - result.init?.status || 500, - undefined, - result.data, - ), + error: dataWithResponseInitToErrorResponse(result), statusCode: isRouteErrorResponse(result) ? result.status : undefined, headers: result.init?.headers ? new Headers(result.init.headers)