N
Nuxt2w ago
Yuri

useNuxtApp && mountSuspended

My Component:
<template>
<div>{{test}}</div>
</template>

<script lang="ts" setup>
const test = ref('111')
const fetchCities = async () => {
test.value = '222';
const nuxtApp = useNuxtApp()
await nuxtApp.$api(apiPath.location.suggest.city)
test.value = '333';
}

onMounted(async () => {
await fetchCities()
})
</script>
<template>
<div>{{test}}</div>
</template>

<script lang="ts" setup>
const test = ref('111')
const fetchCities = async () => {
test.value = '222';
const nuxtApp = useNuxtApp()
await nuxtApp.$api(apiPath.location.suggest.city)
test.value = '333';
}

onMounted(async () => {
await fetchCities()
})
</script>
My test:
import { describe, it, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'
import {flushPromises} from "@vue/test-utils";

describe('LocationSelection.vue', () => {
const createWrapper = async () => {
return await mountSuspended(LocationSelection)
}

it('test',async ()=>{
const wrapper = await createWrapper();
await flushPromises();
await wrapper.vm.$nextTick();
console.log(wrapper.html());
})
})
import { describe, it, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'
import {flushPromises} from "@vue/test-utils";

describe('LocationSelection.vue', () => {
const createWrapper = async () => {
return await mountSuspended(LocationSelection)
}

it('test',async ()=>{
const wrapper = await createWrapper();
await flushPromises();
await wrapper.vm.$nextTick();
console.log(wrapper.html());
})
})
Why console.log render
<div>222</div>
<div>222</div>
Why not "333" ? How can I fix this error?
5 Replies
kapa.ai
kapa.ai2w ago
Hi @Yuri. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To answer your question, I'll need to analyze the provided code and explain why you're seeing "222" instead of "333" in the console log. Let's break it down: The issue you're experiencing is related to how mountSuspended works and how it interacts with the component's lifecycle hooks. Here's why you're seeing "222" instead of "333": 1. mountSuspended is designed to work with Nuxt's async setup, but it doesn't fully simulate the entire Nuxt application environment. 2. In your component, you're using useNuxtApp() inside the fetchCities function. However, useNuxtApp() requires the Nuxt context, which might not be fully available in the test environment. 3. When mountSuspended runs, it will execute the setup function of your component, including the onMounted hook. However, it might not properly handle the useNuxtApp() call inside fetchCities. To fix this issue and get the expected "333" result, you can try the following approaches: 1. Mock the useNuxtApp function:
import { describe, it, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'
import { flushPromises } from "@vue/test-utils";

describe('LocationSelection.vue', () => {
mockNuxtImport('useNuxtApp', () => {
return () => ({
$api: vi.fn().mockResolvedValue({}),
})
})

const createWrapper = async () => {
return await mountSuspended(LocationSelection)
}

it('test', async () => {
const wrapper = await createWrapper();
await flushPromises();
await wrapper.vm.$nextTick();
console.log(wrapper.html());
})
})
import { describe, it, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'
import { flushPromises } from "@vue/test-utils";

describe('LocationSelection.vue', () => {
mockNuxtImport('useNuxtApp', () => {
return () => ({
$api: vi.fn().mockResolvedValue({}),
})
})

const createWrapper = async () => {
return await mountSuspended(LocationSelection)
}

it('test', async () => {
const wrapper = await createWrapper();
await flushPromises();
await wrapper.vm.$nextTick();
console.log(wrapper.html());
})
})
2. If you need to test the actual API call, you can use vi.mock to mock the entire useNuxtApp:
import { describe, it, vi } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'
import { flushPromises } from "@vue/test-utils";

vi.mock('#app', () => ({
useNuxtApp: () => ({
$api: vi.fn().mockResolvedValue({}),
}),
}))

describe('LocationSelection.vue', () => {
const createWrapper = async () => {
return await mountSuspended(LocationSelection)
}

it('test', async () => {
const wrapper = await createWrapper();
await flushPromises();
await wrapper.vm.$nextTick();
console.log(wrapper.html());
})
})
import { describe, it, vi } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'
import { flushPromises } from "@vue/test-utils";

vi.mock('#app', () => ({
useNuxtApp: () => ({
$api: vi.fn().mockResolvedValue({}),
}),
}))

describe('LocationSelection.vue', () => {
const createWrapper = async () => {
return await mountSuspended(LocationSelection)
}

it('test', async () => {
const wrapper = await createWrapper();
await flushPromises();
await wrapper.vm.$nextTick();
console.log(wrapper.html());
})
})
These approaches should allow the fetchCities function to complete, including the API call (mocked), and set the test value to "333". Remember that when testing Nuxt components, especially those that rely on Nuxt-specific features like useNuxtApp, you often need to provide mocks or stubs for these functions to ensure they work correctly in the test environment. For more information on testing in Nuxt and using mountSuspended, you can refer to the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing#mountsuspended). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Yuri
YuriOP2w ago
@kapa.ai with first solution I get errors: [Vue warn]: Component is missing template or render function: { name: 'MountSuspendedHelper', setup: [AsyncFunction: setup] } at <MountSuspendedHelper> at <Anonymous ref="VTU_COMPONENT" > at <VTUROOT> ❯ components/Location/tests/LocationSelection.nuxt.spec.ts (1) ❯ LocationSelection.vue (1) × test ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ FAIL components/Location/tests/LocationSelection.nuxt.spec.ts > LocationSelection.vue > test TypeError: nuxtApp.deferHydration is not a function ❯ Object.setup node_modules/nuxt/dist/app/components/nuxt-root.vue:32:27 30| 31| const IslandRenderer = import.meta.server && componentIslands 32| ? defineAsyncComponent(() => import('./island-renderer').then(r => r.default || r)) | ^ 33| : () => null 34| ❯ setup node_modules/@nuxt/test-utils/dist/runtime-utils/index.mjs:107:50 ❯ callWithErrorHandling node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:200:19 ❯ setupStatefulComponent node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7788:25 ❯ setupComponent node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7749:36 ❯ mountComponent node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5104:7 ❯ processComponent node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5070:9 ❯ patch node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4599:11 ❯ ReactiveEffect.componentUpdateFn [as fn] node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5214:11 ❯ ReactiveEffect.run node_modules/@vue/runtime-core/node_modules/@vue/reactivity/dist/reactivity.cjs.js:226:19
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I apologize for the confusion in my previous answer. The error you're encountering is related to the Nuxt testing environment not being fully set up. Let's try a different approach to resolve this issue. The error suggests that the Nuxt app context is not properly initialized in the test environment. To fix this, we need to ensure that we're using the Nuxt testing environment correctly. Here's a revised approach: 1. First, make sure you have set up your vitest.config.ts file correctly:
import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
test: {
environment: 'nuxt'
}
})
import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
test: {
environment: 'nuxt'
}
})
2. Next, update your test file as follows:
import { describe, it, expect } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

