mocking plugins used within nuxt
Hey, firstly thank you for making this plugin, it looks very useful :)
Running this module seems to run the whole nuxt environment, including the plugins, and we have a plugin that makes a api call. We normally just mock the module where we import the api function but it doesn't seem to work in this case. For example:
// somePlugin.ts
import { fetchProducts } from "~/service/products";
export default defineNuxtPlugin(async () => {
const products = fetchProducts();
// do something with the products
});
// SomeComponent.nuxt.spec.js
import { describe, it, expect, vi } from "vitest";
import { shallowMount } from "@vue/test-utils";
import SomeComponent from "../SomeComponent.vue";
// trying to mock the products service so that the real api doesn't get called during the plugins
vi.mock("~/service/products");
describe("SomeComponent", async () => {
it("Is a Vue instance", () => {
const wrapper = shallowMount(SomeComponent);
expect(wrapper.vm).toBeTruthy();
});
});
I assume these mocks only work for the component that we are testing and not for the plugins in the nuxt environment for example. Do you have a suggestion about how to solve this?
I had a similar problem, my rest client is setup in a nuxt plugin and a subsequent plugin uses that client to make an app init api call.
In my rest client plugin i have something like the following:
const client = process.env?.TEST ? createMockClient() : createClient()
provideClient(client)
How you actually mock the requests is up to you
I had a similar problem, my rest client is setup in a nuxt plugin and a subsequent plugin uses that client to make an app init api call.
In my rest client plugin i have something like the following:
const client = process.env?.TEST ? createMockClient() : createClient() provideClient(client)How you actually mock the requests is up to you
Thanks! Indeed we could do this but I personally like not having any test related logic in the actual code so I would definitely prefer somehow moving this to the vitest config or the test files themselves :/
it's worth noting that you can mock api routes with registerEndpoint: https://github.com/danielroe/nuxt-vitest#registerendpoint.
There may be other reasons you would want to mock a plugin, and I think it should be possible, so leaving this issue up until we document it.
I'm using a plotting library in my project that is installed as a client side only plugin using the name convention (yourplugin.client.ts) since it uses browser API's. When running tests I get errors indicating the plugin is being executed in an environment that doesn't support it. Could it be that I need additional steps to get client side plugins to behave properly? Being able to mock this all together would be great since none of the things I want to test rely on this plugin. This is my code:
// vitest.config.ts
import { defineVitestConfig } from 'nuxt-vitest/config'
export default defineVitestConfig({
test: {
environment: 'nuxt'
}
})
// plugins/09.plotly.client.ts
import Plotly from 'plotly.js-dist-min'
export default defineNuxtPlugin(() => {
return {
provide: {
Plotly
}
}
})
@danielroe Would it be possible to have something that would allow us to replace a plugin in tests?
Api would be akin to
// In the test
import { overridePlugin } from 'nuxt-vitest'
it('allows me to do things that have great power', () => {
overridePlugin('something', () => {
...function that would override the plugin and receive the same arguments
})
})
I'd like to echo the desire to be able to mock and/or exclude functionality within plugins. For a project I work on, either or both of the following resolutions would be ideal for our use case:
1. Some way to easily specify which plugins to include/exclude in the nuxt-vitest Nuxt runtime
The ability to exclude plugins that don't need to run in our testing environment would save us from needing to mock that plugin logic despite questionable value to the quality of our tests.
Note:
We tried to specify a subset of our plugins using environmentOptions.nuxt.overrides.plugins in our vitest.config.ts, but Nuxt appears to auto-import all of the plugins despite our explicitly-passed subset.
2. A way to run test setup files (specifically, files with the same context as Vitest setupFiles) before spinning up the Nuxt runtime environment
Upon running vitest from the command line (through npm test), we see the following output. (Sample repo with reproducible output here).
❯ npm test
> [email protected] test
> vitest
global setup
DEV v0.33.0 /Users/adam.gipril/Developer/nuxt-vitest-playground
stdout | unknown test
<Suspense> is an experimental feature and its API will likely change.
stdout | unknown test
setup file
✓ app.test.ts (1)
✓ is 2
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 14:31:58
Duration 553ms (transform 216ms, setup 3ms, collect 6ms, tests 1ms, environment 382ms, prepare 53ms)
PASS Waiting for file changes...
press h to show help, press q to quit
So to put this ask in other words, is there a way to run some sort of setup with the same Vitest context and mocking abilities as the setupFiles, but such that they execute after globalSetup and before the Nuxt runtime starts?
@adam-gipril Yes, we should build this in in future. (Adding setup files easily.) For now, you can likely implement with this hack:
import { defineVitestConfig } from 'nuxt-vitest/config';
export default defineVitestConfig({
test: {
environmentOptions: {
nuxt: {
overrides: {
plugins: [
// path to custom file
]
}
}
}
}
});
Managed to get it working based on these docs: https://test-utils.vuejs.org/api/#global-mocks
I have this plugin
// plugins/hasFeature.ts
export default defineNuxtPlugin(() => {
const { hasFeature } = useAuth()
return {
provide: {
hasFeature,
},
}
})
I then mock it like this:
import { mountSuspended, mockComponent } from "@nuxt/test-utils/runtime"
import { NavigationSettingsTabbed } from "#components"
import { expect, it, vi } from "vitest"
it("setting hidden with missing feature flag", async () => {
const component = await mountSuspended(NavigationSettingsTabbed, {
global: {
mocks: {
$hasFeature: vi.fn(() => false),
$t: vi.fn((input) => input), // from nuxt-i18n. Returns the key directly
},
},
})
expect(component.find('[data-testid="settings-threat-link"]').exists()).toBe(
false,
)
})
Don't know if there are any downsides with this method but it works for me. Without it I get this error:
TypeError: _ctx.$hasFeature is not a function