Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/app-vitest-workspace/app2/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: ['@nuxtjs/color-mode', '@nuxt/ui'],
pages: false,
devtools: { enabled: true },
compatibilityDate: '2024-04-03',
})
39 changes: 39 additions & 0 deletions examples/app-vitest-workspace/app2/test/nuxt/components.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { describe, expect, it } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'

import Badge from '@nuxt/ui/components/Badge.vue'
import Breadcrumb from '@nuxt/ui/components/Breadcrumb.vue'
import Header from '@nuxt/ui/components/Header.vue'

describe('components', () => {
it('ui/Badge', async () => {
Expand All @@ -12,4 +14,41 @@ describe('components', () => {
})
expect(wrapper.text()).toBe('Hello')
})

it('ui/Header', async () => {
const wrapper = await mountSuspended(Header, {
props: {
title: 'App',
to: '/',
},
})
expect(wrapper.text()).toBe('App')
expect(wrapper.find('a')?.attributes('href')).toBe('/')
})

it('ui/Breadcrumb', async () => {
const component = await mountSuspended(Breadcrumb, {
props: {
items: [
{
label: 'Home',
to: '/',
},
{
label: 'Help',
to: '/help',
},
],
},
})

const links = component.findAll('a')
expect(links).toHaveLength(2)

expect(links[0]?.text()).toBe('Home')
expect(links[0]?.attributes('href')).toBe('/')

expect(links[1]?.text()).toBe('Help')
expect(links[1]?.attributes('href')).toBe('/help')
})
})
3 changes: 3 additions & 0 deletions examples/app-vitest-workspace/app4/app/pages/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
Index
</template>
8 changes: 8 additions & 0 deletions examples/app-vitest-workspace/app4/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
imports: {
autoImport: false,
},
devtools: { enabled: true },
compatibilityDate: '2024-04-03',
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { afterEach, describe, expect, it } from 'vitest'
import { enableAutoUnmount } from '@vue/test-utils'
import { mountSuspended } from '@nuxt/test-utils/runtime'

import { NuxtLink } from '#components'

type DefaultSlotProp = { isActive: boolean, isExactActive: boolean }

describe('NuxtLink without pages', () => {
enableAutoUnmount(afterEach)

it('should mount', async () => {
const wrapper = await mountSuspended(NuxtLink, {
props: {
to: '/',
},
slots: {
default: () => 'Home',
},
})

const a = wrapper.find('a')
expect(a.exists()).toBe(true)
expect(a.attributes('href')).toBe('/')
expect(a.text()).toBe('Home')
})

it('should mount custom', async () => {
const wrapper = await mountSuspended(NuxtLink, {
props: {
to: '/',
custom: true,
},
slots: {
default: ({ isActive, isExactActive }: DefaultSlotProp) =>
`Home:${isActive}:${isExactActive}`,
},
})

expect(wrapper.text()).toBe('Home:undefined:undefined')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { afterEach, describe, expect, it } from 'vitest'
import { enableAutoUnmount } from '@vue/test-utils'
import { mountSuspended } from '@nuxt/test-utils/runtime'

import { NuxtLink } from '#components'

type DefaultSlotProp = { isActive: boolean, isExactActive: boolean }

describe('NuxtLink with pages', () => {
enableAutoUnmount(afterEach)

it('should mount', async () => {
const wrapper = await mountSuspended(NuxtLink, {
props: {
to: '/',
},
slots: {
default: () => 'Home',
},
})

const a = wrapper.find('a')
expect(a.exists()).toBe(true)
expect(a.attributes('href')).toBe('/')
expect(a.text()).toBe('Home')
})

it('should mount custom', async () => {
const wrapper = await mountSuspended(NuxtLink, {
props: {
to: '/',
custom: true,
},
slots: {
default: ({ isActive, isExactActive }: DefaultSlotProp) =>
`Home:${isActive}:${isExactActive}`,
},
})

expect(wrapper.text()).toBe('Home:true:true')
})
})
17 changes: 17 additions & 0 deletions examples/app-vitest-workspace/app4/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"files": [],
"references": [
{
"path": "./.nuxt/tsconfig.app.json"
},
{
"path": "./.nuxt/tsconfig.server.json"
},
{
"path": "./.nuxt/tsconfig.shared.json"
},
{
"path": "./.nuxt/tsconfig.node.json"
}
]
}
17 changes: 17 additions & 0 deletions examples/app-vitest-workspace/app4/vitest.pages-off.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { fileURLToPath } from 'node:url'
import { defineVitestProject } from '@nuxt/test-utils/config'

export default defineVitestProject({
test: {
name: 'nuxt-app4:pages-off',
include: ['test/nuxt/pages-off/*.spec.ts'],
environmentOptions: {
nuxt: {
rootDir: fileURLToPath(new URL('.', import.meta.url)),
overrides: {
pages: false,
},
},
},
},
})
17 changes: 17 additions & 0 deletions examples/app-vitest-workspace/app4/vitest.pages-on.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { fileURLToPath } from 'node:url'
import { defineVitestProject } from '@nuxt/test-utils/config'

export default defineVitestProject({
test: {
name: 'nuxt-app4:pages-on',
include: ['test/nuxt/pages-on/*.spec.ts'],
environmentOptions: {
nuxt: {
rootDir: fileURLToPath(new URL('.', import.meta.url)),
overrides: {
pages: true,
},
},
},
},
})
6 changes: 5 additions & 1 deletion examples/app-vitest-workspace/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"dev:prepare": "nuxt prepare app1 && nuxt prepare app2 && nuxt prepare app3",
"dev:prepare": "pnpm run '/dev:prepare:.*/'",
"dev:prepare:app1": "nuxt prepare app1",
"dev:prepare:app2": "nuxt prepare app2",
"dev:prepare:app3": "nuxt prepare app3",
"dev:prepare:app4": "nuxt prepare app4",
"postinstall": "pnpm dev:prepare",
"test": "vitest run"
},
Expand Down
36 changes: 34 additions & 2 deletions src/runtime-utils/components/RouterLink.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { defineComponent, h } from '#imports'
import { useLink } from 'vue-router'
import { defineComponent, h, useRouter, useNuxtApp } from '#imports'
import type { useLink as useLinkFn } from 'vue-router'

function getUseLink(nuxtApp: ReturnType<typeof useNuxtApp>) {
const linkComponent = nuxtApp.vueApp._context.components.RouterLink
if (!linkComponent || typeof linkComponent !== 'object') return undefined
if (typeof linkComponent.useLink !== 'function') return undefined
return linkComponent.useLink.bind(linkComponent) as typeof useLinkFn
}

export const RouterLink = defineComponent({
functional: true,
Expand All @@ -16,6 +23,31 @@ export const RouterLink = defineComponent({
ariaCurrentValue: String,
},
setup: (props, { slots }) => {
const app = useNuxtApp()
const useLink = getUseLink(app)

if (!useLink) {
const navigate = () => {}
const router = useRouter()
return () => {
const route = router.resolve(props.to)

return props.custom
? slots.default?.({ href: route.href, navigate, route })
: h(
'a',
{
href: route.href,
onClick: (e: MouseEvent) => {
e.preventDefault()
return navigate()
},
},
slots,
)
}
}

const link = useLink(props)

return () => {
Expand Down
Loading