Plugins not overwritten when passed as options
Closed this issue ยท 5 comments
Environment
- Operating System:
Darwin
- Node Version:
v20.11.0
- Nuxt Version:
3.11.2
- CLI Version:
3.11.1
- Nitro Version:
2.9.6
- Package Manager:
pnpm@8.14.2
- Builder:
-
- User Config:
devtools
,modules
,pinia
,typescript
- Runtime Modules:
@nuxt/test-utils/module@3.12.1
,@pinia/nuxt@0.5.1
- Build Modules:
-
Reproduction
https://github.com/lucasecdb/nuxt-app-pinia-repro
Install dependencies with pnpm install
then run pnpm test
Describe the bug
If you configure a vue plugin using Nuxt plugins, like the following:
// plugins/pinia.ts
import { createPinia } from 'pinia';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(createPinia())
})
Given the following component and Pinia store:
<template>
<p>{{ date }}</p>
</template>
<script setup>
const store = useMyStore();
const date = computed(() => store.date);
</script>
// stores/my-store.ts
export const useMyStore = defineStore('my-store', () => {
return {
date: ref(new Date()),
};
});
And then try to overwrite that plugin during testing:
// __tests__/my-component.test.ts
import { createPinia } from 'pinia';
it('should pass', async () => {
await renderSuspended(MyComponent, {
global: { plugins: [createPinia()] },
});
// ...
});
The instance returned by useMyStore
will always use the Pinia store supplied by plugins/pinia
, and not from the global.plugins
parameter provided to renderSuspended
.
Additional context
No response
Logs
No response
The issue you're experiencing with Pinia store instances not being overwritten during testing with renderSuspended
is likely due to how the testing setup is configured, specifically with regard to state management plugins like Pinia. The renderSuspended
function, as part of the test setup, does not directly manipulate or replace state management instances. It focuses on Vue's global properties, provided values, and components, without specific handling for Pinia stores.
To address this, you'll need to manually configure or mock the Pinia store before running your tests to ensure that the mock store is used. This might involve mocking global imports or providing a mock store through the global properties or provides context in your test setup.
Additionally, there's a similar issue discussed in the @nuxt/test-utils
repository, specifically in mountSuspended & createTestingPinia, which points to an existing issue on the @pinia/nuxt
repository. For more detailed information and potential solutions, you might want to check out the discussion there: vuejs/pinia#2555. This could provide further insights into how others have approached and potentially resolved similar testing challenges with Pinia in a Nuxt environment.
Details
Sources
About Dosu
This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.
Help me be more useful! Please leave a ๐ if this is helpful and ๐ if it is irrelevant.
To continue the conversation, mention @dosu.
The issue occurs because on @vue/test-utils
the plugins
from the global properties are applied before the provides
:
- Plugins are applied on line 276: https://github.com/vuejs/test-utils/blob/1cdd7ae5a973e8a2de8eef8c22159bc0cc97f911/src/createInstance.ts#L269-L278
- Provides values are copied to the vue instance on line 303: https://github.com/vuejs/test-utils/blob/1cdd7ae5a973e8a2de8eef8c22159bc0cc97f911/src/createInstance.ts#L299-L305
And since renderSuspended
copies over the provided values from the global instance down to the render
call, the plugin will always be overwritten back by the vueApp
provided value:
test-utils/src/runtime-utils/render.ts
Line 136 in 08ee351
The issue @dosubot linked is caused by this exact same issue, the pinia store is being overwritten by the value injected in @pinia/nuxt
plugin.
Changing the test to use either mount
or render
(from testing-library) solves the issue because we are not reusing the context from nuxtApp.vueApp
.
To address the issue of the Pinia store instance not being overwritten during testing in your Nuxt application, you've pinpointed the core problem related to the order in which plugins and provides are applied in @vue/test-utils
. Specifically, the global plugins are applied before the provides, leading to the original Pinia store being reinstated by the vueApp
provided value.
For a solution, consider manually setting up or mocking the Pinia store before running your tests. This ensures the mock store is utilized instead of the default instance from plugins/pinia.ts
. Here's how you can do it:
import { createPinia, setActivePinia } from 'pinia';
import { renderSuspended } from '@nuxt/test-utils/runtime';
import MyComponent from '@/components/MyComponent.vue';
it('correctly overwrites the Pinia store instance', async () => {
const mockStore = createPinia();
setActivePinia(mockStore);
const options = {
global: {
plugins: [mockStore],
},
};
const { html } = await renderSuspended(MyComponent, options);
// Your test assertions here
});
This approach involves creating a mock Pinia store and setting it as active before the test runs. By passing this mock store in the global.plugins
array of the options
object to renderSuspended
, you ensure that your component under test uses the mocked store.
Additionally, there are discussions and potential solutions in related threads such as mountSuspended & createTestingPinia and Unable to test component using pinia store, which might offer further insights or alternative approaches.
This method allows you to control the Pinia instance used during tests, ensuring that your tests use the intended store configuration. If you encounter any further issues or need more detailed guidance, feel free to ask.
Details
Sources
- mountSuspended & createTestingPinia
- Unable to test component using pinia store
- Testing with a Pinia store best practices
- src/runtime-utils/render.ts
- examples/app-vitest-full/tests/nuxt/render-suspended.spec.ts
- examples/app-vitest-full/nuxt.config.ts
- CHANGELOG.md
- src/runtime-utils/mount.ts
- examples/app-vitest-full/plugins/inject-value.ts
About Dosu
This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.
Help me be more useful! Please leave a ๐ if this is helpful and ๐ if it is irrelevant.
To continue the conversation, mention @dosu.
This is now resolved in the latest @vue/test-utils
: https://github.com/vuejs/test-utils/releases/tag/v2.4.6.