From 55be6437f15e694f44f0e19595a7e9a608baa1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Sat, 31 Aug 2019 09:46:20 +0200 Subject: [PATCH] [FIX] router: better support for hash mode --- src/router/Router.ts | 6 ++- tests/router/router.test.ts | 99 ++++++++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/router/Router.ts b/src/router/Router.ts index aa9c3411..c81866b9 100644 --- a/src/router/Router.ts +++ b/src/router/Router.ts @@ -164,7 +164,8 @@ export class Router { parts[i] = params[key]; } } - return parts.join("/"); + const prefix = this.mode === "hash" ? "#" : ""; + return prefix + parts.join("/"); } private currentPath(): string { @@ -223,6 +224,9 @@ export class Router { if (route.path === "*") { return {}; } + if (path.startsWith("#")) { + path = path.slice(1); + } const descrParts = route.path.split("/"); const targetParts = path.split("/"); const l = descrParts.length; diff --git a/tests/router/router.test.ts b/tests/router/router.test.ts index 680f47f8..8850bf74 100644 --- a/tests/router/router.test.ts +++ b/tests/router/router.test.ts @@ -1,4 +1,4 @@ -import { Destination, Router, RouterEnv, Route } from "../../src/router/Router"; +import { Destination, RouterEnv, Route } from "../../src/router/Router"; import { makeTestEnv } from "../helpers"; import { TestRouter } from "./TestRouter"; @@ -28,15 +28,28 @@ describe("router miscellaneous", () => { }); describe("routeToPath", () => { - const routeToPath = Router.prototype["routeToPath"]; test("simple non parameterized path", () => { - expect(routeToPath({path: "/abc"} as Route, {})).toBe("/abc"); - expect(routeToPath({path: "/abc/def"} as Route, {})).toBe("/abc/def"); - expect(routeToPath({path: "/abc"} as Route, { val: 12 })).toBe("/abc"); + router = new TestRouter(env, []); + expect(router["routeToPath"]({ path: "/abc" } as Route, {})).toBe("/abc"); + expect(router["routeToPath"]({ path: "/abc/def" } as Route, {})).toBe("/abc/def"); + expect(router["routeToPath"]({ path: "/abc" } as Route, { val: 12 })).toBe("/abc"); }); test("simple parameterized path", () => { - expect(routeToPath({path: "/abc/{{def}}"} as Route, { def: 34 })).toBe("/abc/34"); + router = new TestRouter(env, []); + expect(router["routeToPath"]({ path: "/abc/{{def}}" } as Route, { def: 34 })).toBe("/abc/34"); + }); + + test("simple non parameterized path, mode = hash", () => { + router = new TestRouter(env, [], { mode: "hash" }); + expect(router["routeToPath"]({ path: "/abc" } as Route, {})).toBe("#/abc"); + expect(router["routeToPath"]({ path: "/abc/def" } as Route, {})).toBe("#/abc/def"); + expect(router["routeToPath"]({ path: "/abc" } as Route, { val: 12 })).toBe("#/abc"); + }); + + test("simple parameterized path, mode=hash", () => { + router = new TestRouter(env, [], { mode: "hash" }); + expect(router["routeToPath"]({ path: "/abc/{{def}}" } as Route, { def: 34 })).toBe("#/abc/34"); }); }); @@ -58,26 +71,60 @@ describe("destToPath", () => { }); describe("getRouteParams", () => { - const getRouteParams = Router.prototype["getRouteParams"]; test("properly match simple routes", () => { + router = new TestRouter(env, []); // simple route - expect(getRouteParams({path: "/home"} as Route, "/home")).toEqual({}); + expect(router["getRouteParams"]({ path: "/home" } as Route, "/home")).toEqual({}); // no match - expect(getRouteParams({path: "/home"} as Route, "/otherpath")).toEqual(false); + expect(router["getRouteParams"]({ path: "/home" } as Route, "/otherpath")).toEqual(false); // fallback route - expect(getRouteParams({path: "*"} as Route, "somepath")).toEqual({}); + expect(router["getRouteParams"]({ path: "*" } as Route, "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({}); + + // no match + expect(router["getRouteParams"]({ path: "/home" } as Route, "#/otherpath")).toEqual(false); + + // fallback route + expect(router["getRouteParams"]({ path: "*" } as Route, "#/somepath")).toEqual({}); }); test("match some parameterized routes", () => { - expect(getRouteParams({path: "/invoices/{{id}}"} as Route, "/invoices/3")).toEqual({ + router = new TestRouter(env, []); + expect(router["getRouteParams"]({ path: "/invoices/{{id}}" } as Route, "/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" + } + ); + }); + test("can convert to number if needed", () => { - expect(getRouteParams({path: "/invoices/{{id.number}}"} as Route, "/invoices/3")).toEqual({ + router = new TestRouter(env, []); + expect( + router["getRouteParams"]({ path: "/invoices/{{id.number}}" } as Route, "/invoices/3") + ).toEqual({ + id: 3 + }); + }); + + test("can convert to number if needed, mode: hash", () => { + router = new TestRouter(env, [], { mode: "hash" }); + expect( + router["getRouteParams"]({ path: "/invoices/{{id.number}}" } as Route, "#/invoices/3") + ).toEqual({ id: 3 }); }); @@ -131,9 +178,9 @@ describe("beforeRouteEnter", () => { expect(window.location.pathname).toBe("/"); const guard = jest.fn(() => false); router = new TestRouter(env, [ - { name: "routea", path: "/some/patha"}, - { name: "routeb", path: "/some/pathb", beforeRouteEnter: guard } - ]); + { name: "routea", path: "/some/patha" }, + { name: "routeb", path: "/some/pathb", beforeRouteEnter: guard } + ]); await router.start(); await router.navigate({ to: "routea" }); @@ -147,12 +194,14 @@ describe("beforeRouteEnter", () => { test("navigation is redirected if guard decides so", async () => { expect(window.location.pathname).toBe("/"); - const guard = jest.fn(() => {return {to: "routec"}}); + const guard = jest.fn(() => { + return { to: "routec" }; + }); router = new TestRouter(env, [ - { name: "routea", path: "/some/patha"}, - { name: "routeb", path: "/some/pathb", beforeRouteEnter: guard }, - { name: "routec", path: "/some/pathc"}, - ]); + { name: "routea", path: "/some/patha" }, + { name: "routeb", path: "/some/pathb", beforeRouteEnter: guard }, + { name: "routec", path: "/some/pathc" } + ]); await router.start(); const result = await router.navigate({ to: "routea" }); @@ -166,11 +215,13 @@ describe("beforeRouteEnter", () => { test("navigation is initially redirected if guard decides so", async () => { expect(window.location.pathname).toBe("/"); - const guard = jest.fn(() => {return {to: "otherroute"}}); + const guard = jest.fn(() => { + return { to: "otherroute" }; + }); router = new TestRouter(env, [ - { name: "landing", path: "/", beforeRouteEnter: guard}, - { name: "otherroute", path: "/some/other/route"} - ]); + { name: "landing", path: "/", beforeRouteEnter: guard }, + { name: "otherroute", path: "/some/other/route" } + ]); expect(window.location.pathname).toBe("/");