describe('LocationSelection.vue', () => {
it('test', async () => {
const wrapper = await mountSuspended(LocationSelection)

// Wait for any pending updates
await wrapper.vm.$nextTick()

// Log the HTML content
console.log(wrapper.html())

// Add your assertions here
expect(wrapper.text()).toContain('333')
})
})
import { describe, it, expect } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

describe('LocationSelection.vue', () => {
it('test', async () => {
const wrapper = await mountSuspended(LocationSelection)

// Wait for any pending updates
await wrapper.vm.$nextTick()

// Log the HTML content
console.log(wrapper.html())

// Add your assertions here
expect(wrapper.text()).toContain('333')
})
})
3. If you still need to mock the useNuxtApp and $api calls, you can use the mockNuxtImport helper:
import { describe, it, expect, vi } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

describe('LocationSelection.vue', () => {
mockNuxtImport('useNuxtApp', () => {
return () => ({
$api: vi.fn().mockResolvedValue({})
})
})
it('test', async () => {
const wrapper = await mountSuspended(LocationSelection)

// Wait for any pending updates
await wrapper.vm.$nextTick()

// Log the HTML content
console.log(wrapper.html())

// Add your assertions here
expect(wrapper.text()).toContain('333')
})
})
import { describe, it, expect, vi } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

describe('LocationSelection.vue', () => {
mockNuxtImport('useNuxtApp', () => {
return () => ({
$api: vi.fn().mockResolvedValue({})
})
})
it('test', async () => {
const wrapper = await mountSuspended(LocationSelection)

// Wait for any pending updates
await wrapper.vm.$nextTick()

// Log the HTML content
console.log(wrapper.html())

// Add your assertions here
expect(wrapper.text()).toContain('333')
})
})
This approach should resolve the issues you were facing. The key points are: 1. Using the Nuxt testing environment by setting it in the vitest.config.ts file. 2. Using mountSuspended from @nuxt/test-utils/runtime to properly mount your Nuxt component. 3. Mocking the useNuxtApp function if needed, using mockNuxtImport. If you're still encountering issues, it might be helpful to check your Nuxt and @nuxt/test-utils versions to ensure they are compatible and up-to-date. For more detailed information on testing Nuxt applications, you can refer to the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Want results from more Discord servers?
Add your server