[FIX] router: add support for more arbitrary param placements in paths

Before this commit, params in paths had to be be between slashes and
comprise the entirety of the contents between those slashes (eg:
`/books/{{id}}/{{name}}`)

This is unnecessarily restrictive. This commit removes this restriction,
which allows for paths such as:
- `/books/{{id}}-{{name}}`
- `#books&id={{id}}&name={{name}}`

among others

closes #858
This commit is contained in:
Samuel Degueldre
2021-05-19 10:17:30 +02:00
committed by Géry Debongnie
parent 968a5460bb
commit acac9d1741
4 changed files with 99 additions and 55 deletions
+24
View File
@@ -103,4 +103,28 @@ describe("RouteComponent", () => {
await app.mount(fixture);
expect(fixture.innerHTML).toBe("<div><span>Book 1984|124</span></div>");
});
test("can render parameterized route where params are not separated by slashes", async () => {
env.qweb.addTemplates(`
<templates>
<div t-name="App">
<RouteComponent />
</div>
<span t-name="Book">Book <t t-esc="props.title"/>|<t t-esc="props.val"/></span>
</templates>
`);
class Book extends Component {}
class App extends Component {
static components = { RouteComponent };
}
const routes = [
{ name: "book", path: "/#title={{title}}&val={{val.number}}", component: Book },
];
router = new TestRouter(env, routes, { mode: "hash" });
await router.navigate({ to: "book", params: { title: "1984", val: "123" } });
const app = new App();
await app.mount(fixture);
expect(fixture.innerHTML).toBe("<div><span>Book 1984|123</span></div>");
});
});
+27 -23
View File
@@ -1,6 +1,6 @@
import { Destination, RouterEnv, Route } from "../../src/router/router";
import { makeTestEnv, nextTick } from "../helpers";
import { TestRouter } from "./test_router";
import { TestRouter, getRouteParams } from "./test_router";
let env: RouterEnv;
let router: TestRouter | null = null;
@@ -107,60 +107,64 @@ describe("destToPath", () => {
describe("getRouteParams", () => {
test("properly match simple routes", () => {
router = new TestRouter(env, []);
// simple route
expect(router["getRouteParams"]({ path: "/home" } as Route, "/home")).toEqual({});
expect(getRouteParams({ path: "/home" }, "/home")).toEqual({});
// no match
expect(router["getRouteParams"]({ path: "/home" } as Route, "/otherpath")).toEqual(false);
expect(getRouteParams({ path: "/home" }, "/otherpath")).toEqual(false);
// fallback route
expect(router["getRouteParams"]({ path: "*" } as Route, "somepath")).toEqual({});
expect(getRouteParams({ path: "*" }, "somepath")).toEqual({});
});
test("properly match simple routes, mode hash", () => {
router = new TestRouter(env, [], { mode: "hash" });
// simple route
expect(router["getRouteParams"]({ path: "/home" } as Route, "#/home")).toEqual({});
expect(getRouteParams({ path: "/home" }, "#/home")).toEqual({});
// no match
expect(router["getRouteParams"]({ path: "/home" } as Route, "#/otherpath")).toEqual(false);
expect(getRouteParams({ path: "/home" }, "#/otherpath")).toEqual(false);
// fallback route
expect(router["getRouteParams"]({ path: "*" } as Route, "#/somepath")).toEqual({});
expect(getRouteParams({ path: "*" }, "#/somepath")).toEqual({});
});
test("match some parameterized routes", () => {
router = new TestRouter(env, []);
expect(router["getRouteParams"]({ path: "/invoices/{{id}}" } as Route, "/invoices/3")).toEqual({
expect(getRouteParams({ path: "/invoices/{{id}}" }, "/invoices/3")).toEqual({
id: "3",
});
});
test("match some parameterized routes, mode hash", () => {
router = new TestRouter(env, [], { mode: "hash" });
expect(router["getRouteParams"]({ path: "/invoices/{{id}}" } as Route, "#/invoices/3")).toEqual(
{
id: "3",
}
);
expect(getRouteParams({ path: "/invoices/{{id}}" }, "#/invoices/3")).toEqual({
id: "3",
});
});
test("can convert to number if needed", () => {
router = new TestRouter(env, []);
expect(
router["getRouteParams"]({ path: "/invoices/{{id.number}}" } as Route, "/invoices/3")
).toEqual({
expect(getRouteParams({ path: "/invoices/{{id.number}}" }, "/invoices/3")).toEqual({
id: 3,
});
});
test("can convert to number if needed, mode: hash", () => {
router = new TestRouter(env, [], { mode: "hash" });
expect(getRouteParams({ path: "/invoices/{{id.number}}" }, "#/invoices/3")).toEqual({
id: 3,
});
});
test("can extract params not separated by slashes", () => {
expect(getRouteParams({ path: "/books/{{id.number}}-{{name}}" }, "/books/3-1984")).toEqual({
id: 3,
name: "1984",
});
});
test("can extract params not separated by slashes, mode: hash", () => {
expect(
router["getRouteParams"]({ path: "/invoices/{{id.number}}" } as Route, "#/invoices/3")
getRouteParams({ path: "books&id={{id.number}}&name={{name}}" }, "#books&id=3&name=1984")
).toEqual({
id: 3,
name: "1984",
});
});
});
+12 -1
View File
@@ -1,4 +1,5 @@
import { Router } from "../../src/router/router";
import { Router, Route, RouterEnv } from "../../src/router/router";
import { makeTestEnv } from "../helpers";
import { QWeb } from "../../src/qweb/index";
export class TestRouter extends Router {
@@ -13,3 +14,13 @@ export class TestRouter extends Router {
}
}
}
export function getRouteParams(route: Partial<Route>, path: string) {
const env = <RouterEnv>makeTestEnv();
const router = new TestRouter(env, [route]);
const {
routeIds: [routeId],
routes,
} = router;
return router["getRouteParams"](routes[routeId], path);
}