N
Nuxt5mo ago
Yuri

Unit Test OnMounted

My component:
import { debounce, upperCase } from 'lodash'
import type { ILocationCitySuggestItem, ILocationCitySuggests } from '~/types/location'
import { useLocationStore } from '~/store/location'

const locationStore = useLocationStore()
const customCSS = useCustomCSS()

// Состояние поиска и списков городов
const searchText = ref('')
const cities: Ref<ILocationCitySuggestItem[]> = ref([])
const initialCities: Ref<ILocationCitySuggestItem[]> = ref([]) // Исходный список городов
const isLoading = ref(false)

// Функция для получения списка городов
const fetchCities = async (query: string | null = null) => {
isLoading.value = true
const nuxtApp = useNuxtApp()
const params = query ? { query: upperCase(query) } : {}

const response = await nuxtApp.$api<ILocationCitySuggests>(apiPath.location.suggest.city, { params })
cities.value = response.items
isLoading.value = false
}

// Дебаунс-функция для оптимизации запросов
const debouncedFetchCities = debounce(() => fetchCities(searchText.value), 300)

// Обновление списка городов при изменении `searchText`
watch(searchText, (newVal) => {
if (newVal) {
debouncedFetchCities()
}
else {
cities.value = initialCities.value
}
})

// Инициализация компонента и начальная загрузка городов
onMounted(async () => {
await fetchCities()
initialCities.value = cities.value
})

// Выбор города
const selectLocation = async (id: number) => {
await locationStore.updateCurrent(id)
}
import { debounce, upperCase } from 'lodash'
import type { ILocationCitySuggestItem, ILocationCitySuggests } from '~/types/location'
import { useLocationStore } from '~/store/location'

const locationStore = useLocationStore()
const customCSS = useCustomCSS()

// Состояние поиска и списков городов
const searchText = ref('')
const cities: Ref<ILocationCitySuggestItem[]> = ref([])
const initialCities: Ref<ILocationCitySuggestItem[]> = ref([]) // Исходный список городов
const isLoading = ref(false)

// Функция для получения списка городов
const fetchCities = async (query: string | null = null) => {
isLoading.value = true
const nuxtApp = useNuxtApp()
const params = query ? { query: upperCase(query) } : {}

const response = await nuxtApp.$api<ILocationCitySuggests>(apiPath.location.suggest.city, { params })
cities.value = response.items
isLoading.value = false
}

// Дебаунс-функция для оптимизации запросов
const debouncedFetchCities = debounce(() => fetchCities(searchText.value), 300)

// Обновление списка городов при изменении `searchText`
watch(searchText, (newVal) => {
if (newVal) {
debouncedFetchCities()
}
else {
cities.value = initialCities.value
}
})

// Инициализация компонента и начальная загрузка городов
onMounted(async () => {
await fetchCities()
initialCities.value = cities.value
})

// Выбор города
const selectLocation = async (id: number) => {
await locationStore.updateCurrent(id)
}
How can I check that fetchCities has been called on mounted hook and initialCities was been set ? I use @nuxt/test-utils
16 Replies
kapa.ai
kapa.ai5mo 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 test that fetchCities is called on the mounted hook and initialCities is set, you can use @nuxt/test-utils along with @vue/test-utils for unit testing your Nuxt component. Here's how you can approach this: 1. First, make sure you have set up your testing environment correctly as described in the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing#setup). 2. Create a test file for your component, for example, YourComponent.nuxt.spec.ts. 3. Use mountSuspended from @nuxt/test-utils/runtime to mount your component in a Nuxt environment. 4. Mock the fetchCities function and the useLocationStore. 5. Assert that fetchCities was called and initialCities was set. Here's an example of how your test could look:
import { describe, it, expect, vi } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import YourComponent from './YourComponent.vue'

// Mock the store and API call
vi.mock('~/store/location', () => ({
useLocationStore: () => ({
updateCurrent: vi.fn(),
}),
}))

