Skip to content

Commit bf08537

Browse files
authored
Normalize search + hash strings in resolvePath (#7953)
* Normalize search and hash strings in resolvePath * remove unused vars in tests * simplify test
1 parent 16f0542 commit bf08537

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

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

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
MemoryRouter as Router,
66
Routes,
77
Route,
8-
useNavigate
8+
useNavigate,
9+
useLocation
910
} from "react-router";
1011

1112
describe("navigate", () => {
@@ -115,4 +116,51 @@ describe("navigate", () => {
115116
expect(node.innerHTML).toMatchInlineSnapshot(`"<h1>About</h1>"`);
116117
});
117118
});
119+
120+
describe("with a search param", () => {
121+
it("navigates to the correct URL with params", () => {
122+
function Home() {
123+
let navigate = useNavigate();
124+
125+
function handleClick() {
126+
navigate({
127+
pathname: "../about",
128+
search: new URLSearchParams({ user: "mj" }).toString()
129+
});
130+
}
131+
132+
return (
133+
<div>
134+
<h1>Home</h1>
135+
<button onClick={handleClick}>click me</button>
136+
</div>
137+
);
138+
}
139+
140+
function About() {
141+
let user = new URLSearchParams(useLocation().search).get("user");
142+
return <h1>About {user}</h1>;
143+
}
144+
145+
act(() => {
146+
ReactDOM.render(
147+
<Router initialEntries={["/home"]}>
148+
<Routes>
149+
<Route path="home" element={<Home />} />
150+
<Route path="about" element={<About />} />
151+
</Routes>
152+
</Router>,
153+
node
154+
);
155+
});
156+
157+
let button = node.querySelector("button");
158+
159+
act(() => {
160+
button?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
161+
});
162+
163+
expect(node.innerHTML).toMatchInlineSnapshot(`"<h1>About mj</h1>"`);
164+
});
165+
});
118166
});

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,33 @@ describe("useResolvedPath", () => {
3232
});
3333
});
3434

35+
it("partial path object resolves to Path object", () => {
36+
let path!: Path;
37+
function Home() {
38+
path = useResolvedPath({
39+
pathname: "/home",
40+
search: new URLSearchParams({ user: "mj" }).toString(),
41+
hash: "#welcome"
42+
});
43+
return <h1>Home</h1>;
44+
}
45+
46+
createTestRenderer(
47+
<Router initialEntries={["/home"]}>
48+
<Routes>
49+
<Route path="/home" element={<Home />} />
50+
</Routes>
51+
</Router>
52+
);
53+
54+
expect(typeof path).toBe("object");
55+
expect(path).toMatchObject({
56+
pathname: "/home",
57+
search: "?user=mj",
58+
hash: "#welcome"
59+
});
60+
});
61+
3562
describe("given a hash with a ? character", () => {
3663
it("hash is not parsed as a search string", () => {
3764
let path!: Path;

packages/react-router/index.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,13 +989,25 @@ export function resolvePath(to: To, fromPathname = "/", basename = ""): Path {
989989
)
990990
: fromPathname;
991991

992-
return { pathname, search, hash };
992+
return {
993+
pathname,
994+
search: normalizeSearch(search),
995+
hash: normalizeHash(hash)
996+
};
993997
}
994998

995999
const trimTrailingSlashes = (path: string) => path.replace(/\/+$/, "");
9961000
const normalizeSlashes = (path: string) => path.replace(/\/\/+/g, "/");
9971001
const joinPaths = (paths: string[]) => normalizeSlashes(paths.join("/"));
9981002
const splitPath = (path: string) => normalizeSlashes(path).split("/");
1003+
const normalizeSearch = (search: string) =>
1004+
!search || search === "?"
1005+
? ""
1006+
: search.startsWith("?")
1007+
? search
1008+
: "?" + search;
1009+
const normalizeHash = (hash: string) =>
1010+
!hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
9991011

10001012
function resolvePathname(toPathname: string, fromPathname: string): string {
10011013
let segments = splitPath(trimTrailingSlashes(fromPathname));

0 commit comments

Comments
 (0)