Skip to content

Commit caf3c85

Browse files
committed
Merge branch 'dev' of github.com:remix-run/react-router into dev
2 parents d191ea1 + fea545d commit caf3c85

File tree

3 files changed

+187
-4
lines changed

3 files changed

+187
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import * as React from "react";
2+
import { create as createTestRenderer } from "react-test-renderer";
3+
import {
4+
MemoryRouter as Router,
5+
Route,
6+
Routes,
7+
useParams
8+
} from "react-router";
9+
10+
describe("<Routes> with a location", () => {
11+
12+
function Home() {
13+
return <h1>Home</h1>;
14+
}
15+
16+
function User() {
17+
let { userId } = useParams();
18+
return (
19+
<div>
20+
<h1>User: {userId}</h1>
21+
</div>
22+
);
23+
}
24+
25+
it("matches when the location is overridden", () => {
26+
27+
const location = {
28+
pathname: '/home',
29+
search: '',
30+
hash: '',
31+
state: null,
32+
key: 'r9qntrej'
33+
};
34+
const renderer = createTestRenderer(
35+
<Router initialEntries={["/users/michael"]}>
36+
<Routes location={location}>
37+
<Route path="home" element={<Home />} />
38+
<Route path="users/:userId" element={<User />} />
39+
</Routes>
40+
</Router>
41+
);
42+
43+
expect(renderer.toJSON()).not.toBeNull();
44+
expect(renderer.toJSON()).toMatchInlineSnapshot(`
45+
<h1>
46+
Home
47+
</h1>
48+
`);
49+
});
50+
51+
52+
it("matches when the location is not overridden", () => {
53+
const renderer = createTestRenderer(
54+
<Router initialEntries={["/users/michael"]}>
55+
<Routes>
56+
<Route path="home" element={<Home />} />
57+
<Route path="users/:userId" element={<User />} />
58+
</Routes>
59+
</Router>
60+
);
61+
62+
expect(renderer.toJSON()).not.toBeNull();
63+
expect(renderer.toJSON()).toMatchInlineSnapshot(`
64+
<div>
65+
<h1>
66+
User:
67+
michael
68+
</h1>
69+
</div>
70+
`);
71+
});
72+
});

packages/react-router/__tests__/navigate-test.tsx

+108
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as ReactDOM from "react-dom";
33
import { act } from "react-dom/test-utils";
44
import {
55
MemoryRouter as Router,
6+
Outlet,
67
Routes,
78
Route,
89
useNavigate,
@@ -163,4 +164,111 @@ describe("navigate", () => {
163164
expect(node.innerHTML).toMatchInlineSnapshot(`"<h1>About mj</h1>"`);
164165
});
165166
});
167+
168+
describe("with a search param and no pathname", () => {
169+
function Bakery() {
170+
let navigate = useNavigate();
171+
172+
let user = new URLSearchParams(useLocation().search).get("user");
173+
function handleClick() {
174+
navigate({
175+
search: user ? "" : new URLSearchParams({ user: "mj" }).toString()
176+
});
177+
}
178+
179+
return (
180+
<div>
181+
<h1>Bakery</h1>
182+
{user && <p>Welcome {user}</p>}
183+
<Outlet />
184+
<button onClick={handleClick}>{user ? "logout" : "login"}</button>
185+
</div>
186+
);
187+
}
188+
189+
function Muffins() {
190+
return <h2>Yay, muffins!</h2>;
191+
}
192+
193+
function About() {
194+
let user = new URLSearchParams(useLocation().search).get("user");
195+
return <h1>About {user}</h1>;
196+
}
197+
198+
it("resolves using the current location", () => {
199+
act(() => {
200+
ReactDOM.render(
201+
<Router initialEntries={["/bakery/muffins"]}>
202+
<Routes>
203+
<Route path="bakery" element={<Bakery />}>
204+
<Route path="muffins" element={<Muffins />} />
205+
</Route>
206+
<Route path="about" element={<About />} />
207+
</Routes>
208+
</Router>,
209+
node
210+
);
211+
});
212+
213+
let button = node.querySelector("button");
214+
215+
act(() => {
216+
button?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
217+
});
218+
219+
expect(node.innerHTML).toMatchInlineSnapshot(
220+
`"<div><h1>Bakery</h1><p>Welcome mj</p><h2>Yay, muffins!</h2><button>logout</button></div>"`
221+
);
222+
});
223+
});
224+
225+
describe("with a hash param and no pathname", () => {
226+
function Bakery() {
227+
let navigate = useNavigate();
228+
function handleClick() {
229+
navigate({
230+
hash: "#about"
231+
});
232+
}
233+
234+
return (
235+
<div>
236+
<h1>Bakery</h1>
237+
<button onClick={handleClick}>About us</button>
238+
<Outlet />
239+
<h2 id="about">About us</h2>
240+
<p>We bake delicious cakes!</p>
241+
</div>
242+
);
243+
}
244+
245+
function Muffins() {
246+
return <h2>Yay, muffins!</h2>;
247+
}
248+
249+
it("resolves using the current location", () => {
250+
act(() => {
251+
ReactDOM.render(
252+
<Router initialEntries={["/bakery/muffins"]}>
253+
<Routes>
254+
<Route path="bakery" element={<Bakery />}>
255+
<Route path="muffins" element={<Muffins />} />
256+
</Route>
257+
</Routes>
258+
</Router>,
259+
node
260+
);
261+
});
262+
263+
let button = node.querySelector("button");
264+
265+
act(() => {
266+
button?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
267+
});
268+
269+
expect(node.innerHTML).toMatchInlineSnapshot(
270+
`"<div><h1>Bakery</h1><button>About us</button><h2>Yay, muffins!</h2><h2 id=\\"about\\">About us</h2><p>We bake delicious cakes!</p></div>"`
271+
);
272+
});
273+
});
166274
});

packages/react-router/index.tsx

+7-4
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ export function Router({
253253
export interface RoutesProps {
254254
basename?: string;
255255
children?: React.ReactNode;
256+
location?: Location;
256257
}
257258

258259
/**
@@ -263,11 +264,12 @@ export interface RoutesProps {
263264
*/
264265
export function Routes({
265266
basename = "",
266-
children
267+
children,
268+
location
267269
}: RoutesProps): React.ReactElement | null {
268270
let routes = createRoutesFromChildren(children);
269-
let location = useLocation();
270-
return useRoutes_(routes, location, basename);
271+
let location_ = useLocation();
272+
return useRoutes_(routes, location ?? location_, basename);
271273
}
272274

273275
///////////////////////////////////////////////////////////////////////////////
@@ -413,7 +415,8 @@ export function useNavigate(): NavigateFunction {
413415
);
414416

415417
let navigator = React.useContext(NavigatorContext);
416-
let { pathname, basename } = React.useContext(RouteContext);
418+
let { basename } = React.useContext(RouteContext);
419+
let { pathname } = useLocation();
417420

418421
let activeRef = React.useRef(false);
419422
React.useEffect(() => {

0 commit comments

Comments
 (0)