UNPKG

@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
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"); }); }); });