]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
fix: custom directive doesn't work when custom=true (#2377)
authorDecadeMoon <decademoon@outlook.com>
Thu, 17 Oct 2024 03:25:42 +0000 (14:25 +1100)
committerGitHub <noreply@github.com>
Thu, 17 Oct 2024 03:25:42 +0000 (12:25 +0900)
Co-authored-by: Eduardo San Martin Morote <posva13@gmail.com>
packages/router/__tests__/RouterLink.spec.ts
packages/router/src/RouterLink.ts

index bf87c2de7261853edbd6bcd18264fba9bf167302..ccca9fdb1156076b6d2949106d2f075e68baf4c0 100644 (file)
@@ -358,7 +358,8 @@ async function factory(
   currentLocation: RouteLocationNormalized,
   propsData: any,
   resolvedLocation: RouteLocationResolved,
-  slotTemplate: string = ''
+  slotTemplate: string = '',
+  component: any = RouterLink
 ) {
   const route = createMockedRoute(currentLocation)
   const router = {
@@ -373,7 +374,7 @@ async function factory(
   }
   router.resolve.mockReturnValueOnce(resolvedLocation)
 
-  const wrapper = mount(RouterLink as any, {
+  const wrapper = mount(component, {
     propsData,
     global: {
       provide: {
@@ -899,6 +900,32 @@ describe('RouterLink', () => {
       expect(wrapper.html()).not.toContain('</a>')
     })
 
+    // #2375
+    it('works with custom directive when custom=true', async () => {
+      const Directive = (el: HTMLElement) => el.setAttribute('data-test', 'x')
+      const AppLink = defineComponent({
+        template: `
+<router-link custom v-directive>
+  <a></a>
+</router-link>
+        `,
+        components: { RouterLink },
+        directives: { Directive },
+        name: 'AppLink',
+      })
+
+      const { wrapper } = await factory(
+        locations.basic.normalized,
+        { to: locations.basic.string },
+        locations.basic.normalized,
+        undefined,
+        AppLink
+      )
+
+      expect(wrapper.element.tagName).toBe('A')
+      expect(wrapper.attributes('data-test')).toBe('x')
+    })
+
     describe('Extending RouterLink', () => {
       const AppLink = defineComponent({
         template: `
@@ -932,59 +959,31 @@ describe('RouterLink', () => {
         },
       })
 
-      async function factoryCustom(
-        currentLocation: RouteLocationNormalized,
-        propsData: any,
-        resolvedLocation: RouteLocationResolved,
-        slotTemplate: string = ''
-      ) {
-        const route = createMockedRoute(currentLocation)
-        const router = {
-          history: createMemoryHistory(),
-          createHref(to: RouteLocationNormalized): string {
-            return this.history.base + to.fullPath
-          },
-          options: {} as Partial<RouterOptions>,
-          resolve: vi.fn(),
-          push: vi.fn().mockResolvedValue(resolvedLocation),
-        }
-        router.resolve.mockReturnValueOnce(resolvedLocation)
-
-        const wrapper = await mount(AppLink as any, {
-          propsData,
-          global: {
-            provide: {
-              [routerKey as any]: router,
-              ...route.provides,
-            },
-          },
-          slots: { default: slotTemplate },
-        })
-
-        return { router, wrapper, route }
-      }
-
       it('can extend RouterLink with inactive class', async () => {
-        const { wrapper } = await factoryCustom(
+        const { wrapper } = await factory(
           locations.basic.normalized,
           {
             to: locations.basic.string,
             inactiveClass: 'inactive',
             activeClass: 'active',
           },
-          locations.foo.normalized
+          locations.foo.normalized,
+          undefined,
+          AppLink
         )
 
         expect(wrapper.find('a')!.classes()).toEqual(['inactive'])
       })
 
       it('can extend RouterLink with external link', async () => {
-        const { wrapper } = await factoryCustom(
+        const { wrapper } = await factory(
           locations.basic.normalized,
           {
             to: 'https://esm.dev',
           },
-          locations.foo.normalized
+          locations.foo.normalized,
+          undefined,
+          AppLink
         )
 
         expect(wrapper.find('a')!.classes()).toHaveLength(0)
index 731dfbf7502d57977a8af88f85b34fb7f2943513..e9c0141967f77fd4bf08a34466c170370a1ada74 100644 (file)
@@ -263,6 +263,10 @@ export function useLink<Name extends keyof RouteMap = keyof RouteMap>(
   }
 }
 
+function preferSingleVNode(vnodes: VNode[]) {
+  return vnodes.length === 1 ? vnodes[0] : vnodes
+}
+
 export const RouterLinkImpl = /*#__PURE__*/ defineComponent({
   name: 'RouterLink',
   compatConfig: { MODE: 3 },
@@ -307,7 +311,7 @@ export const RouterLinkImpl = /*#__PURE__*/ defineComponent({
     }))
 
     return () => {
-      const children = slots.default && slots.default(link)
+      const children = slots.default && preferSingleVNode(slots.default(link))
       return props.custom
         ? children
         : h(