alpha
Login
or
Join now
danielroe.dev
/
nuxt-vitest
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
[READ-ONLY] Mirror of https://github.com/danielroe/nuxt-vitest. An vitest environment with support for testing code that needs a Nuxt runtime environment
nuxt
nuxt-module
testing
unit-testing
vitest
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
feat: mock `<RouterLink>`
author
Daniel Roe
date
3 years ago
(Dec 9, 2022, 10:45 PM +0100)
commit
b1e61faf
b1e61fafbfded8e03c3b4e3cabe41860da1844cb
parent
b8240fb0
b8240fb05be32bbf970bb39dd7c831863e62ff7c
+59
-51
7 changed files
Expand all
Collapse all
Unified
Split
playground
app.vue
pages
index.vue
tests
index.spec.ts
src
index.ts
runtime
components
RouterLink.ts
mount.ts
vitest-environment-nuxt
index.ts
+1
-1
playground/app.vue
View file
Reviewed
···
1
1
<template>
2
2
<LazySomeComponent />
3
3
<!-- TODO: <NuxtPage /> -->
4
4
-
<!-- TODO: <NuxtLink to="/test">Test link</NuxtLink> -->
4
4
+
<NuxtLink to="/test">Test link</NuxtLink>
5
5
</template>
6
6
7
7
<script setup>
+6
playground/pages/index.vue
View file
Reviewed
···
1
1
<template>
2
2
<div>Index page</div>
3
3
</template>
4
4
+
5
5
+
<script setup>
6
6
+
definePageMeta({
7
7
+
value: 'set in index',
8
8
+
})
9
9
+
</script>
+8
-6
playground/tests/index.spec.ts
View file
Reviewed
···
25
25
expect(app.$router).toBeDefined()
26
26
})
27
27
28
28
-
it('works with route composables', async () => {
29
29
-
expect(useRoute().matched[0].meta).toMatchInlineSnapshot('{}')
28
28
+
it('defaults to index page', async () => {
29
29
+
expect(useRoute().matched[0].meta).toMatchInlineSnapshot(`
30
30
+
{
31
31
+
"value": "set in index",
32
32
+
}
33
33
+
`)
30
34
expect(useRoute().fullPath).toMatchInlineSnapshot('"/"')
31
31
-
// TODO:
32
32
-
// await useRouter().push('/test')
33
33
-
// expect(useRoute().fullPath).toMatchInlineSnapshot('"/test"')
35
35
+
// TODO: should it be possible to push to other routes?
34
36
})
35
37
})
36
38
···
40
42
expect(component.html()).toMatchInlineSnapshot(`
41
43
"<div>This is an auto-imported component</div>
42
44
<!-- TODO: <NuxtPage /> -->
43
43
-
<!-- TODO: <NuxtLink to=\\"/test\\">Test link</NuxtLink> -->"
45
45
+
<a href=\\"/test\\">Test link</a>"
44
46
`)
45
47
})
46
48
+6
-1
src/index.ts
View file
Reviewed
···
9
9
const nuxt = await loadNuxt({
10
10
cwd: rootDir,
11
11
dev: false,
12
12
-
overrides: { ssr: false },
12
12
+
overrides: {
13
13
+
ssr: false,
14
14
+
app: {
15
15
+
rootId: 'nuxt-test'
16
16
+
},
17
17
+
},
13
18
})
14
19
return new Promise<InlineConfig>((resolve, reject) => {
15
20
nuxt.hook('vite:extendConfig', config => {
+21
src/runtime/components/RouterLink.ts
View file
Reviewed
···
1
1
+
export const RouterLink = defineComponent({
2
2
+
functional: true,
3
3
+
props: {
4
4
+
to: String,
5
5
+
custom: Boolean,
6
6
+
replace: Boolean,
7
7
+
// Not implemented
8
8
+
activeClass: String,
9
9
+
exactActiveClass: String,
10
10
+
ariaCurrentValue: String
11
11
+
},
12
12
+
setup: (props, { slots }) => {
13
13
+
const navigate = () => {}
14
14
+
return () => {
15
15
+
const route = props.to ? useRouter().resolve(props.to) : {}
16
16
+
return props.custom
17
17
+
? slots.default?.({ href: props.to, navigate, route })
18
18
+
: h('a', { href: props.to, onClick: (e: MouseEvent) => { e.preventDefault(); return navigate() } }, slots)
19
19
+
}
20
20
+
}
21
21
+
})
+8
-33
src/runtime/mount.ts
View file
Reviewed
···
1
1
import { mount, VueWrapper } from '@vue/test-utils'
2
2
import { h, DefineComponent, Suspense } from 'vue'
3
3
4
4
+
import { RouterLink } from './components/RouterLink'
5
5
+
4
6
// @ts-expect-error virtual file
5
7
import NuxtRoot from '#build/root-component.mjs'
6
8
···
9
11
const vm = mount({
10
12
setup: NuxtRoot.setup,
11
13
render: () => h(Suspense, { onResolve: () => resolve(vm as any) }, { default: () => h(component) })
14
14
+
}, {
15
15
+
global: {
16
16
+
components: {
17
17
+
RouterLink
18
18
+
}
19
19
+
}
12
20
})
13
21
})
14
22
}
15
15
-
16
16
-
17
17
-
export async function mountSuspendedWithRoute<T extends DefineComponent<any, any, any, any>> (component: T) {
18
18
-
return new Promise<VueWrapper<InstanceType<T>>>(async resolve => {
19
19
-
// const vueApp = createApp({
20
20
-
// setup: NuxtRoot.setup,
21
21
-
// render: () => h(Suspense, { onResolve: () => resolve(vueApp as any) }, { default: () => h(component) })
22
22
-
// })
23
23
-
24
24
-
// const nuxt = createNuxtApp({ vueApp })
25
25
-
26
26
-
// try {
27
27
-
// await applyPlugins(nuxt, plugins)
28
28
-
// } catch (err) {
29
29
-
// await nuxt.callHook('app:error', err)
30
30
-
// nuxt.payload.error = (nuxt.payload.error || err) as any
31
31
-
// }
32
32
-
33
33
-
// try {
34
34
-
// await nuxt.hooks.callHook('app:created', vueApp)
35
35
-
// await nuxt.hooks.callHook('app:beforeMount', vueApp)
36
36
-
// const app = document.createElement('div')
37
37
-
// document.body.appendChild(app)
38
38
-
// app.id = 'something'
39
39
-
// vueApp.mount('#something')
40
40
-
// await nuxt.hooks.callHook('app:mounted', vueApp)
41
41
-
// await nextTick()
42
42
-
// } catch (err) {
43
43
-
// await nuxt.callHook('app:error', err)
44
44
-
// nuxt.payload.error = (nuxt.payload.error || err) as any
45
45
-
// }
46
46
-
})
47
47
-
}
+9
-10
src/vitest-environment-nuxt/index.ts
View file
Reviewed
···
1
1
import type { Environment } from 'vitest'
2
2
-
import { builtinEnvironments, populateGlobal } from 'vitest/environments'
3
2
import { Window, GlobalWindow } from 'happy-dom'
4
3
import { createFetch } from 'ohmyfetch'
5
5
-
import { App, createApp, defineEventHandler, toNodeListener } from 'h3'
4
4
+
import { App, createApp, toNodeListener } from 'h3'
6
5
import {
7
6
createCall,
8
7
createFetch as createLocalFetch,
9
8
} from 'unenv/runtime/fetch/index'
9
9
+
// @ts-expect-error TODO: add subpath types
10
10
+
import * as viteEnvironments from 'vitest/environments'
11
11
+
const { populateGlobal } = viteEnvironments as typeof import('vitest/dist/environments')
10
12
11
13
export default <Environment> {
12
14
name: 'nuxt',
···
14
16
const win = new (GlobalWindow || Window)() as any as (Window & {
15
17
__app: App
16
18
__registry: Set<string>
19
19
+
__NUXT__: any
17
20
$fetch: any
18
21
fetch: any
19
22
})
20
23
21
21
-
// @ts-expect-error undeclared property on window
22
24
win.__NUXT__ = {
23
25
serverRendered: false,
24
26
config: {
···
30
32
}
31
33
32
34
const app = win.document.createElement('div')
35
35
+
app.id = 'nuxt-test'
33
36
win.document.body.appendChild(app)
34
37
35
35
-
// Workaround for happy-dom bug
36
36
-
const { querySelector } = win.document
37
37
-
app.id = 'nuxt'
38
38
-
function qsWrapper (selectors) {
39
39
-
if (selectors === '#__nuxt') selectors = '#nuxt'
40
40
-
return querySelector(selectors)
38
38
+
// @ts-expect-error
39
39
+
win.IntersectionObserver = win.IntersectionObserver || class IntersectionObserver {
40
40
+
observe () {}
41
41
}
42
42
-
win.document.querySelector = qsWrapper
43
42
44
43
const h3App = createApp()
45
44