Skip to content

Commit

Permalink
fix: support basename and relative routing in loader/action redirects (
Browse files Browse the repository at this point in the history
…#9447)

* fix: respect basename in loaders and actions redirects (#9418)

Co-authored-by: Mikaël ANZANO <m.anzano@meetic-corp.com>

* fix: support basename and relative routes in redirects

* ci: add tests for data memory router

* add changeset

* Bump bundle threshold

* convert invariant to 404 for missing routeId

* Bundle bump

Co-authored-by: Mikaël Anzano <mikael.anzano@gmail.com>
Co-authored-by: Mikaël ANZANO <m.anzano@meetic-corp.com>
  • Loading branch information
3 people committed Oct 21, 2022
1 parent ec9bacf commit 8f684eb
Show file tree
Hide file tree
Showing 5 changed files with 652 additions and 61 deletions.
5 changes: 5 additions & 0 deletions .changeset/smart-ants-decide.md
@@ -0,0 +1,5 @@
---
"@remix-run/router": patch
---

Support basename and relative routing in loader/action redirects
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -107,7 +107,7 @@
},
"filesize": {
"packages/router/dist/router.js": {
"none": "105 kB"
"none": "106 kB"
},
"packages/react-router/dist/react-router.production.min.js": {
"none": "12.5 kB"
Expand Down
117 changes: 117 additions & 0 deletions packages/react-router/__tests__/data-memory-router-test.tsx
Expand Up @@ -9,6 +9,7 @@ import {
} from "@testing-library/react";
import "@testing-library/jest-dom";
import type { FormMethod, Router, RouterInit } from "@remix-run/router";
import { joinPaths } from "@remix-run/router";
import type { RouteObject } from "react-router";
import {
Await,
Expand All @@ -20,6 +21,7 @@ import {
createMemoryRouter,
createRoutesFromElements,
defer,
redirect,
useActionData,
useAsyncError,
useAsyncValue,
Expand Down Expand Up @@ -158,6 +160,116 @@ describe("<DataMemoryRouter>", () => {
`);
});

it("prepends basename to loader/action redirects", async () => {
let { container } = render(
<DataMemoryRouter
basename="/my/base/path"
initialEntries={["/my/base/path"]}
>
<Route path="/" element={<Root />}>
<Route path="thing" loader={() => redirect("/other")} />
<Route path="other" element={<h1>Other</h1>} />
</Route>
</DataMemoryRouter>
);

function Root() {
return (
<>
<MemoryNavigate to="/thing">Link to thing</MemoryNavigate>
<Outlet />
</>
);
}

expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<a
href=\\"/my/base/path/thing\\"
>
Link to thing
</a>
</div>"
`);

fireEvent.click(screen.getByText("Link to thing"));
await waitFor(() => screen.getByText("Other"));
expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<a
href=\\"/my/base/path/thing\\"
>
Link to thing
</a>
<h1>
Other
</h1>
</div>"
`);
});

it("supports relative routing in loader/action redirects", async () => {
let { container } = render(
<DataMemoryRouter
basename="/my/base/path"
initialEntries={["/my/base/path"]}
>
<Route path="/" element={<Root />}>
<Route path="parent" element={<Parent />}>
<Route path="child" loader={() => redirect("../other")} />
<Route path="other" element={<h2>Other</h2>} />
</Route>
</Route>
</DataMemoryRouter>
);

function Root() {
return (
<>
<MemoryNavigate to="/parent/child">Link to child</MemoryNavigate>
<Outlet />
</>
);
}

function Parent() {
return (
<>
<h1>Parent</h1>
<Outlet />
</>
);
}

expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<a
href=\\"/my/base/path/parent/child\\"
>
Link to child
</a>
</div>"
`);

fireEvent.click(screen.getByText("Link to child"));
await waitFor(() => screen.getByText("Parent"));
expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<a
href=\\"/my/base/path/parent/child\\"
>
Link to child
</a>
<h1>
Parent
</h1>
<h2>
Other
</h2>
</div>"
`);
});

it("renders with hydration data", async () => {
let { container } = render(
<DataMemoryRouter
Expand Down Expand Up @@ -2817,6 +2929,11 @@ function MemoryNavigate({
}) {
let dataRouterContext = React.useContext(DataRouterContext);

let basename = dataRouterContext?.basename;
if (basename && basename !== "/") {
to = to === "/" ? basename : joinPaths([basename, to]);
}

let onClickHandler = React.useCallback(
async (event: React.MouseEvent) => {
event.preventDefault();
Expand Down

0 comments on commit 8f684eb

Please sign in to comment.