Skip to content

Commit

Permalink
Fix matcher when invalid params
Browse files Browse the repository at this point in the history
  • Loading branch information
zoontek committed Dec 29, 2023
1 parent 3dd563c commit 7188e34
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 28 deletions.
122 changes: 95 additions & 27 deletions __tests__/matcher.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
import { randomUUID } from "crypto";
import { expect, test } from "vitest";
import { decodeLocation } from "../src/history";
import { getMatcher, match } from "../src/matcher";

const getMatcherEqual = <E>(name: string, route: string, expected: E) =>
expect(getMatcher(name, route)).toStrictEqual({ name, ...expected });

const matchers = [
getMatcher("Groups", "/groups"),
getMatcher("Group", "/groups/:groupId"),
getMatcher("MyGroup", "/groups/mine"),
getMatcher("UsersArea", "/groups/:groupId/users/*"),
getMatcher("Users", "/groups/:groupId/users"),
getMatcher("Project", "/projects/:projectId/:env{live|sandbox}"),
].sort((a, b) => b.ranking - a.ranking); // we sort the matchers since match doesn't do it at each call

const matchEqual = <E>(path: string, expected: E) =>
expect(match(decodeLocation(path), matchers)).toStrictEqual(expected);
const getMatcherEqual = <E>(route: string, expected: E) => {
const name = randomUUID();
return expect(getMatcher(name, route)).toStrictEqual({ name, ...expected });
};

