UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

260 lines (224 loc) 6.41 kB
import { describe, it } from "vitest"; import { RouterProvider } from "../providers/RouterProvider.ts"; interface TestRoute { name: string; path: string; } class TestRouterProvider extends RouterProvider<TestRoute> { public push(route: TestRoute) { super.push(route); } } const playground = () => { const router = new TestRouterProvider(); const add = (path: string, name: string) => { router.push({ path, name, }); }; const match = (path: string) => { const { route, params } = router.match(`${path}?a=b`); return { name: route?.name ?? "null", params: params, }; }; return { add, match, router, }; }; describe("RouterProvider", () => { it("should match routes with static paths, params, and wildcards", ({ expect, }) => { const { add, match } = playground(); add("/", "home"); add("/about", "about"); add("/dist/", "dist"); add("/users", "users"); add("/users/:name", "users-by-name"); add("/users/:name/INFO", "users-by-name-info"); add("/users/:name/x/y/z", "users-by-name-x-y-z"); add("/useRs/:name/x/*", "users-by-name-x-not-found"); add("/*", "not-found"); expect(match("/")).toEqual({ name: "home", params: {}, }); expect(match("/about")).toEqual({ name: "about", params: {}, }); expect(match("/dist")).toEqual({ name: "dist", params: {}, }); expect(match("/dist/")).toEqual({ name: "dist", params: {}, }); expect(match("/users/jack")).toEqual({ name: "users-by-name", params: { name: "jack", }, }); expect(match("/users/jack/info")).toEqual({ name: "users-by-name-info", params: { name: "jack", }, }); expect(match("/users/jack/info/other")).toEqual({ name: "not-found", params: { name: "jack", }, }); expect(match("/users/JACK/x")).toEqual({ name: "users-by-name-x-not-found", params: { name: "JACK", }, }); expect(match("/users/jack/x/y")).toEqual({ name: "users-by-name-x-not-found", params: { name: "jack", }, }); expect(match("/users/jack/x/y/z")).toEqual({ name: "users-by-name-x-y-z", params: { name: "jack", }, }); expect(match("/users/jack/x/abc/def")).toEqual({ name: "users-by-name-x-not-found", params: { "*": "abc/def", name: "jack", }, }); expect(match("/weird")).toEqual({ name: "not-found", params: { "*": "weird", }, }); }); it("should return null for paths with no matching routes", ({ expect }) => { const { match } = playground(); expect(match("/")).toEqual({ name: "null", params: {}, }); expect(match("/abc/def")).toEqual({ name: "null", params: {}, }); }); it("should throw error for invalid path formats", ({ expect }) => { const { match } = playground(); expect(() => match("x")).toThrowError(); expect(() => match("(*__*)")).toThrowError(); }); it("should match only wildcard route", ({ expect }) => { const { add, match } = playground(); add("/*", "wildcard"); expect(match("/")).toEqual({ name: "wildcard", params: { "*": "", }, }); }); it("should throw error when adding invalid path", ({ expect }) => { const { add } = playground(); expect(() => add("*", "wildcard")).toThrowError(); }); it("should handle routes with params and wildcard", ({ expect }) => { const { add, match } = playground(); add("/users/*", "users-not-found"); add("/users/:name/x/*", "users-by-name-x-not-found"); expect(match("/users/jack/x/y/z")).toEqual({ name: "users-by-name-x-not-found", params: { name: "jack", "*": "y/z", }, }); }); it("should return a fresh params object on each match (no shared mutation)", ({ expect, }) => { const { add, router } = playground(); add("/users/:id", "user"); const a = router.match("/users/42"); const b = router.match("/users/42"); expect(a.params).not.toBe(b.params); a.params!.injected = "x"; expect(b.params).toEqual({ id: "42" }); }); it("should cache by pathname only (ignoring query string)", ({ expect }) => { const { add, router } = playground(); add("/search", "search"); router.match("/search?q=1"); router.match("/search?q=2"); router.match("/search?q=3"); // cache is protected; assert via Map size on the subclass expect( (router as unknown as { cache: Map<string, unknown> }).cache.size, ).toBe(1); }); it("should cap the cache size to avoid unbounded growth", ({ expect }) => { const { add, router } = playground(); add("/*", "catchall"); (router as unknown as { maxCacheSize: number }).maxCacheSize = 5; for (let i = 0; i < 20; i++) { router.match(`/x/${i}`); } const size = (router as unknown as { cache: Map<string, unknown> }).cache .size; expect(size).toBeLessThanOrEqual(5); }); it("should invalidate the cache when a new route is pushed", ({ expect }) => { const { add, router } = playground(); const m1 = router.match("/new"); expect(m1.route).toBeUndefined(); add("/new", "new-route"); const m2 = router.match("/new"); expect(m2.route?.name).toBe("new-route"); }); it("should handle three-way conflicting param names at the same level", ({ expect, }) => { const { add, match } = playground(); add("/u/:a", "a-route"); add("/u/:b/x", "b-route"); add("/u/:c/y", "c-route"); expect(match("/u/1")).toEqual({ name: "a-route", params: { a: "1" } }); expect(match("/u/1/x")).toEqual({ name: "b-route", params: { b: "1" } }); expect(match("/u/1/y")).toEqual({ name: "c-route", params: { c: "1" } }); }); it("should handle routes with different param names", ({ expect }) => { const { add, match } = playground(); add("/users/:id", "home"); add("/users/:userId/hello", "hello"); expect(match("/users/jack")).toEqual({ name: "home", params: { id: "jack", }, }); expect(match("/users/jack/hello")).toEqual({ name: "hello", params: { userId: "jack", }, }); }); });