vi.mock('#app', () => ({
useNuxtApp: () => ({
$api: vi.fn(() => Promise.resolve({ items: [{ id: 1, name: 'City1' }] })),
}),
}))

describe('YourComponent', () => {
it('calls fetchCities on mounted and sets initialCities', async () => {
const wrapper = await mountSuspended(YourComponent)

// Wait for the next tick to ensure all promises are resolved
await wrapper.vm.$nextTick()

// Check if fetchCities was called (indirectly by checking if the API was called)
expect(wrapper.vm.useNuxtApp().$api).toHaveBeenCalledWith(
expect.any(String),
expect.any(Object)
)

// Check if initialCities was set
expect(wrapper.vm.initialCities).toEqual([{ id: 1, name: 'City1' }])
})
})
import { describe, it, expect, vi } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import YourComponent from './YourComponent.vue'

// Mock the store and API call
vi.mock('~/store/location', () => ({
useLocationStore: () => ({
updateCurrent: vi.fn(),
}),
}))

vi.mock('#app', () => ({
useNuxtApp: () => ({
$api: vi.fn(() => Promise.resolve({ items: [{ id: 1, name: 'City1' }] })),
}),
}))

describe('YourComponent', () => {
it('calls fetchCities on mounted and sets initialCities', async () => {
const wrapper = await mountSuspended(YourComponent)

// Wait for the next tick to ensure all promises are resolved
await wrapper.vm.$nextTick()

// Check if fetchCities was called (indirectly by checking if the API was called)
expect(wrapper.vm.useNuxtApp().$api).toHaveBeenCalledWith(
expect.any(String),
expect.any(Object)
)

// Check if initialCities was set
expect(wrapper.vm.initialCities).toEqual([{ id: 1, name: 'City1' }])
})
})
This test does the following: 1. It mocks the useLocationStore and the $api call to avoid actual API requests during testing. 2. It uses mountSuspended to mount the component in a Nuxt environment. 3. It waits for the next tick to ensure all promises are resolved. 4. It checks if the $api method (which is called by fetchCities) was called. 5. It verifies that initialCities was set with the mocked data. Remember to adjust the import paths and component name according to your project structure. For more details on using @nuxt/test-utils, you can refer to the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing). Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing#unit-testing) provides more information on unit testing in Nuxt, including how to set up your testing environment and use the provided utilities. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5mo ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Yuri
YuriOP5mo ago
@kapa.ai on this line: expect(wrapper.vm.useNuxtApp().$api).toHaveBeenCalledWith( I get error TypeError: [AsyncFunction api] is not a spy or a call to a spy!
kapa.ai
kapa.ai5mo 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 because we haven't properly mocked the $api function as a spy. Let's correct this approach using @nuxt/test-utils. To properly test your component and mock the Nuxt app instance, we can use the mockNuxtImport helper provided by @nuxt/test-utils/runtime. Here's a corrected version of the test:
import { describe, it, expect, vi } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import YourComponent from './YourComponent.vue'

describe('YourComponent', () => {
it('calls fetchCities on mounted and sets initialCities', async () => {
// Mock the API call
const mockApi = vi.fn(() => Promise.resolve({ items: [{ id: 1, name: 'City1' }] }))

// Mock the useNuxtApp composable
mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

// Mock the useLocationStore
mockNuxtImport('useLocationStore', () => () => ({
updateCurrent: vi.fn(),
}))

const wrapper = await mountSuspended(YourComponent)

// Wait for the next tick to ensure all promises are resolved
await vi.runAllTimers()
await wrapper.vm.$nextTick()

// Check if fetchCities was called (by checking if the mocked API was called)
expect(mockApi).toHaveBeenCalledWith(
expect.any(String),
expect.any(Object)
)

// Check if initialCities was set
expect(wrapper.vm.initialCities).toEqual([{ id: 1, name: 'City1' }])
})
})
import { describe, it, expect, vi } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import YourComponent from './YourComponent.vue'

describe('YourComponent', () => {
it('calls fetchCities on mounted and sets initialCities', async () => {
// Mock the API call
const mockApi = vi.fn(() => Promise.resolve({ items: [{ id: 1, name: 'City1' }] }))

// Mock the useNuxtApp composable
mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

// Mock the useLocationStore
mockNuxtImport('useLocationStore', () => () => ({
updateCurrent: vi.fn(),
}))

const wrapper = await mountSuspended(YourComponent)

// Wait for the next tick to ensure all promises are resolved
await vi.runAllTimers()
await wrapper.vm.$nextTick()

// Check if fetchCities was called (by checking if the mocked API was called)
expect(mockApi).toHaveBeenCalledWith(
expect.any(String),
expect.any(Object)
)

// Check if initialCities was set
expect(wrapper.vm.initialCities).toEqual([{ id: 1, name: 'City1' }])
})
})
This approach uses mockNuxtImport to mock both useNuxtApp and useLocationStore. The $api function is now properly mocked as a spy using vi.fn(), which allows us to make assertions on its calls. Key points: 1. We use mockNuxtImport to mock useNuxtApp and useLocationStore. 2. The $api function is mocked using vi.fn(), which creates a spy. 3. We use vi.runAllTimers() to ensure all timers (including debounced functions) are executed. 4. We assert on the mocked mockApi function instead of trying to access it through wrapper.vm. This approach should resolve the "TypeError: [AsyncFunction api] is not a spy or a call to a spy!" error you were encountering. For more information on mocking imports in Nuxt tests, you can refer to the mockNuxtImport section in the Nuxt documentation (https://nuxt.com/docs/getting-started/testing#mocknuxtimport). Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing#unit-testing) provides more details on unit testing in Nuxt, including how to use the provided utilities like mockNuxtImport. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5mo ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Yuri
YuriOP5mo ago
@kapa.ai what is correct variant for mock const response = await nuxtApp.$api<ILocationCitySuggests>(apiPath.location.suggest.city, { params })
kapa.ai
kapa.ai5mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- To correctly mock the nuxtApp.$api call in your Nuxt component test, you can use the mockNuxtImport helper from @nuxt/test-utils/runtime. Here's the correct way to mock this specific API call:
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
import { vi } from 'vitest'

// Mock the API response
const mockApiResponse = {
items: [
{ id: 1, name: 'City1' },
{ id: 2, name: 'City2' }
]
}

// Mock the $api function
const mockApi = vi.fn().mockResolvedValue(mockApiResponse)

// Mock the useNuxtApp composable
mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

// In your test
it('fetches cities correctly', async () => {
// ... mount your component

// Assert that the API was called with the correct arguments
expect(mockApi).toHaveBeenCalledWith(
'apiPath.location.suggest.city', // Replace with the actual path
{ params: expect.any(Object) }
)

// ... other assertions
})
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
import { vi } from 'vitest'

// Mock the API response
const mockApiResponse = {
items: [
{ id: 1, name: 'City1' },
{ id: 2, name: 'City2' }
]
}

// Mock the $api function
const mockApi = vi.fn().mockResolvedValue(mockApiResponse)

// Mock the useNuxtApp composable
mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

// In your test
it('fetches cities correctly', async () => {
// ... mount your component

// Assert that the API was called with the correct arguments
expect(mockApi).toHaveBeenCalledWith(
'apiPath.location.suggest.city', // Replace with the actual path
{ params: expect.any(Object) }
)

// ... other assertions
})
This approach does the following: 1. It creates a mock API response that matches the structure of ILocationCitySuggests. 2. It uses vi.fn().mockResolvedValue() to create a mock function that resolves with the mock response. 3. It uses mockNuxtImport to mock the useNuxtApp composable, which returns an object with the mocked $api function. This method allows you to control the response of the API call and make assertions about how it was called. Remember to adjust the apiPath.location.suggest.city to match the actual path used in your component. For more information on mocking Nuxt imports and testing, you can refer to the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing#mocknuxtimport). Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing#unit-testing) provides comprehensive guidance on unit testing in Nuxt, including how to use utilities like mockNuxtImport for mocking imports and API calls. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5mo ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Yuri
YuriOP5mo ago
@kapa.ai My current 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";

// Mock the API response
const mockApiResponse = {
items: [
{ id: 1, name: 'City1' },
{ id: 2, name: 'City2' }
]
}

const mockApi = vi.fn().mockResolvedValue(mockApiResponse)
mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

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";

// Mock the API response
const mockApiResponse = {
items: [
{ id: 1, name: 'City1' },
{ id: 2, name: 'City2' }
]
}

const mockApi = vi.fn().mockResolvedValue(mockApiResponse)
mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

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());
})
})
But I receive error: 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 Vitest caught 1 unhandled error during the test run. This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.
kapa.ai
kapa.ai5mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- The error you're encountering suggests that there's an issue with the Nuxt runtime environment in your test setup. This is likely because the mountSuspended function is trying to set up a full Nuxt environment, including the <NuxtRoot> component, which expects certain Nuxt-specific functions to be available. To resolve this issue, we need to ensure that the Nuxt testing environment is properly set up. Here are some steps to try: 1. Make sure you're using the latest version of @nuxt/test-utils. 2. Ensure that your vitest.config.ts file is correctly configured for Nuxt testing. It should look something like this:
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'
}
})
3. Make sure your test file has the .nuxt.spec.ts extension or includes the // @vitest-environment nuxt comment at the top of the file. 4. Try to simplify your test setup. Here's a modified version of your test that might work:
// LocationSelection.nuxt.spec.ts
import { describe, it, expect, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

// Mock the API response
const mockApiResponse = {
items: [
{ id: 1, name: 'City1' },
{ id: 2, name: 'City2' }
]
}

describe('LocationSelection.vue', () => {
it('fetches cities on mount', async () => {
const mockApi = vi.fn().mockResolvedValue(mockApiResponse)

mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

const wrapper = await mountSuspended(LocationSelection)

// Wait for the next tick to ensure all promises are resolved
await vi.runAllTimers()
await wrapper.vm.$nextTick()

// Check if the API was called
expect(mockApi).toHaveBeenCalled()
// Check if the cities are rendered (adjust based on your component's structure)
expect(wrapper.text()).toContain('City1')
expect(wrapper.text()).toContain('City2')
})
})
// LocationSelection.nuxt.spec.ts
import { describe, it, expect, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

// Mock the API response
const mockApiResponse = {
items: [
{ id: 1, name: 'City1' },
{ id: 2, name: 'City2' }
]
}

describe('LocationSelection.vue', () => {
it('fetches cities on mount', async () => {
const mockApi = vi.fn().mockResolvedValue(mockApiResponse)

mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

const wrapper = await mountSuspended(LocationSelection)

// Wait for the next tick to ensure all promises are resolved
await vi.runAllTimers()
await wrapper.vm.$nextTick()

// Check if the API was called
expect(mockApi).toHaveBeenCalled()
// Check if the cities are rendered (adjust based on your component's structure)
expect(wrapper.text()).toContain('City1')
expect(wrapper.text()).toContain('City2')
})
})
5. If you're still encountering issues, you might need to mock additional Nuxt composables. For example:
mockNuxtImport('useCustomCSS', () => () => ({}))
mockNuxtImport('useLocationStore', () => () => ({
updateCurrent: vi.fn()
}))
mockNuxtImport('useCustomCSS', () => () => ({}))
mockNuxtImport('useLocationStore', () => () => ({
updateCurrent: vi.fn()
}))
6. Ensure that your package.json has the correct test script and dependencies for Nuxt testing. If you're still facing issues after trying these steps, it might be helpful to check the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing) for any recent changes or known issues with the testing setup. Remember, the Nuxt testing utilities are designed to work with a specific Nuxt environment, so make sure all parts of your testing setup are compatible with your Nuxt version and configuration. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5mo ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Yuri
YuriOP5mo ago
1 @kapa.ai
kapa.ai
kapa.ai5mo ago
Let me check the knowledge base for you again. One moment! :books: Sorry @Yuri, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
Yuri
YuriOP5mo ago
@kapa.ai My component:
import { debounce, upperCase } from 'lodash'
import type { ILocationCitySuggestItem, ILocationCitySuggests } from '~/types/location'
import { useLocationStore } from '~/store/location'

const locationStore = useLocationStore()
const customCSS = useCustomCSS()

const searchText = ref('')
const cities: Ref<ILocationCitySuggestItem[]> = ref([])
const initialCities: Ref<ILocationCitySuggestItem[]> = ref([]) //
const isLoading = ref(false)

const fetchCities = async (query: string | null = null) => {
isLoading.value = true
const nuxtApp = useNuxtApp()
const params = query ? { query: upperCase(query) } : {}
const response = await nuxtApp.$api<ILocationCitySuggests>(apiPath.location.suggest.city, { params })
cities.value = response.items
isLoading.value = false
}

const debouncedFetchCities = debounce(() => fetchCities(searchText.value), 300)

watch(searchText, (newVal) => {
if (newVal) {
debouncedFetchCities()
}
else {
cities.value = initialCities.value
}
})
onMounted(async () => {
await fetchCities()
initialCities.value = cities.value
})

const selectLocation = async (id: number) => {
await locationStore.updateCurrent(id)
}
import { debounce, upperCase } from 'lodash'
import type { ILocationCitySuggestItem, ILocationCitySuggests } from '~/types/location'
import { useLocationStore } from '~/store/location'

const locationStore = useLocationStore()
const customCSS = useCustomCSS()

const searchText = ref('')
const cities: Ref<ILocationCitySuggestItem[]> = ref([])
const initialCities: Ref<ILocationCitySuggestItem[]> = ref([]) //
const isLoading = ref(false)

const fetchCities = async (query: string | null = null) => {
isLoading.value = true
const nuxtApp = useNuxtApp()
const params = query ? { query: upperCase(query) } : {}
const response = await nuxtApp.$api<ILocationCitySuggests>(apiPath.location.suggest.city, { params })
cities.value = response.items
isLoading.value = false
}

const debouncedFetchCities = debounce(() => fetchCities(searchText.value), 300)

watch(searchText, (newVal) => {
if (newVal) {
debouncedFetchCities()
}
else {
cities.value = initialCities.value
}
})
onMounted(async () => {
await fetchCities()
initialCities.value = cities.value
})

const selectLocation = async (id: number) => {
await locationStore.updateCurrent(id)
}
And my test:
import LocationSelection from '../LocationSelection.vue'
import {flushPromises} from "@vue/test-utils";

const mockApiResponse = {
items: [
{ id: 1, name: 'City1' }
]
}

const mockApi = vi.fn().mockResolvedValue(mockApiResponse)
mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

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 LocationSelection from '../LocationSelection.vue'
import {flushPromises} from "@vue/test-utils";

const mockApiResponse = {
items: [
{ id: 1, name: 'City1' }
]
}

const mockApi = vi.fn().mockResolvedValue(mockApiResponse)
mockNuxtImport('useNuxtApp', () => () => ({
$api: mockApi
}))

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());
})
})
But i receive errors: TypeError: nuxtApp.deferHydration is not a function Where is a mistake?
kapa.ai
kapa.ai5mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- The error you're encountering suggests that there's an issue with the Nuxt runtime environment in your test setup. This is likely because the mountSuspended function is trying to set up a full Nuxt environment, which expects certain Nuxt-specific functions to be available. To resolve this issue, we need to ensure that the Nuxt testing environment is properly set up. Here are some steps to try: 1. Make sure your test file has the .nuxt.spec.ts extension or includes the // @vitest-environment nuxt comment at the top of the file. This ensures that the Nuxt environment is used for your tests. 2. Ensure that your vitest.config.ts file is correctly configured for Nuxt testing. It should look something like this:
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'
}
})
3. You need to mock all the composables used in your component. Here's an updated version of your test that includes mocks for all the necessary composables:
import { describe, it, expect, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

// Mock the API response
const mockApiResponse = {
items: [
{ id: 1, name: 'City1' }
]
}

describe('LocationSelection.vue', () => {
beforeEach(() => {
// Mock all necessary composables
mockNuxtImport('useLocationStore', () => () => ({
updateCurrent: vi.fn()
}))
mockNuxtImport('useCustomCSS', () => () => ({}))
mockNuxtImport('useNuxtApp', () => () => ({
$api: vi.fn().mockResolvedValue(mockApiResponse)
}))
})

it('fetches cities on mount', async () => {
const wrapper = await mountSuspended(LocationSelection)
// Wait for the next tick to ensure all promises are resolved
await vi.runAllTimers()
await wrapper.vm.$nextTick()

// Check if the cities are rendered (adjust based on your component's structure)
expect(wrapper.text()).toContain('City1')
})
})
import { describe, it, expect, vi } from 'vitest'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import LocationSelection from '../LocationSelection.vue'

// Mock the API response
const mockApiResponse = {
items: [
{ id: 1, name: 'City1' }
]
}

describe('LocationSelection.vue', () => {
beforeEach(() => {
// Mock all necessary composables
mockNuxtImport('useLocationStore', () => () => ({
updateCurrent: vi.fn()
}))
mockNuxtImport('useCustomCSS', () => () => ({}))
mockNuxtImport('useNuxtApp', () => () => ({
$api: vi.fn().mockResolvedValue(mockApiResponse)
}))
})

it('fetches cities on mount', async () => {
const wrapper = await mountSuspended(LocationSelection)
// Wait for the next tick to ensure all promises are resolved
await vi.runAllTimers()
await wrapper.vm.$nextTick()

// Check if the cities are rendered (adjust based on your component's structure)
expect(wrapper.text()).toContain('City1')
})
})
4. Make sure you're importing vi from Vitest:
import { describe, it, expect, vi } from 'vitest'
import { describe, it, expect, vi } from 'vitest'
5. Remove the createWrapper function and directly use mountSuspended in your test. 6. If you're still encountering issues, you might need to mock additional Nuxt composables or globals. For example:
vi.mock('#imports', () => ({
useNuxtApp: () => ({
$api: vi.fn().mockResolvedValue(mockApiResponse)
}),
useLocationStore: () => ({
updateCurrent: vi.fn()
}),
useCustomCSS: () => ({}),
// Add any other global imports your component uses
}))
vi.mock('#imports', () => ({
useNuxtApp: () => ({
$api: vi.fn().mockResolvedValue(mockApiResponse)
}),
useLocationStore: () => ({
updateCurrent: vi.fn()
}),
useCustomCSS: () => ({}),
// Add any other global imports your component uses
}))
If you're still facing issues after trying these steps, it might be helpful to check the Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing) for any recent changes or known issues with the testing setup. Remember, the Nuxt testing utilities are designed to work with a specific Nuxt environment, so make sure all parts of your testing setup are compatible with your Nuxt version and configuration. Nuxt Testing documentation (https://nuxt.com/docs/getting-started/testing#unit-testing) provides comprehensive guidance on unit testing in Nuxt, including how to set up your testing environment and use the provided utilities. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5mo ago
<@740173469404364872> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?