test("getMatcher returns a proper matcher structure for paths without params", () => {
getMatcherEqual("Groups", "/groups", {
getMatcherEqual("/groups", {
isArea: false,
ranking: 9,
path: ["groups"],
search: undefined,
});

getMatcherEqual("MyGroup", "/groups/mine", {
getMatcherEqual("/groups/mine", {
isArea: false,
ranking: 18,
path: ["groups", "mine"],
Expand All @@ -34,21 +25,21 @@ test("getMatcher returns a proper matcher structure for paths without params", (
});

test("getMatcher returns a proper matcher structure for paths with params (in path only)", () => {
getMatcherEqual("Group", "/group/:groupId", {
getMatcherEqual("/group/:groupId", {
isArea: false,
ranking: 16,
path: ["group", { name: "groupId" }],
search: undefined,
});

getMatcherEqual("Users", "/groups/:groupId/users", {
getMatcherEqual("/groups/:groupId/users", {
isArea: false,
ranking: 25,
path: ["groups", { name: "groupId" }, "users"],
search: undefined,
});

getMatcherEqual("Project", "/projects/:projectId/:env{live|sandbox}", {
getMatcherEqual("/projects/:projectId/:env{live|sandbox}", {
isArea: false,
ranking: 24,
path: [
Expand All @@ -61,14 +52,17 @@ test("getMatcher returns a proper matcher structure for paths with params (in pa
});

test("getMatcher returns a proper matcher structure for paths with params (in path and search)", () => {
getMatcherEqual("Group", "/group/:groupId?:foo&:bar[]#:baz", {
getMatcherEqual("/group/:groupId?:foo&:bar[]#:baz", {
isArea: false,
ranking: 16,
path: ["group", { name: "groupId" }],
search: { foo: { multiple: false }, bar: { multiple: true } },
search: {
foo: { multiple: false },
bar: { multiple: true },
},
});

getMatcherEqual("Group", "/group/:groupId?:foo{a|b}&:bar{c|d}[]#:baz{e|f}", {
getMatcherEqual("/group/:groupId?:foo{a|b}&:bar{c|d}[]#:baz{e|f}", {
isArea: false,
ranking: 16,
path: ["group", { name: "groupId" }],
Expand All @@ -80,28 +74,72 @@ test("getMatcher returns a proper matcher structure for paths with params (in pa
});

test("getMatcher decrements the ranking by 1 if the path is an area", () => {
getMatcherEqual("UsersArea", "/groups/:groupId/users/*", {
getMatcherEqual("/groups/:groupId/users/*", {
isArea: true,
ranking: 24,
path: ["groups", { name: "groupId" }, "users"],
search: undefined,
});

getMatcherEqual("UsersArea", "/groups/:groupId/users/*?:foo&:bar[]", {
getMatcherEqual("/groups/:groupId/users/*?:foo&:bar[]", {
isArea: true,
ranking: 24,
path: ["groups", { name: "groupId" }, "users"],
search: { foo: { multiple: false }, bar: { multiple: true } },
search: {
foo: { multiple: false },
bar: { multiple: true },
},
});

getMatcherEqual("/groups/:groupId/users", {
isArea: false,
ranking: 25,
path: ["groups", { name: "groupId" }, "users"],
search: undefined,
});

getMatcherEqual("Users", "/groups/:groupId/users", {
getMatcherEqual("/groups/:groupId/users", {
isArea: false,
ranking: 25,
path: ["groups", { name: "groupId" }, "users"],
search: undefined,
});

getMatcherEqual(
"/groups?:orderBy{asc|desc}&:status{disabled|enabled|pending}[]",
{
isArea: false,
ranking: 9,
path: ["groups"],
search: {
orderBy: {
multiple: false,
values: ["asc", "desc"],
},
status: {
multiple: true,
values: ["disabled", "enabled", "pending"],
},
},
},
);
});

const matchers = [
getMatcher(
"Groups",
"/groups?:orderBy{asc|desc}&:status{disabled|enabled|pending}[]",
),
getMatcher("Group", "/groups/:groupId"),
getMatcher("MyGroup", "/groups/mine"),
getMatcher("UsersArea", "/groups/:groupId/users/*"),
getMatcher("Users", "/groups/:groupId/users"),
getMatcher("Project", "/projects/:projectId/:env{live|sandbox}"),
].sort((a, b) => b.ranking - a.ranking); // we sort the matchers since match doesn't do it at each call

const matchEqual = <E>(path: string, expected: E) =>
expect(match(decodeLocation(path), matchers)).toStrictEqual(expected);

test("match extract route params and matches against a matcher", () => {
matchEqual("/groups", {
name: "Groups",
Expand All @@ -128,6 +166,36 @@ test("match extract route params and matches against a matcher", () => {
params: { groupId: "github" },
});

matchEqual("/groups?orderBy=asc", {
name: "Groups",
params: { orderBy: "asc" },
});

matchEqual("/groups?orderBy=asc&orderBy=desc", {
name: "Groups",
params: { orderBy: "asc" },
});

matchEqual("/groups?orderBy=invalid", {
name: "Groups",
params: {},
});

matchEqual("/groups?orderBy=invalid&orderBy=desc", {
name: "Groups",
params: { orderBy: "desc" },
});

matchEqual("/groups?status=disabled&status=pending", {
name: "Groups",
params: { status: ["disabled", "pending"] },
});

matchEqual("/groups?status=invalid&status=pending", {
name: "Groups",
params: { status: ["pending"] },
});

matchEqual("/projects/swan/live", {
name: "Project",
params: { projectId: "swan", env: "live" },
Expand All @@ -137,5 +205,5 @@ test("match extract route params and matches against a matcher", () => {
test("match returns undefined in case of no route match", () => {
matchEqual("/repositories/:repositoryId", undefined);
matchEqual("/bills/:billId", undefined);
matchEqual("/projects/swan/unexpected", undefined);
matchEqual("/projects/swan/invalid", undefined);
});
6 changes: 5 additions & 1 deletion src/matcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,11 @@ export const extractLocationParams = (
}

const locationValue =
typeof locationPart === "string" ? locationPart : locationPart[0];
typeof locationPart === "string"
? locationPart
: values == null
? locationPart[0]
: locationPart.filter((item) => values.includes(item))[0];

if (
locationValue != null &&
Expand Down

0 comments on commit 7188e34

Please sign in to comment.