router-dom
Version:
A lightweight router for everyone
285 lines (254 loc) • 10.3 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Router Tests</title>
<script type="module">
import { hydro, $ } from "hydro-js";
import { runTests } from "@web/test-runner-mocha";
import { expect } from "@esm-bundle/chai";
import Router from "../../dist/router.js";
const sleep = (time) =>
new Promise((resolve) => setTimeout(resolve, time));
runTests(() => {
describe("router", () => {
let router;
beforeEach(async () => {
router = new Router([
{
path: "/",
element: "<h1>Home</h1>",
leave(params) {
window.leaveHome = params;
},
beforeEnter(params) {
window.beforeEnterHome = params;
},
afterEnter(params) {
window.afterEnterHome = params;
},
},
{
path: "/a(\\?)?(.*)",
element: "<h1>a</h1>",
leave(params) {
window.leaveA = params;
},
beforeEnter(params) {
window.beforeEnterA = params;
},
afterEnter(params) {
window.afterEnterA = params;
},
},
{
path: "/b/:id?",
element: "<h1>b</h1>",
leave(params) {
window.leaveB = params;
},
beforeEnter(params) {
window.beforeEnterB = params;
},
afterEnter(params) {
window.afterEnterB = params;
},
},
]);
router.go("/");
await sleep(50);
delete window.leaveHome;
delete window.leaveA;
delete window.leaveB;
delete window.beforeEnterHome;
delete window.beforeEnterA;
delete window.beforeEnterB;
delete window.afterEnterHome;
delete window.afterEnterA;
delete window.afterEnterB;
});
it("applies to the correct elements", () => {
expect($("#home").getAttribute("href").startsWith("http")).to.be
.false;
expect($("#other").getAttribute("href").startsWith("http")).to.be
.true;
});
it("goes to the correct route when clicking on an element", () => {
$("#home").click();
expect(location.pathname + location.search).to.equal("/");
$("#a").click();
expect(location.pathname + location.search).to.equal("/a");
$("#b").click();
expect(location.pathname + location.search).to.equal("/b");
$("#home").click();
expect(location.pathname + location.search).to.equal("/");
});
it("goes to the correct route when clicking on an element - with params", () => {
$("#param").click();
expect(location.pathname).to.equal("/a");
expect(location.search).to.equal("?q=testing");
});
it("goes to the correct route when clicking on an element (API)", () => {
router.go("/a?q=testing2");
expect(location.pathname).to.equal("/a");
expect(location.search).to.equal("?q=testing2");
});
it("goes to the correct route when clicking on an element - with params (API)", () => {
router.go("/b", {}, "?q=testing3");
expect(location.pathname).to.equal("/b");
expect(location.search).to.equal("?q=testing3");
});
it("goes to the correct route (param with spaces) and returns the correct params", () => {
router.go("/b?q=test value");
expect(location.pathname).to.equal("/b");
expect(location.search).to.equal("?q=test%20value");
expect(Router.getParams()).to.deep.equal({ q: "test value" });
});
it("sends data via API", () => {
const data = { awesome: 42 };
router.go("/a", data);
expect(history.state).to.deep.equal(data);
});
it("sends data via element", () => {
hydro.data = { awesome: 42 };
$("#data").click();
expect(history.state).to.deep.equal(hydro.data);
});
it("renders into data-outlet", async () => {
$("#a").click();
await sleep(50);
expect($("[data-outlet]").textContent).to.include("a");
router.go("/b", data);
await sleep(50);
expect($("[data-outlet]").textContent).to.include("b");
});
it("does not navigate when route is the same", async () => {
const props = { from: "/", to: "/a" };
$("#a").click();
await sleep(50);
expect(window.beforeEnterA).to.deep.equal(props);
delete window.beforeEnterA;
$("#a").click();
await sleep(50);
expect(window.beforeEnterA).to.be.undefined;
$("#param").click();
await sleep(50);
expect(window.beforeEnterA).to.not.be.undefined;
});
it("calls the lifecycle hooks when navigating via API", async () => {
const props = { from: "/", to: "/a" };
router.go("/a");
await sleep(50);
expect(window.leaveHome).to.deep.equal(props);
expect(window.beforeEnterA).to.deep.equal(props);
expect(window.afterEnterA).to.deep.equal(props);
expect(window.leaveA).to.be.undefined;
expect(window.leaveB).to.be.undefined;
expect(window.beforeEnterHome).to.be.undefined;
expect(window.beforeEnterB).to.be.undefined;
expect(window.afterEnterHome).to.be.undefined;
expect(window.afterEnterB).to.be.undefined;
});
it("calls the lifecycle hooks when navigating via click", async () => {
const props = { from: "/", to: "/b/4", params: { id: "4" } };
$("#id").click();
await sleep(50);
expect(window.leaveHome).to.deep.equal(props);
expect(window.beforeEnterB).to.deep.equal(props);
expect(window.afterEnterB).to.deep.equal(props);
expect(window.leaveA).to.be.undefined;
expect(window.leaveB).to.be.undefined;
expect(window.beforeEnterHome).to.be.undefined;
expect(window.beforeEnterA).to.be.undefined;
expect(window.afterEnterHome).to.be.undefined;
expect(window.afterEnterA).to.be.undefined;
});
it("calls the lifecycle hooks when navigating via browser API", async () => {
const props = { from: "/", to: "/b/4", params: { id: "4" } };
history.back();
await sleep(50);
expect(window.leaveHome).to.deep.equal(props);
expect(window.beforeEnterB).to.deep.equal(props);
expect(window.afterEnterB).to.deep.equal(props);
expect(window.leaveA).to.be.undefined;
expect(window.leaveB).to.be.undefined;
expect(window.beforeEnterHome).to.be.undefined;
expect(window.beforeEnterA).to.be.undefined;
expect(window.afterEnterHome).to.be.undefined;
expect(window.afterEnterA).to.be.undefined;
});
it("uses the errorHandler", async () => {
router = new Router(
[
{
path: "/",
leave() {
throw "Route Error";
},
},
{
path: "/a",
},
],
{
errorHandler(err) {
window.err = err;
},
}
);
$("#a").click();
await sleep(50);
expect(window.err).to.equal("Route Error");
delete window.err;
});
describe("passes params and state when using the lifecycle hooks", () => {
it("uses state and data - click", async () => {
const props = {
from: "/",
to: "/a?q=testing",
params: { q: "testing" },
state: { awesome: 42 },
};
$("#data").click();
await sleep(50);
expect(window.leaveHome).to.deep.equal(props);
});
it("uses state and data - API", async () => {
const props = {
from: "/",
to: "/a?q=testing",
params: { q: "testing" },
state: { awesome: 42 },
};
router.go("/a?q=testing", { awesome: 42 });
await sleep(50);
expect(window.leaveHome).to.deep.equal(props);
});
it("uses state and data - API - param", async () => {
const props = {
from: "/",
to: "/a?q=testing",
params: { q: "testing" },
state: { awesome: 42 },
};
router.go("/a", { awesome: 42 }, "?q=testing");
await sleep(50);
expect(window.leaveHome).to.deep.equal(props);
});
});
});
});
</script>
</head>
<body>
<a id="home" href="/">Home</a>
<a id="a" href="/a">a</a>
<a id="b" href="/b">b</a>
<a id="id" href="/b/4">b</a>
<a id="other" href="https://krutsch.netlify.app">Page</a>
<a id="param" href="/a?q=testing">a</a>
<a id="data" href="/a?q=testing" data="data">a</a>
<div data-outlet></div>
</body>
</html>