Skip to content

Fix greedy * in route paths #8052

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
},
"filesize": {
"build/react-router/react-router.production.min.js": {
"none": "6 kB"
"none": "7 kB"
},
"build/react-router/umd/react-router.production.min.js": {
"none": "8 kB"
Expand Down
82 changes: 82 additions & 0 deletions packages/react-router/__tests__/greedy-matching-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as React from "react";
import { create as createTestRenderer } from "react-test-renderer";
import {
MemoryRouter as Router,
Routes,
Route,
Outlet
} from "react-router-dom";

describe("greedy matching", () => {
let routes = (
<Routes>
<Route path="/" element={<p>Root</p>} />
<Route
path="home"
element={
<div>
Home Layout <Outlet />
</div>
}
>
<Route index element={<p>Home</p>} />
<Route path="*" element={<p>Home Not Found</p>} />
</Route>
<Route path="*" element={<p>Not Found</p>} />
</Routes>
);

it("matches the root route", () => {
let renderer = createTestRenderer(
<Router initialEntries={["/"]} children={routes} />
);

expect(renderer.toJSON()).toMatchInlineSnapshot(`
<p>
Root
</p>
`);
});

it("matches the index route", () => {
let renderer = createTestRenderer(
<Router initialEntries={["/home"]} children={routes} />
);

expect(renderer.toJSON()).toMatchInlineSnapshot(`
<div>
Home Layout
<p>
Home
</p>
</div>
`);
});

it('matches the nested "not found" route', () => {
let renderer = createTestRenderer(
<Router initialEntries={["/home/typo"]} children={routes} />
);

expect(renderer.toJSON()).toMatchInlineSnapshot(`
<div>
Home Layout
<p>
Home Not Found
</p>
</div>
`);
});

it('matches the "not found" route', () => {
let renderer = createTestRenderer(
<Router initialEntries={["/hometypo"]} children={routes} />
);

expect(renderer.toJSON()).toMatchInlineSnapshot(`
<p>
Not Found
</p>
`);
});
});
205 changes: 205 additions & 0 deletions packages/react-router/__tests__/matchPath-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import { matchPath } from "react-router";

describe("matchPath", () => {
it("matches the root / URL", () => {
expect(matchPath("/", "/")).toMatchObject({ pathname: "/" });
});

describe("when the pattern has no leading slash", () => {
it("fails to match a pathname that does not match", () => {
expect(matchPath("users", "/usersblah")).toBeNull();
});

it("matches a pathname", () => {
expect(matchPath("users", "/users")).toMatchObject({
pathname: "/users"
});
});

it("matches a pathname with multiple segments", () => {
expect(matchPath("users/mj", "/users/mj")).toMatchObject({
pathname: "/users/mj"
});
});

it("matches a pathname with a trailing slash", () => {
expect(matchPath("users", "/users/")).toMatchObject({
pathname: "/users/"
});
});

it("matches a pathname with multiple segments and a trailing slash", () => {
expect(matchPath("users/mj", "/users/mj/")).toMatchObject({
pathname: "/users/mj/"
});
});
});

describe("when the pattern has a leading slash", () => {
it("fails to match a pathname that does not match", () => {
expect(matchPath("/users", "/usersblah")).toBeNull();
});

it("matches a pathname", () => {
expect(matchPath("/users", "/users")).toMatchObject({
pathname: "/users"
});
});

it("matches a pathname with multiple segments", () => {
expect(matchPath("/users/mj", "/users/mj")).toMatchObject({
pathname: "/users/mj"
});
});

it("matches a pathname with a trailing slash", () => {
expect(matchPath("/users", "/users/")).toMatchObject({
pathname: "/users/"
});
});

it("matches a pathname with multiple segments and a trailing slash", () => {
expect(matchPath("/users/mj", "/users/mj/")).toMatchObject({
pathname: "/users/mj/"
});
});
});

describe("when the pattern has a trailing slash", () => {
it("fails to match a pathname that does not match", () => {
expect(matchPath("users/", "/usersblah")).toBeNull();
});

it("matches a pathname", () => {
expect(matchPath("users/", "/users")).toMatchObject({
pathname: "/users"
});
});

it("matches a pathname with multiple segments", () => {
expect(matchPath("users/mj/", "/users/mj")).toMatchObject({
pathname: "/users/mj"
});
});

it("matches a pathname with a trailing slash", () => {
expect(matchPath("users/", "/users/")).toMatchObject({
pathname: "/users/"
});
});

it("matches a pathname with multiple segments and a trailing slash", () => {
expect(matchPath("users/mj/", "/users/mj/")).toMatchObject({
pathname: "/users/mj/"
});
});
});

describe("with { end: false }", () => {
it("matches the beginning of a pathname", () => {
expect(matchPath({ path: "/users", end: false }, "/users")).toMatchObject(
{ pathname: "/users" }
);
});

it("matches the beginning of a pathname with multiple segments", () => {
expect(
matchPath({ path: "/users", end: false }, "/users/mj")
).toMatchObject({ pathname: "/users" });
});

it("fails to match a pathname where the segments do not match", () => {
expect(matchPath({ path: "/users", end: false }, "/")).toBeNull();
expect(matchPath({ path: "/users", end: false }, "/users2")).toBeNull();
expect(
matchPath({ path: "/users/mj", end: false }, "/users/mj2")
).toBeNull();
});
});

describe("with { end: false } and a / pattern", () => {
it("matches a pathname", () => {
expect(matchPath({ path: "/", end: false }, "/users")).toMatchObject({
pathname: "/"
});
});

it("matches a pathname with multiple segments", () => {
expect(matchPath({ path: "/", end: false }, "/users/mj")).toMatchObject({
pathname: "/"
});
});

it("matches a pathname with a trailing slash", () => {
expect(matchPath({ path: "/", end: false }, "/users/")).toMatchObject({
pathname: "/"
});
});

it("matches a pathname with multiple segments and a trailing slash", () => {
expect(matchPath({ path: "/", end: false }, "/users/mj/")).toMatchObject({
pathname: "/"
});
});
});

it("is not case-sensitive by default", () => {
expect(matchPath("/SystemDashboard", "/systemdashboard")).toMatchObject({
pathname: "/systemdashboard"
});
});

it("matches a case-sensitive pathname", () => {
expect(
matchPath(
{ path: "/SystemDashboard", caseSensitive: true },
"/SystemDashboard"
)
).toMatchObject({
pathname: "/SystemDashboard"
});
});

it("does not match a case-sensitive pathname with the wrong case", () => {
expect(
matchPath(
{ path: "/SystemDashboard", caseSensitive: true },
"/systemDashboard"
)
).toBeNull();
});

describe("when the pattern has a trailing *", () => {
it("matches the remaining portion of the pathname", () => {
expect(matchPath("/files*", "/files/mj.jpg")).toMatchObject({
params: { "*": "/mj.jpg" },
pathname: "/files/mj.jpg"
});
expect(matchPath("/files*", "/files/")).toMatchObject({
params: { "*": "/" },
pathname: "/files/"
});
expect(matchPath("/files*", "/files")).toMatchObject({
params: { "*": "" },
pathname: "/files"
});
});
});

describe("when the pattern has a trailing /*", () => {
it("matches the remaining portion of the pathname", () => {
expect(matchPath("/files/*", "/files/mj.jpg")).toMatchObject({
params: { "*": "mj.jpg" },
pathname: "/files/mj.jpg"
});
expect(matchPath("/files/*", "/files/")).toMatchObject({
params: { "*": "" },
pathname: "/files/"
});
expect(matchPath("/files/*", "/files")).toMatchObject({
params: { "*": "" },
pathname: "/files"
});
});
});
});
1 change: 1 addition & 0 deletions packages/react-router/__tests__/matchRoutes-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe("matchRoutes", () => {

it("matches root * routes correctly", () => {
expect(pickPaths(routes, "/not-found")).toEqual(["*"]);
expect(pickPaths(routes, "/hometypo")).toEqual(["*"]);
});

it("matches index routes correctly", () => {
Expand Down
86 changes: 0 additions & 86 deletions packages/react-router/__tests__/nested-params-test.tsx

This file was deleted.

Loading