@esmx/router-vue
Version:
Vue integration for @esmx/router - A universal router that works seamlessly with both Vue 2.7+ and Vue 3
377 lines (376 loc) • 11.6 kB
JavaScript
import { Router, RouterMode } from "@esmx/router";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { nextTick } from "vue";
import { createApp, defineComponent, getCurrentInstance, h } from "vue";
import { RouterView } from "./router-view.mjs";
import {
getRouterViewDepth,
useProvideRouter,
useRoute,
useRouter,
useRouterViewDepth
} from "./use.mjs";
describe("Router Vue Integration", () => {
let app;
let router;
let mountPoint;
beforeEach(async () => {
router = new Router({
mode: RouterMode.memory,
routes: [
{ path: "/initial", component: {} },
{ path: "/new-route", component: {} },
{ path: "/user/:id", component: {} },
{ path: "/new-path", component: {} }
],
base: new URL("http://localhost:8000/")
});
await router.replace("/initial");
mountPoint = document.createElement("div");
mountPoint.id = "app";
document.body.appendChild(mountPoint);
});
afterEach(() => {
if (app) {
app.unmount();
}
document.body.removeChild(mountPoint);
router.destroy();
});
describe("Router and Route Access", () => {
it("should provide router and route access", async () => {
let routerResult;
let routeResult;
const TestApp = {
setup() {
useProvideRouter(router);
routerResult = useRouter();
routeResult = useRoute();
return () => h("div", "Test App");
}
};
app = createApp(TestApp);
app.mount("#app");
expect(routerResult).toEqual(router);
expect(routeResult).toBeDefined();
expect(routeResult == null ? void 0 : routeResult.path).toBe("/initial");
});
});
describe("Route Reactivity", () => {
it("should update route properties when route changes", async () => {
let routeRef;
const TestApp = {
setup() {
useProvideRouter(router);
routeRef = useRoute();
return () => h("div", routeRef == null ? void 0 : routeRef.path);
}
};
app = createApp(TestApp);
app.mount("#app");
expect(routeRef == null ? void 0 : routeRef.path).toBe("/initial");
const initialRouteRef = routeRef;
await router.replace("/new-route");
await nextTick();
expect(routeRef).toBe(initialRouteRef);
expect(routeRef == null ? void 0 : routeRef.path).toBe("/new-route");
});
it("should update route params when route changes", async () => {
var _a;
let routeRef;
const TestApp = {
setup() {
useProvideRouter(router);
routeRef = useRoute();
return () => {
var _a2;
return h("div", [
h("span", routeRef == null ? void 0 : routeRef.path),
h("span", ((_a2 = routeRef == null ? void 0 : routeRef.params) == null ? void 0 : _a2.id) || "no-id")
]);
};
}
};
app = createApp(TestApp);
app.mount("#app");
await router.replace("/user/123");
await nextTick();
expect(routeRef == null ? void 0 : routeRef.path).toBe("/user/123");
expect((_a = routeRef == null ? void 0 : routeRef.params) == null ? void 0 : _a.id).toBe("123");
});
it("should automatically update view when route changes", async () => {
const renderCount = { value: 0 };
let routeRef;
const TestApp = {
setup() {
useProvideRouter(router);
routeRef = useRoute();
return () => {
renderCount.value++;
return h("div", routeRef == null ? void 0 : routeRef.path);
};
}
};
app = createApp(TestApp);
app.mount("#app");
const initialRenderCount = renderCount.value;
expect(routeRef == null ? void 0 : routeRef.path).toBe("/initial");
await router.replace("/new-route");
await nextTick();
expect(renderCount.value).toBeGreaterThan(initialRenderCount);
expect(routeRef == null ? void 0 : routeRef.path).toBe("/new-route");
const previousRenderCount = renderCount.value;
await router.replace("/new-path");
await nextTick();
expect(renderCount.value).toBeGreaterThan(previousRenderCount);
expect(routeRef == null ? void 0 : routeRef.path).toBe("/new-path");
});
});
describe("Nested Components", () => {
it("should provide route context to child components", async () => {
let parentRoute;
let childRoute;
const ChildComponent = {
setup() {
childRoute = useRoute();
return () => h("div", "Child: " + (childRoute == null ? void 0 : childRoute.path));
}
};
const ParentComponent = {
setup() {
parentRoute = useRoute();
return () => h("div", [
h("span", "Parent: " + (parentRoute == null ? void 0 : parentRoute.path)),
h(ChildComponent)
]);
}
};
const TestApp = {
setup() {
useProvideRouter(router);
return () => h(ParentComponent);
}
};
app = createApp(TestApp);
app.mount("#app");
expect(parentRoute).toBeDefined();
expect(childRoute).toBeDefined();
expect(parentRoute == null ? void 0 : parentRoute.path).toBe("/initial");
expect(childRoute == null ? void 0 : childRoute.path).toBe("/initial");
await router.replace("/new-path");
await nextTick();
expect(parentRoute == null ? void 0 : parentRoute.path).toBe("/new-path");
expect(childRoute == null ? void 0 : childRoute.path).toBe("/new-path");
});
});
describe("RouterView Depth", () => {
it("should get depth in single RouterView", async () => {
let observedDepth;
const LeafProbe = defineComponent({
setup() {
const p = getCurrentInstance().proxy;
observedDepth = getRouterViewDepth(p);
return () => h("div");
}
});
const Level1 = defineComponent({
setup() {
return () => h("div", [h(LeafProbe)]);
}
});
router = new Router({
mode: RouterMode.memory,
routes: [{ path: "/level1", component: Level1 }],
base: new URL("http://localhost:8000/")
});
await router.replace("/level1");
const TestApp = defineComponent({
setup() {
useProvideRouter(router);
return () => h("div", [h(RouterView)]);
}
});
app = createApp(TestApp);
app.mount("#app");
await nextTick();
expect(observedDepth).toBe(1);
});
it("should get depth in nested RouterView", async () => {
let observedDepth;
const LeafProbe = defineComponent({
setup() {
const p = getCurrentInstance().proxy;
observedDepth = getRouterViewDepth(p);
return () => h("div");
}
});
const Level1 = defineComponent({
setup() {
return () => h("div", [h(RouterView)]);
}
});
const Leaf = defineComponent({
setup() {
return () => h("div", [h(LeafProbe)]);
}
});
router = new Router({
mode: RouterMode.memory,
routes: [
{
path: "/level1",
component: Level1,
children: [{ path: "leaf", component: Leaf }]
}
],
base: new URL("http://localhost:8000/")
});
await router.replace("/level1/leaf");
const TestApp = defineComponent({
setup() {
useProvideRouter(router);
return () => h("div", [h(RouterView)]);
}
});
app = createApp(TestApp);
app.mount("#app");
await nextTick();
expect(observedDepth).toBe(2);
});
it("should get depth in double-nested RouterViews", async () => {
let observedDepth;
const LeafProbe = defineComponent({
setup() {
const p = getCurrentInstance().proxy;
observedDepth = getRouterViewDepth(p);
return () => h("div");
}
});
const Level1 = defineComponent({
setup() {
return () => h("div", [h(RouterView)]);
}
});
const Level2 = defineComponent({
setup() {
return () => h("div", [h(RouterView)]);
}
});
const Leaf = defineComponent({
setup() {
return () => h("div", [h(LeafProbe)]);
}
});
router = new Router({
mode: RouterMode.memory,
routes: [
{
path: "/level1",
component: Level1,
children: [
{
path: "level2",
component: Level2,
children: [{ path: "leaf", component: Leaf }]
}
]
}
],
base: new URL("http://localhost:8000/")
});
await router.replace("/level1/level2/leaf");
const TestApp = defineComponent({
setup() {
useProvideRouter(router);
return () => h("div", [h(RouterView)]);
}
});
app = createApp(TestApp);
app.mount("#app");
await nextTick();
expect(observedDepth).toBe(3);
});
it("should throw when no RouterView ancestor exists", async () => {
let callDepth;
const Probe = defineComponent({
setup() {
const p = getCurrentInstance().proxy;
callDepth = () => getRouterViewDepth(p);
return () => h("div");
}
});
const TestApp = defineComponent({
setup() {
useProvideRouter(router);
return () => h(Probe);
}
});
app = createApp(TestApp);
app.mount("#app");
await nextTick();
expect(() => callDepth()).toThrow(
new Error(
"[@esmx/router-vue] RouterView depth not found. Please ensure a RouterView exists in ancestor components."
)
);
});
it("should return 0 for useRouterViewDepth without RouterView", async () => {
let observed = -1;
const Probe = defineComponent({
setup() {
observed = useRouterViewDepth();
return () => h("div");
}
});
const TestApp = defineComponent({
setup() {
useProvideRouter(router);
return () => h(Probe);
}
});
app = createApp(TestApp);
app.mount("#app");
await nextTick();
expect(observed).toBe(0);
});
it("should reflect depth via useRouterViewDepth at each level", async () => {
let level1Depth = -1;
let level2Depth = -1;
const Level2 = defineComponent({
setup() {
level2Depth = useRouterViewDepth();
return () => h("div");
}
});
const Level1 = defineComponent({
setup() {
level1Depth = useRouterViewDepth();
return () => h("div", [h(RouterView)]);
}
});
router = new Router({
mode: RouterMode.memory,
routes: [
{
path: "/level1",
component: Level1,
children: [{ path: "level2", component: Level2 }]
}
],
base: new URL("http://localhost:8000/")
});
await router.replace("/level1/level2");
const TestApp = defineComponent({
setup() {
useProvideRouter(router);
return () => h("div", [h(RouterView)]);
}
});
app = createApp(TestApp);
app.mount("#app");
await nextTick();
expect(level1Depth).toBe(1);
expect(level2Depth).toBe(2);
});
});
});