N
Nuxt2w ago
Yuri

The test ignores useNuxtApp

Hello, everyone! I need help with unit-testing. My component LocationSelection.vue:
<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 LocationSelection.nuxt.spec.ts:
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)
await wrapper.vm.$nextTick()
console.log(wrapper.html())
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)
await wrapper.vm.$nextTick()
console.log(wrapper.html())
expect(wrapper.text()).toContain('333')
})
})
But why do I receive 222 instead 333?
AssertionError: expected '222' to contain '333'
AssertionError: expected '222' to contain '333'
7 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: ---------------------- Based on the information provided in the knowledge sources, I can help explain why you're receiving '222' instead of '333' in your test. The issue is related to how useNuxtApp() is handled in the testing environment. Let me break it down for you: 1. Your component is using useNuxtApp() inside the fetchCities function, which is called in the onMounted hook. 2. In your test, you're using mountSuspended from @nuxt/test-utils/runtime. This helper is designed to mount components within the Nuxt environment, allowing access to Nuxt-specific features like plugins and injections Docs > Getting-started > Testing > Unit Testing > 🛠️ Helpers (https://nuxt.com/docs/getting-started/testing#%EF%B8%8F-helpers). 3. However, it seems that the useNuxtApp() call is not being properly mocked or handled in your test environment. This is causing the test to stop at test.value = '222' and not proceed to test.value = '333'. To resolve this issue, you have a few options: 1. Mock useNuxtApp: You can use mockNuxtImport to mock the useNuxtApp function. Here's how you can modify your test:
import { describe, it, expect } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

describe('LocationSelection.vue', () => {
it('test', async () => {
mockNuxtImport('useNuxtApp', () => {
return () => ({
$api: () => Promise.resolve() // Mock the $api method
})
})

const wrapper = await mountSuspended(LocationSelection)
await wrapper.vm.$nextTick()
console.log(wrapper.html())
expect(wrapper.text()).toContain('333')
})
})

import { describe, it, expect } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

describe('LocationSelection.vue', () => {
it('test', async () => {
mockNuxtImport('useNuxtApp', () => {
return () => ({
$api: () => Promise.resolve() // Mock the $api method
})
})

const wrapper = await mountSuspended(LocationSelection)
await wrapper.vm.$nextTick()
console.log(wrapper.html())
expect(wrapper.text()).toContain('333')
})
})

This approach is mentioned in the Docs > Getting-started > Testing > Unit Testing > 🛠️ Helpers (https://nuxt.com/docs/getting-started/testing#conflict-with-end-to-end-testing) section. 2. Use renderSuspended: Alternatively, you could use renderSuspended instead of mountSuspended. This helper is designed to work with @testing-library/vue and might handle the Nuxt environment differently:
import { describe, it, expect } from 'vitest'
import { renderSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'
import { screen } from '@testing-library/vue'

describe('LocationSelection.vue', () => {
it('test', async () => {
await renderSuspended(LocationSelection)
expect(screen.getByText('333')).toBeDefined()
})
})

import { describe, it, expect } from 'vitest'
import { renderSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'
import { screen } from '@testing-library/vue'

describe('LocationSelection.vue', () => {
it('test', async () => {
await renderSuspended(LocationSelection)
expect(screen.getByText('333')).toBeDefined()
})
})

This approach is described in the Docs > Getting-started > Testing > Unit Testing > 🛠️ Helpers (https://nuxt.com/docs/getting-started/testing#rendersuspended) section. Remember that when testing components that rely on Nuxt-specific features like useNuxtApp(), you need to ensure that the Nuxt environment is properly set up or mocked in your tests. The @nuxt/test-utils package provides tools to help with this, but you may need to configure them correctly based on your specific use case. ---------------------- 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 import {describe, it, expect, 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', () => { it('test', async () => { // Mock the $api method to return a resolved promise const mockApi = vi.fn().mockResolvedValue({ data: 'mocked data' }) const wrapper = await mountSuspended(LocationSelection, { globals: { provide: { nuxtApp: { $api: mockApi } } } }) await wrapper.vm.$nextTick() await flushPromises() console.log(wrapper.html()) expect(wrapper.text()).toContain('333') }) }) Not working import { describe, it, expect } from 'vitest' import {mockNuxtImport, mountSuspended} from '@nuxt/test-utils/runtime' import LocationSelection from '../LocationSelection.vue' describe('LocationSelection.vue', () => { mockNuxtImport('useNuxtApp', () => { return () => ({ $api: () => Promise.resolve() // Mock the $api method }) }) it('test', async () => { const wrapper = await mountSuspended(LocationSelection) await wrapper.vm.$nextTick() console.log(wrapper.html()) expect(wrapper.text()).toContain('333') }) }) Not working
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I understand you're still having issues with testing your LocationSelection.vue component. Let's analyze the problem based on the knowledge sources provided and suggest a solution. The main issue here is that useNuxtApp() is not being properly mocked in your test environment. The approaches you've tried are close, but they need some adjustments. Let's try a different approach using mockNuxtImport:
import { describe, it, expect, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

const { useNuxtApp } = vi.hoisted(() => {
return {
useNuxtApp: vi.fn().mockImplementation(() => ({
$api: vi.fn().mockResolvedValue({ data: 'mocked data' })
}))
}
})

mockNuxtImport('useNuxtApp', () => useNuxtApp)

describe('LocationSelection.vue', () => {
it('test', async () => {
const wrapper = await mountSuspended(LocationSelection)
await wrapper.vm.$nextTick()
await vi.runAllTimers() // If you're using setTimeout or setInterval
await vi.runAllTicks() // Run all microtasks
console.log(wrapper.html())
expect(wrapper.text()).toContain('333')
})
})
import { describe, it, expect, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

const { useNuxtApp } = vi.hoisted(() => {
return {
useNuxtApp: vi.fn().mockImplementation(() => ({
$api: vi.fn().mockResolvedValue({ data: 'mocked data' })
}))
}
})

mockNuxtImport('useNuxtApp', () => useNuxtApp)

describe('LocationSelection.vue', () => {
it('test', async () => {
const wrapper = await mountSuspended(LocationSelection)
await wrapper.vm.$nextTick()
await vi.runAllTimers() // If you're using setTimeout or setInterval
await vi.runAllTicks() // Run all microtasks
console.log(wrapper.html())
expect(wrapper.text()).toContain('333')
})
})
This approach is based on the solution provided in the Stack Overflow post about mocking Supabase in Vitest (https://stackoverflow.com/questions/78427333). Here's why this should work: 1. We use vi.hoisted() to create a mock implementation of useNuxtApp that will be available throughout the test file. 2. We use mockNuxtImport to replace the real useNuxtApp with our mocked version. This ensures that when your component calls useNuxtApp(), it gets our mocked version. 3. The mocked useNuxtApp returns an object with a $api method that resolves immediately, allowing your component's logic to proceed to setting test.value = '333'. 4. We use vi.runAllTimers() and vi.runAllTicks() to ensure all asynchronous operations complete before we check the component's content. If this still doesn't work, there might be other factors at play. Here are a few things to check: 1. Make sure your vitest.config.ts is set up correctly for Nuxt testing. It should include:
export default defineVitestConfig({
test: {
environment: 'nuxt'
}
})

export default defineVitestConfig({
test: {
environment: 'nuxt'
}
})

This is mentioned in the Docs > Getting-started > Testing > Unit Testing > Setup (https://nuxt.com/docs/getting-started/testing#setup) section. 2. If you're using other Nuxt composables or auto-imports, make sure to mock them as well using mockNuxtImport. 3. If the issue persists, it might be worth checking if there are any other asynchronous operations in your component that are not being properly handled in the test. If you're still encountering issues after trying these suggestions, it might be helpful to review the full component code and any related files to identify potential causes. The problem could be related to how the component is structured or how other Nuxt features are being used. Docs > Getting-started > Testing (https://nuxt.com/docs/getting-started/testing#mocknuxtimport) provides more information about testing Nuxt applications, which might be helpful for troubleshooting this issue further. ---------------------- 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
I decided to change mountSuspended to mount. It helped me.
manniL
manniL2w ago
@Yuri you shouldn't call useNuxtApp in your fetchCities function but outside of it (just FYI)
Want results from more Discord servers?
Add your server