diff --git a/examples/app-vitest-full/tests/nuxt/auto-import.spec.ts b/examples/app-vitest-full/tests/nuxt/auto-import.spec.ts
index d916aa368..4ddccdefe 100644
--- a/examples/app-vitest-full/tests/nuxt/auto-import.spec.ts
+++ b/examples/app-vitest-full/tests/nuxt/auto-import.spec.ts
@@ -1,6 +1,20 @@
-import { expect, it } from 'vitest'
+import { describe, expect, it } from 'vitest'
-it('should not mock', () => {
- expect(useAutoImportedTarget()).toMatchInlineSnapshot('"the original"')
- expect(useAutoImportedNonTarget()).toMatchInlineSnapshot('"the original"')
+describe('auto-imports', () => {
+ it('can use core nuxt composables within test file', () => {
+ expect(useAppConfig().hey).toMatchInlineSnapshot('false')
+ })
+
+ it('can access auto-imported composables from within project', () => {
+ const state = useSingleState()
+ expect(state.value).toMatchInlineSnapshot('{}')
+ state.value.field = 'new value'
+ expect(state.value.field).toMatchInlineSnapshot('"new value"')
+ expect(useSingleState().value.field).toMatchInlineSnapshot('"new value"')
+ })
+
+ it('should not mock imports that are mocked in another test file', () => {
+ expect(useAutoImportedTarget()).toMatchInlineSnapshot('"the original"')
+ expect(useAutoImportedNonTarget()).toMatchInlineSnapshot('"the original"')
+ })
})
diff --git a/examples/app-vitest-full/tests/nuxt/export-define-component.spec.ts b/examples/app-vitest-full/tests/nuxt/export-define-component.spec.ts
deleted file mode 100644
index fd9825df1..000000000
--- a/examples/app-vitest-full/tests/nuxt/export-define-component.spec.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { expect, it } from 'vitest'
-import { mountSuspended } from '@nuxt/test-utils/runtime-utils'
-import ExportDefaultComponent from '~/components/ExportDefaultComponent.vue'
-import ExportDefineComponent from '~/components/ExportDefineComponent.vue'
-import ExportDefaultWithRenderComponent from '~/components/ExportDefaultWithRenderComponent.vue'
-import ExportDefaultReturnsRenderComponent from '~/components/ExportDefaultReturnsRenderComponent.vue'
-
-it('should support export default defineComponent', async () => {
- const component = await mountSuspended(ExportDefineComponent, {
- props: {
- myProp: 'Hello nuxt-vitest',
- },
- })
- expect(component.html()).toMatchInlineSnapshot(`
- "
-
ExportDefineComponent
Hello nuxt-vitest
XHello nuxt-vitest
-
"
- `)
-})
-
-it('should support export default without setup script', async () => {
- const component = await mountSuspended(ExportDefaultComponent, {
- props: {
- myProp: 'Hello nuxt-vitest',
- },
- })
- expect(component.html()).toMatchInlineSnapshot(`
- "
-
ExportDefaultComponent
Hello nuxt-vitest
XHello nuxt-vitest
-
"
- `)
-})
-
-it('should support export default with render function', async () => {
- const component = await mountSuspended(ExportDefaultWithRenderComponent, {
- props: {
- myProp: 'Hello nuxt-vitest',
- },
- })
- expect(component.html()).toMatchInlineSnapshot(`
- "
-
ExportDefaultWithRenderComponent
Hello nuxt-vitest
XHello nuxt-vitest
-
"
- `)
-})
-
-it('should support export default that returns render function', async () => {
- const component = await mountSuspended(ExportDefaultReturnsRenderComponent, {
- props: {
- myProp: 'Hello nuxt-vitest',
- },
- })
- expect(component.html()).toMatchInlineSnapshot(`
- "
-
ExportDefaultReturnsRenderComponent
Hello nuxt-vitest
XHello nuxt-vitest
-
"
- `)
-})
diff --git a/examples/app-vitest-full/tests/nuxt/index.spec.ts b/examples/app-vitest-full/tests/nuxt/mount-suspended.spec.ts
similarity index 50%
rename from examples/app-vitest-full/tests/nuxt/index.spec.ts
rename to examples/app-vitest-full/tests/nuxt/mount-suspended.spec.ts
index fc50ad847..20c630f37 100644
--- a/examples/app-vitest-full/tests/nuxt/index.spec.ts
+++ b/examples/app-vitest-full/tests/nuxt/mount-suspended.spec.ts
@@ -1,53 +1,26 @@
import { describe, expect, it } from 'vitest'
-import { mountSuspended, registerEndpoint } from '@nuxt/test-utils/runtime-utils'
-
-import { listen } from 'listhen'
-import { createApp, eventHandler, toNodeListener } from 'h3'
+import { mountSuspended } from '@nuxt/test-utils/runtime-utils'
import App from '~/app.vue'
-import FetchComponent from '~/components/FetchComponent.vue'
import OptionsComponent from '~/components/OptionsComponent.vue'
import WrapperTests from '~/components/WrapperTests.vue'
import { mount } from '@vue/test-utils'
-describe('client-side nuxt features', () => {
- it('can use core nuxt composables within test file', () => {
- expect(useAppConfig().hey).toMatchInlineSnapshot('false')
- })
+import ExportDefaultComponent from '~/components/ExportDefaultComponent.vue'
+import ExportDefineComponent from '~/components/ExportDefineComponent.vue'
+import ExportDefaultWithRenderComponent from '~/components/ExportDefaultWithRenderComponent.vue'
+import ExportDefaultReturnsRenderComponent from '~/components/ExportDefaultReturnsRenderComponent.vue'
- it('can access auto-imported composables from within project', () => {
- const state = useSingleState()
- expect(state.value).toMatchInlineSnapshot('{}')
- state.value.field = 'new value'
- expect(state.value.field).toMatchInlineSnapshot('"new value"')
- expect(useSingleState().value.field).toMatchInlineSnapshot('"new value"')
- })
-
- it('can access injections from nuxt plugins', () => {
- const app = useNuxtApp()
- expect(app.$auth.didInject).toMatchInlineSnapshot('true')
- expect(app.$router).toBeDefined()
- })
+const formats = {
+ ExportDefaultComponent,
+ ExportDefineComponent,
+ ExportDefaultWithRenderComponent,
+ ExportDefaultReturnsRenderComponent,
+}
- it('defaults to index page', async () => {
- expect(useRoute().matched[0].meta).toMatchInlineSnapshot(`
- {
- "value": "set in index",
- }
- `)
- })
-
- it('allows pushing to other pages', async () => {
- await navigateTo('/something')
- expect(useNuxtApp().$router.currentRoute.value.path).toEqual('/something')
- await nextTick()
- expect(useRoute().path).toEqual('/something')
- })
-})
-
-describe('test utils', () => {
+describe('mountSuspended', () => {
it('can mount components within nuxt suspense', async () => {
const component = await mountSuspended(App)
expect(component.html()).toMatchInlineSnapshot(`
@@ -114,19 +87,6 @@ describe('test utils', () => {
`)
})
- it('can use $fetch', async () => {
- const app = createApp().use(
- '/todos/1',
- eventHandler(() => ({ id: 1 }))
- )
- const server = await listen(toNodeListener(app))
- const [{ url }] = await server.getURLs()
- expect(await $fetch('/todos/1', { baseURL: url })).toMatchObject({
- id: 1,
- })
- await server.close()
- })
-
// This test works (you can delete it later)
it('can receive emitted events from components using defineModel', () => {
const component = mount(WrapperTests)
@@ -147,51 +107,19 @@ describe('test utils', () => {
expect(component.vm.testExpose?.()).toBe('thing')
expect(component.vm.someRef).toBe('thing')
})
+})
- it('can mock fetch requests', async () => {
- registerEndpoint('https://jsonplaceholder.typicode.com/todos/1', () => ({
- title: 'title from mocked api',
- }))
- const component = await mountSuspended(FetchComponent)
- expect(component.html()).toMatchInlineSnapshot(
- '"title from mocked api
"'
- )
- })
-
- it('can mock fetch requests', async () => {
- registerEndpoint('/with-query', () => ({
- title: 'mocked',
- }))
- expect(
- await $fetch('/with-query', { query: { test: true } })
- ).toMatchObject({
- title: 'mocked',
- })
- })
-
- it('can mock fetch requests with explicit methods', async () => {
- registerEndpoint('/method', {
- method: 'POST',
- handler: () => ({ method: 'POST' }),
- })
- registerEndpoint('/method', {
- method: 'GET',
- handler: () => ({ method: 'GET' }),
- })
- expect(await $fetch('/method', { method: 'POST' })).toMatchObject({
- method: 'POST',
+describe.each(Object.entries(formats))(`%s`, (name, component) => {
+ it('mounts with props', async () => {
+ const wrapper = await mountSuspended(component, {
+ props: {
+ myProp: 'Hello nuxt-vitest',
+ },
})
- expect(await $fetch('/method')).toMatchObject({ method: 'GET' })
- })
-
- // TODO: reenable when merging Nuxt 3.7
- it.skip('handles nuxt routing', async () => {
- const component = await mountSuspended(App, { route: '/test' })
- expect(component.html()).toMatchInlineSnapshot(`
- "This is an auto-imported component
- I am a global component
- /test
- Test link "
- `)
+ expect(wrapper.html()).toEqual(`
+
+
${name}
Hello nuxt-vitest
XHello nuxt-vitest
+
+ `.trim())
})
})
diff --git a/examples/app-vitest-full/tests/nuxt/plugins.spec.ts b/examples/app-vitest-full/tests/nuxt/plugins.spec.ts
new file mode 100644
index 000000000..4439fd485
--- /dev/null
+++ b/examples/app-vitest-full/tests/nuxt/plugins.spec.ts
@@ -0,0 +1,9 @@
+import { describe, expect, it } from 'vitest'
+
+describe('plugins', () => {
+ it('can access injections', () => {
+ const app = useNuxtApp()
+ expect(app.$auth.didInject).toMatchInlineSnapshot('true')
+ expect(app.$router).toBeDefined()
+ })
+})
diff --git a/examples/app-vitest-full/tests/nuxt/render-suspended.spec.ts b/examples/app-vitest-full/tests/nuxt/render-suspended.spec.ts
new file mode 100644
index 000000000..0bae98d42
--- /dev/null
+++ b/examples/app-vitest-full/tests/nuxt/render-suspended.spec.ts
@@ -0,0 +1,94 @@
+import { afterEach, describe, expect, it } from 'vitest'
+import { renderSuspended } from '@nuxt/test-utils/runtime-utils'
+import { cleanup, fireEvent, screen } from '@testing-library/vue'
+
+import App from '~/app.vue'
+import OptionsComponent from '~/components/OptionsComponent.vue'
+import WrapperTests from '~/components/WrapperTests.vue'
+
+describe('renderSuspended', () => {
+ afterEach(() => {
+ // since we're not running with Vitest globals when running the tests
+ // from inside the test server. This means testing-library cannot
+ // auto-attach the cleanup go testing globals, and we have to do
+ // it here manually.
+ if (process.env.NUXT_VITEST_DEV_TEST) {
+ cleanup()
+ }
+ })
+
+ it('can render components within nuxt suspense', async () => {
+ const { html } = await renderSuspended(App)
+ expect(html()).toMatchInlineSnapshot(`
+ "
+
This is an auto-imported component
+
I am a global component
+
Index page
Test link
+
"
+ `)
+ })
+
+ it('should render default props within nuxt suspense', async () => {
+ await renderSuspended(OptionsComponent)
+ expect(screen.getByRole('heading', { level: 2 })).toMatchInlineSnapshot(
+ `
+
+ The original
+
+ `
+ )
+ })
+
+ it('should render passed props within nuxt suspense', async () => {
+ await renderSuspended(OptionsComponent, {
+ props: {
+ title: 'title from mount suspense props',
+ },
+ })
+ expect(screen.getByRole('heading', { level: 2 })).toMatchInlineSnapshot(
+ `
+
+ title from mount suspense props
+
+ `
+ )
+ })
+
+ it('can pass slots to rendered components within nuxt suspense', async () => {
+ const text = 'slot from mount suspense'
+ await renderSuspended(OptionsComponent, {
+ slots: {
+ default: () => text,
+ },
+ })
+ expect(screen.getByText(text)).toBeDefined()
+ })
+
+ it('can receive emitted events from components rendered within nuxt suspense', async () => {
+ const { emitted } = await renderSuspended(WrapperTests)
+ const button = screen.getByRole('button', { name: 'Click me!' })
+ await fireEvent.click(button)
+
+ const emittedEvents = emitted()
+ expect(emittedEvents.click).toMatchObject(
+ expect.arrayContaining([
+ expect.arrayContaining([expect.objectContaining({ type: 'click' })]),
+ ])
+ )
+
+ // since this is a native event it doesn't serialize well
+ delete emittedEvents.click
+ expect(emittedEvents).toMatchInlineSnapshot(`
+ {
+ "customEvent": [
+ [
+ "foo",
+ ],
+ ],
+ "otherEvent": [
+ [],
+ ],
+ }
+ `)
+ })
+})
diff --git a/examples/app-vitest-full/tests/nuxt/routing.spec.ts b/examples/app-vitest-full/tests/nuxt/routing.spec.ts
new file mode 100644
index 000000000..01be68ab7
--- /dev/null
+++ b/examples/app-vitest-full/tests/nuxt/routing.spec.ts
@@ -0,0 +1,32 @@
+import { describe, expect, it } from 'vitest'
+
+import { mountSuspended } from '@nuxt/test-utils/runtime-utils'
+
+import App from '~/app.vue'
+
+describe('routing', () => {
+ it('defaults to index page', async () => {
+ expect(useRoute().matched[0].meta).toMatchInlineSnapshot(`
+ {
+ "value": "set in index",
+ }
+ `)
+ })
+
+ it('allows pushing to other pages', async () => {
+ await navigateTo('/something')
+ expect(useNuxtApp().$router.currentRoute.value.path).toEqual('/something')
+ await nextTick()
+ expect(useRoute().path).toEqual('/something')
+ })
+
+ it('handles nuxt routing', async () => {
+ const component = await mountSuspended(App, { route: '/test' })
+ expect(component.html()).toMatchInlineSnapshot(`
+ "This is an auto-imported component
+ I am a global component
+ /test
+ Test link "
+ `)
+ })
+})
diff --git a/examples/app-vitest-full/tests/nuxt/server.spec.ts b/examples/app-vitest-full/tests/nuxt/server.spec.ts
new file mode 100644
index 000000000..e28f95e72
--- /dev/null
+++ b/examples/app-vitest-full/tests/nuxt/server.spec.ts
@@ -0,0 +1,59 @@
+import { describe, expect, it } from 'vitest'
+
+import { mountSuspended, registerEndpoint } from '@nuxt/test-utils/runtime-utils'
+
+import { listen } from 'listhen'
+import { createApp, eventHandler, toNodeListener } from 'h3'
+
+import FetchComponent from '~/components/FetchComponent.vue'
+
+describe('server mocks and data fetching', () => {
+ it('can use $fetch', async () => {
+ const app = createApp().use(
+ '/todos/1',
+ eventHandler(() => ({ id: 1 }))
+ )
+ const server = await listen(toNodeListener(app))
+ const [{ url }] = await server.getURLs()
+ expect(await $fetch('/todos/1', { baseURL: url })).toMatchObject({
+ id: 1,
+ })
+ await server.close()
+ })
+
+ it('can mock fetch requests', async () => {
+ registerEndpoint('https://jsonplaceholder.typicode.com/todos/1', () => ({
+ title: 'title from mocked api',
+ }))
+ const component = await mountSuspended(FetchComponent)
+ expect(component.html()).toMatchInlineSnapshot(
+ '"title from mocked api
"'
+ )
+ })
+
+ it('can mock fetch requests', async () => {
+ registerEndpoint('/with-query', () => ({
+ title: 'mocked',
+ }))
+ expect(
+ await $fetch('/with-query', { query: { test: true } })
+ ).toMatchObject({
+ title: 'mocked',
+ })
+ })
+
+ it('can mock fetch requests with explicit methods', async () => {
+ registerEndpoint('/method', {
+ method: 'POST',
+ handler: () => ({ method: 'POST' }),
+ })
+ registerEndpoint('/method', {
+ method: 'GET',
+ handler: () => ({ method: 'GET' }),
+ })
+ expect(await $fetch('/method', { method: 'POST' })).toMatchObject({
+ method: 'POST',
+ })
+ expect(await $fetch('/method')).toMatchObject({ method: 'GET' })
+ })
+})
diff --git a/examples/app-vitest-full/tests/nuxt/utils-render.spec.ts b/examples/app-vitest-full/tests/nuxt/utils-render.spec.ts
deleted file mode 100644
index a056c358f..000000000
--- a/examples/app-vitest-full/tests/nuxt/utils-render.spec.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import { afterEach, describe, expect, it } from 'vitest'
-import { renderSuspended } from '@nuxt/test-utils/runtime-utils'
-import { cleanup, fireEvent, screen } from '@testing-library/vue'
-
-import App from '~/app.vue'
-import OptionsComponent from '~/components/OptionsComponent.vue'
-import WrapperTests from '~/components/WrapperTests.vue'
-
-describe('test utils', () => {
- describe('renderSuspended', () => {
- afterEach(() => {
- // since we're not running with Vitest globals when running the tests
- // from inside the test server. This means testing-library cannot
- // auto-attach the cleanup go testing globals, and we have to do
- // it here manually.
- if (process.env.NUXT_VITEST_DEV_TEST) {
- cleanup()
- }
- })
-
- it('can render components within nuxt suspense', async () => {
- const { html } = await renderSuspended(App)
- expect(html()).toMatchInlineSnapshot(`
- "
-
This is an auto-imported component
-
I am a global component
-
Index page
Test link
-
"
- `)
- })
-
- it('should render default props within nuxt suspense', async () => {
- await renderSuspended(OptionsComponent)
- expect(screen.getByRole('heading', { level: 2 })).toMatchInlineSnapshot(
- `
-
- The original
-
- `
- )
- })
-
- it('should render passed props within nuxt suspense', async () => {
- await renderSuspended(OptionsComponent, {
- props: {
- title: 'title from mount suspense props',
- },
- })
- expect(screen.getByRole('heading', { level: 2 })).toMatchInlineSnapshot(
- `
-
- title from mount suspense props
-
- `
- )
- })
-
- it('can pass slots to rendered components within nuxt suspense', async () => {
- const text = 'slot from mount suspense'
- await renderSuspended(OptionsComponent, {
- slots: {
- default: () => text,
- },
- })
- expect(screen.getByText(text)).toBeDefined()
- })
-
- it('can receive emitted events from components rendered within nuxt suspense', async () => {
- const { emitted } = await renderSuspended(WrapperTests)
- const button = screen.getByRole('button', { name: 'Click me!' })
- await fireEvent.click(button)
-
- const emittedEvents = emitted()
- expect(emittedEvents.click).toMatchObject(
- expect.arrayContaining([
- expect.arrayContaining([expect.objectContaining({ type: 'click' })]),
- ])
- )
-
- // since this is a native event it doesn't serialize well
- delete emittedEvents.click
- expect(emittedEvents).toMatchInlineSnapshot(`
- {
- "customEvent": [
- [
- "foo",
- ],
- ],
- "otherEvent": [
- [],
- ],
- }
- `)
- })
- })
-})