-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nuxt server environment support #531
Comments
Thanks for opening this issue. There are probably cases, such as using It seems that I can't do this in simple unit tests even for those tests which are not running this Nuxt environment once the plugin is installed. |
Nuxt hard codes |
I see, thanks for the clarification |
as a work around for my apicalls / nitro plugins i added all auto imported server stuff to my setup.ts as vitest.stubGlobal("defineEventHandler", (func: any) => func);
vitest.stubGlobal("defineNitroPlugin", (e: any) => e);
//etc Which works absolutely fine for the time being, if anyone has a better idea/way i'd love to know! I mock my own utilities the same way and then use them in unit tests like this (getService as MockedFunction<typeof getService>).mockReturnValue(
{mockedServiceCall: () => true}
); |
Are there any plans to make this happen still? I was hoping for my full stack Nuxt framework that I'd be able to unit test the full stack but the confusion/limited support for unit testing the server side has resulted in weeks of lost time and confusion around the matter. Even a section in the testing docs warning people away from unit testing the server/api routes would help others here. |
For unit tests on Nuxt API endpoints this problem might also be solved w/ H3 test utils that are agnostic of the Nuxt runtime & instead allow for programmatic execution of event handlers I have been playing w/ an implementation that allows for me to:
Extending this workaround, we can define a function that registers // ~/test/setup.ts
import type { H3Event } from "h3";
import { vi } from "vitest";
type Handler = (event: H3Event) => Promise<unknown>;
export function useH3TestUtils() {
const h3 = vi.hoisted(() => ({
defineEventHandler: vi.fn((handler: Handler) => (event: H3Event) => handler(event)),
// TODO mock these utils: https://www.jsdocs.io/package/h3#package-index-functions
});
// stub `h3` & functions individually to support auto-imports
vi.stubGlobal("h3", h3);
vi.stubGlobal("defineEventHandler", h3.defineEventHandler);
// TODO stub remaing utils
return h3;
} This makes unit testing a given handler a breeze: // ~/test/server/api/handler.test.ts
import { useH3TestUtils } from "@@/test/setup";
import { describe, it, expect } from "vitest";
const {
defineEventHandler,
// TODO add mocked utils your handler uses...
} = useH3TestUtils();
describe("my handler", async () => {
const handler = await import("../../../server/api/handler.get.ts");
it("is registered as an event handler", () => expect(defineEventHandler).toHaveBeenCalled());
it("does something", async () => {
const results = await handler.default({ /* custom `H3Event` here */ });
expect(results).toBe("some expected value");
});
}); This structure could be extended to provide a broad set of utils for H3 that enable unit tests for Nuxt API endpoints & could support future development of a simulated Nuxt server environment Hopefully this helps someone else who hits issues running Nuxt server unit tests, if there is interest in my approach I am happy to spin this up into a POC module 😄 |
I'm posting this here for anyone looking for a more comprehensive solution to unit testing Nuxt server code or doing other fully-isolated unit tests. Since I added unit tests to our Nuxt 3 project long before test-utils was ready, I had to come up with a way to test the entire stack without Nuxt in the picture at all. Here's what my import path from 'path'
import Vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import { defineConfig } from 'vitest/config'
export default defineConfig({
plugins: [
Vue(),
Components({
dirs: ['./app/components'],
dts: './tests/vitest-components.d.ts',
}),
AutoImport({
imports: [
'vue',
'vitest',
'pinia',
{
'~~/tests/fixtures/nuxt-stub': [
'useRuntimeConfig',
'useCookie',
'useState',
'useStorage',
'useRouter',
'useRoute',
'navigateTo',
'useNuxtApp',
],
},
{
'graphql-tag': ['gql'],
},
],
dirs: ['./app/composables', './server/utils', './app/utils', './app/stores'],
ignore: ['./server/utils/shared.ts'],
dts: './tests/vitest-auto-imports.d.ts',
vueTemplate: true,
}),
],
resolve: {
alias: {
'~': path.resolve(__dirname, './app'),
'~~': path.resolve(__dirname, '.'),
// Specific to our project: generated imports from modules pointing to existing instance of them. (Requires running nuxi dev first)
'#graphql/schema': path.resolve(__dirname, './.nuxt/graphql-schema.mjs'),
'#graphql/generated-resolvers': path.resolve(__dirname, './.nuxt/graphql-resolvers.ts'),
// Specific to our project: additional overrides to override specific imports with stubbed versions. Useful for mocking external APIs and services.
'@tn-webshare/community-api-client-typescript': path.resolve(
__dirname,
'./server/lib/tessitura-api-node-mock.ts'
),
'./cache': path.resolve(__dirname, './server/lib/cache-mock.ts'),
},
},
test: {
globals: true,
include: ['./**/tests/*.spec.ts', './tests/unit/**/*.spec.ts'],
environmentMatchGlobs: [
// all Vue components, Pinia Stores and other client-side or isomorphic tests use jsdom
['./app/stores/tests/**', 'jsdom'],
['./tests/unit/**', 'jsdom'],
['./tests/unit/components/**', 'jsdom'],
],
},
}) This setup allowed us to fully test code in server handlers, Vue components, Pinia stores and composables without Nuxt at all. One key is using the Vite Components and AutoImport plugins, which properly imports any auto-imported functions or components anywhere in the codebase, just like what would happen in Nuxt. The Now that I'm trying test-utils for the first time to add some integration tests, I need to have a completely separate Vitest config file from the above, since the runtime environments are so different and the auto-importing doesn't work with |
We currently support running composables/components in a browser-type environment (with happy-dom, and soon jsdom). But there are use cases where it might be useful to support running tests in a hybrid server environment where things like h3 utilities and nuxt ssr utilities work.
This could definitely be classed as non-essential and experimental, but we can track it here.
The text was updated successfully, but these errors were encountered: