@esmx/router-vue
Version:
Vue integration for @esmx/router - A universal router that works seamlessly with both Vue 2.7+ and Vue 3
437 lines (436 loc) • 14.9 kB
JavaScript
import { Router, RouterMode } from "@esmx/router";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { createApp, defineComponent, h, nextTick } from "vue";
import { RouterPlugin } from "./plugin.mjs";
import { RouterLink } from "./router-link.mjs";
import { RouterView } from "./router-view.mjs";
import { useProvideRouter } from "./use.mjs";
describe("plugin.ts - RouterPlugin", () => {
let router;
let app;
let container;
beforeEach(async () => {
container = document.createElement("div");
container.id = "test-app";
document.body.appendChild(container);
const routes = [
{
path: "/",
component: defineComponent({
name: "Home",
render: () => h("div", "Home Page")
}),
meta: { title: "Home" }
},
{
path: "/about",
component: defineComponent({
name: "About",
render: () => h("div", "About Page")
}),
meta: { title: "About" }
}
];
router = new Router({
mode: RouterMode.memory,
routes,
base: new URL("http://localhost:8000/")
});
await router.replace("/");
await nextTick();
});
afterEach(() => {
if (app) {
app.unmount();
}
if (router) {
router.destroy();
}
if (container == null ? void 0 : container.parentNode) {
container.parentNode.removeChild(container);
}
});
describe("Plugin Installation", () => {
it("should install plugin without errors", () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App");
}
});
expect(() => {
app.use(RouterPlugin);
}).not.toThrow();
});
it("should throw error for invalid Vue app instance", () => {
const invalidApp = {};
expect(() => {
RouterPlugin.install(invalidApp);
}).toThrow("[@esmx/router-vue] Invalid Vue app instance");
});
it("should throw error for null app instance", () => {
expect(() => {
RouterPlugin.install(null);
}).toThrow("[@esmx/router-vue] Invalid Vue app instance");
});
it("should throw error for undefined app instance", () => {
expect(() => {
RouterPlugin.install(void 0);
}).toThrow("[@esmx/router-vue] Invalid Vue app instance");
});
});
describe("Global Properties Injection", () => {
it("should inject $router and $route properties", async () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App");
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
const globalProperties = app.config.globalProperties;
const routerDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$router"
);
const routeDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$route"
);
expect(routerDescriptor).toBeDefined();
expect(routeDescriptor).toBeDefined();
expect(routerDescriptor == null ? void 0 : routerDescriptor.get).toBeDefined();
expect(routeDescriptor == null ? void 0 : routeDescriptor.get).toBeDefined();
expect(typeof (routerDescriptor == null ? void 0 : routerDescriptor.get)).toBe("function");
expect(typeof (routeDescriptor == null ? void 0 : routeDescriptor.get)).toBe("function");
});
it("should provide reactive $route property", async () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App");
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
await router.push("/about");
await nextTick();
const globalProperties = app.config.globalProperties;
const routeDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$route"
);
expect(routeDescriptor == null ? void 0 : routeDescriptor.get).toBeDefined();
expect(typeof (routeDescriptor == null ? void 0 : routeDescriptor.get)).toBe("function");
expect(routeDescriptor == null ? void 0 : routeDescriptor.enumerable).toBe(false);
expect(routeDescriptor == null ? void 0 : routeDescriptor.configurable).toBe(false);
});
it("should provide consistent $router instance across components", async () => {
const ChildComponent = defineComponent({
render() {
return h("div", "Child");
}
});
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", [h("div", "Parent"), h(ChildComponent)]);
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
const globalProperties = app.config.globalProperties;
const routerDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$router"
);
const routeDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$route"
);
expect(routerDescriptor).toBeDefined();
expect(routeDescriptor).toBeDefined();
expect(routerDescriptor == null ? void 0 : routerDescriptor.get).toBeDefined();
expect(typeof (routerDescriptor == null ? void 0 : routerDescriptor.get)).toBe("function");
expect(routeDescriptor == null ? void 0 : routeDescriptor.get).toBeDefined();
expect(typeof (routeDescriptor == null ? void 0 : routeDescriptor.get)).toBe("function");
});
it("should actually call $router getter when accessed in component", async () => {
let routerResult = null;
const TestComponent = defineComponent({
mounted() {
routerResult = this.$router;
},
render() {
return h("div", "Test Component");
}
});
app = createApp({
setup() {
useProvideRouter(router);
return () => h(TestComponent);
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
expect(routerResult).toEqual(router);
expect(routerResult).toBeInstanceOf(Router);
});
it("should actually call $route getter when accessed in component", async () => {
let routeResult = null;
const TestComponent = defineComponent({
mounted() {
routeResult = this.$route;
},
render() {
return h("div", "Test Component");
}
});
app = createApp({
setup() {
useProvideRouter(router);
return () => h(TestComponent);
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
await router.push("/about");
await nextTick();
expect(routeResult).toBeTruthy();
expect(routeResult).toHaveProperty("path", "/about");
expect(routeResult).toHaveProperty("meta.title", "About");
});
});
describe("Component Registration", () => {
it("should register components with correct names", () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App");
}
});
app.use(RouterPlugin);
const globalComponents = app._context.components;
expect(globalComponents).toHaveProperty("RouterLink");
expect(globalComponents).toHaveProperty("RouterView");
expect(globalComponents.RouterLink).toBe(RouterLink);
expect(globalComponents.RouterView).toBe(RouterView);
});
it("should register RouterLink component for global use", async () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App with RouterLink available");
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
const globalComponents = app._context.components;
expect(globalComponents.RouterLink).toBeDefined();
expect(typeof globalComponents.RouterLink).toBe("object");
});
it("should register RouterView component for global use", async () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App with RouterView available");
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
const globalComponents = app._context.components;
expect(globalComponents.RouterView).toBeDefined();
expect(typeof globalComponents.RouterView).toBe("object");
});
});
describe("Error Handling", () => {
it("should handle missing router context in global properties", () => {
const mockComponent = {
$: {
provides: {}
}
};
const target = {};
Object.defineProperties(target, {
$router: {
get() {
return require("./use").getRouter(mockComponent);
}
}
});
expect(() => {
target.$router;
}).toThrow();
});
it("should handle missing router context in $route property", () => {
const mockComponent = {
$: {
provides: {}
}
};
const target = {};
Object.defineProperties(target, {
$route: {
get() {
return require("./use").getRoute(mockComponent);
}
}
});
expect(() => {
target.$route;
}).toThrow();
});
});
describe("Plugin Integration", () => {
it("should work with multiple plugin installations", () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App");
}
});
app.use(RouterPlugin);
app.use(RouterPlugin);
expect(() => {
app.mount(container);
}).not.toThrow();
});
it("should maintain global properties after installation", async () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App");
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
const globalProperties = app.config.globalProperties;
const routerDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$router"
);
const routeDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$route"
);
expect(routerDescriptor).toBeDefined();
expect(routeDescriptor).toBeDefined();
expect(routerDescriptor == null ? void 0 : routerDescriptor.get).toBeDefined();
expect(routeDescriptor == null ? void 0 : routeDescriptor.get).toBeDefined();
expect(typeof (routerDescriptor == null ? void 0 : routerDescriptor.get)).toBe("function");
expect(typeof (routeDescriptor == null ? void 0 : routeDescriptor.get)).toBe("function");
});
});
describe("Type Safety", () => {
it("should provide properly typed global properties", async () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App");
}
});
app.use(RouterPlugin);
app.mount(container);
await nextTick();
const globalProperties = app.config.globalProperties;
const routerDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$router"
);
const routeDescriptor = Object.getOwnPropertyDescriptor(
globalProperties,
"$route"
);
expect(routerDescriptor).toBeDefined();
expect(routeDescriptor).toBeDefined();
expect(typeof (routerDescriptor == null ? void 0 : routerDescriptor.get)).toBe("function");
expect(typeof (routeDescriptor == null ? void 0 : routeDescriptor.get)).toBe("function");
expect(
Object.prototype.hasOwnProperty.call(
globalProperties,
"$router"
)
).toBe(true);
expect(
Object.prototype.hasOwnProperty.call(globalProperties, "$route")
).toBe(true);
});
it("should provide correct component types", () => {
app = createApp({
setup() {
useProvideRouter(router);
return () => h("div", "Test App");
}
});
app.use(RouterPlugin);
const globalComponents = app._context.components;
expect(globalComponents.RouterLink.name).toBe("RouterLink");
expect(globalComponents.RouterView.name).toBe("RouterView");
const routerLinkComponent = globalComponents.RouterLink;
const routerViewComponent = globalComponents.RouterView;
expect(typeof routerLinkComponent.setup).toBe("function");
expect(typeof routerViewComponent.setup).toBe("function");
});
});
describe("Advanced Plugin Features", () => {
it("should support property descriptor configuration", () => {
const testApp = {
config: {
globalProperties: {}
},
component: (name, component) => {
}
};
RouterPlugin.install(testApp);
const routerDescriptor = Object.getOwnPropertyDescriptor(
testApp.config.globalProperties,
"$router"
);
const routeDescriptor = Object.getOwnPropertyDescriptor(
testApp.config.globalProperties,
"$route"
);
expect(routerDescriptor == null ? void 0 : routerDescriptor.get).toBeDefined();
expect(routerDescriptor == null ? void 0 : routerDescriptor.enumerable).toBe(false);
expect(routerDescriptor == null ? void 0 : routerDescriptor.configurable).toBe(false);
expect(routeDescriptor == null ? void 0 : routeDescriptor.get).toBeDefined();
expect(routeDescriptor == null ? void 0 : routeDescriptor.enumerable).toBe(false);
expect(routeDescriptor == null ? void 0 : routeDescriptor.configurable).toBe(false);
});
it("should handle different app instance structures", () => {
const minimalApp = {
config: {
globalProperties: {}
},
component: () => {
}
};
expect(() => {
RouterPlugin.install(minimalApp);
}).not.toThrow();
const routerDescriptor = Object.getOwnPropertyDescriptor(
minimalApp.config.globalProperties,
"$router"
);
const routeDescriptor = Object.getOwnPropertyDescriptor(
minimalApp.config.globalProperties,
"$route"
);
expect(routerDescriptor).toBeDefined();
expect(routeDescriptor).toBeDefined();
expect(routerDescriptor == null ? void 0 : routerDescriptor.get).toBeDefined();
expect(routeDescriptor == null ? void 0 : routeDescriptor.get).toBeDefined();
expect(typeof (routerDescriptor == null ? void 0 : routerDescriptor.get)).toBe("function");
expect(typeof (routeDescriptor == null ? void 0 : routeDescriptor.get)).toBe("function");
});
});
});