Reputation: 2138
I am testing pinia store in nuxt3
app.
Inside setup()
of store I'm using useRuntimeConfig
to get initial value for counter from public config variables and I got this error ReferenceError: useRuntimeConfig is not defined
don't know how to solve it
// store/counter.ts
...
state: () => {
const runtimeConfig = useRuntimeConfig()
const count = runtimeConfig.public.count
return {
...
count
...
}
},
...
code
// store/counter.test.ts
import { fileURLToPath } from 'node:url'
import { describe, expect, it, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useCounter } from './counter'
import { setup } from '@nuxt/test-utils'
await setup({
rootDir: fileURLToPath(new URL('../', import.meta.url)),
server: true,
browser: true,
})
describe('Counter Store', () => {
beforeEach(() => {
// creates a fresh pinia and make it active so it's automatically picked
// up by any useStore() call without having to pass it to it:
// `useStore(pinia)`
setActivePinia(createPinia())
})
it('increments', () => {
const counter = useCounter()
expect(counter.n).toBe(0)
counter.increment()
expect(counter.n).toBe(1)
})
it('increments by amount', () => {
const counter = useCounter()
counter.increment(10)
expect(counter.n).toBe(10)
})
})
Upvotes: 7
Views: 7569
Reputation: 76
The best practice for handling these auto imported composables now seems to be the mockNuxtImport()
method from @nuxt/test-utils/runtime
.
Brief example based on what I've been trying to achieve:
// @vitest-environment nuxt
import axios from "axios"
import { describe, it, expect } from "vitest"
import { mockNuxtImport } from "@nuxt/test-utils/runtime"
import yourServiceOrPlugin from "../your-service-or-plugin"
mockNuxtImport("useRuntimeConfig", () => {
return () => {
return {
public: {
// ...your config here
exampleValue: "test-of-the-unit",
},
}
}
})
vi.mock("axios", () => ({
default: {
create: vi.fn().mockReturnThis(),
request: vi.fn(() => Promise.resolve()),
},
}))
describe("your-service-or-plugin", () => {
it("should make a POST request some endpoint", async () => {
const config = useRuntimeConfig()
const { exampleValue } = config.public
await yourServiceOrPlugin.makeSandwich(someData)
expect(axios.request).toHaveBeenCalledWith({
method: "POST",
url: exampleValue,
headers: {
"content-type": "application/json",
},
data: {
payloadItem: someData,
},
})
})
})
Upvotes: 4
Reputation: 4816
I used vitest globalThis
as effectively the tests thought useRuntimeConfig
was undefined I could set it in my test like this:
globalThis.useRuntimeConfig = () => {
return {
public: {
something: 'value'
},
};
};
Sharing sentiments with @KatieAdamsDev, I hope that the auto importing with nuxt tests becomes a little easier. For the moment the above seems not necessarily the correct long-term solution, but I will wait for the Nuxt team to define what that is.
Upvotes: 2
Reputation: 129
This looks similar to an issue that I just solved today. Hopefully it helps you too:
In your component, in this case the Pinia store module, add the explicit import for useRuntimeConfig, as below:
import { useRuntimeConfig } from '#imports'
At the moment I don't have a better way to get around the package being 'undefined' aside from just manually importing it. As Nuxt3 progresses, I'm hoping to see testing become more a focus. Documentation seems to suggest importing it from '#app' but I've not been able to get it working that way and '#imports' seemed the more appropriate alias.
#imports
package to the hidden nuxt file. An example of a vitest.config.js file is below:export default defineConfig({
test: {
// other test specific plugins
},
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, './'),
'~': path.resolve(__dirname, './'),
'#imports': path.resolve(__dirname, './.nuxt/imports.d.ts')
}
}
})
#imports
package. vi.mock('#imports', () => {
return {
useRuntimeConfig() {
return {
public: {
// Your public config!
}
}
}
}
})
This allowed me to mock the runtimeConfig at a test level - hopefully it helps you too! Good luck :D
For anybody reading this wanting to achieve a similar thing in Jest, this is the GitHub discussion that helped me figure this solution out. Unfortunately the discussion I used to create this solution no longer exists. (404)
EDIT: If you need to change the mocked return value on a test-by-test basis, you can return an object defined elsewhere and change the values of that object in your test.
i.e.
let storeMock = {
user: {
getUsername: 'Jane Doe',
setUsername: vi.fn()
}
}
vi.mock('#imports', () => {
return {
useNuxtApp: vi.fn().mockImplementation(() => ({
$store: {
...storeMock
}
})),
}
})
// In your test
storeMock = {
user: {
getUsername: 'Janet Van Dyne',
setUsername: vi.fn()
}
}
Upvotes: 12
Reputation: 21
I had the same issue, but I did not want to explicitly import the composables in the components. There is a plugin that helped me a lot called 'unplugin-auto-import/vite'.
With my vitest.conf.ts am able to mock my useRoute without importing it in the component explicitly.
vitest.config.ts
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
root: '.',
plugins: [
vue(),
AutoImport({
/* options */
imports: ['vue-router'],
}),
],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './setupTests.ts',
},
// ... standart nuxt resolve stuff from ./.nuxt/tsconfig.json
})
VueComponent.vue
<script setup lang="ts">
const route = useRoute()
defineProps<{
componentName?: string
}>()
</script>
<template>
<div>
{{ route.fullPath }}
</div>
</template>
your tests
import VueComponent from '@/components/VueComponent.vue'
import { render, screen } from '@testing-library/vue'
import '@testing-library/jest-dom'
import { vi } from 'vitest'
describe('Default Content Component', () => {
test('Renders Content', () => {
render(VueComponent, {
global: {
mocks: {
route: { fullPath: 'asds' },
},
},
})
// ... your assertions
})
})
Upvotes: 2