Files
nest/vitest.config.integration.mts
Kamil Myśliwiec 6e345edc1b test: resolve nest packages from this checkout in integration tests
The @nestjs/* packages installed from npm (graphql, apollo, mongoose,
typeorm) import @nestjs/core and @nestjs/common from where they are
installed. When node_modules is linked to another checkout, as in a git
worktree that shares the main checkout's node_modules, that is a second
copy of every class. Dependency injection then failed (GraphQLModule
could not resolve HttpAdapterHost), so every graphql-schema-first spec
failed in such a checkout while CI passed.

The integration config now dedupes the packages of this repository, so
Vite resolves them from the project root whoever imports them. Nothing
changes where node_modules is installed in place.
2026-10-19 10:22:20 +02:00

95 lines
3.1 KiB
TypeScript

import { existsSync } from 'fs';
import type { Plugin } from 'vite';
import { defineConfig } from 'vitest/config';
/**
* Resolves `.js` imports to `.ts` source files when both exist side-by-side.
*
* The NestJS monorepo keeps compiled `.js` output next to the `.ts` sources.
* Without this plugin, Vite resolves `import '…/foo.js'` to the compiled JS
* instead of the original TypeScript source.
*/
function resolveTypescriptSource(): Plugin {
return {
name: 'resolve-ts-source',
enforce: 'pre',
async resolveId(source, importer, options) {
if (!importer) return null;
const resolved = await this.resolve(source, importer, {
...options,
skipSelf: true,
});
if (resolved && !resolved.external && resolved.id.endsWith('.js')) {
const tsPath = resolved.id.replace(/\.js$/, '.ts');
if (existsSync(tsPath)) return tsPath;
}
return null;
},
};
}
export default defineConfig({
// Spec files are excluded from every tsconfig in the repo, so Oxc cannot pick
// up `experimentalDecorators`/`emitDecoratorMetadata` from them and would emit
// TC39 decorators (which reject parameter decorators). Configure them here.
oxc: {
decorator: {
legacy: true,
emitDecoratorMetadata: true,
},
assumptions: {
setPublicClassFields: true,
},
typescript: {
removeClassFieldsWithoutInitializer: true,
},
},
test: {
globals: true,
root: './',
include: ['integration/**/*.spec.ts'],
exclude: [
'**/node_modules/**',
// Two copies of `graphql` load: "Cannot use GraphQLSchema from another
// module or realm".
'integration/graphql-code-first/**',
// The serialized graph gains websocket entrypoints the fixture lacks.
'integration/inspector/**',
// `@nestjs/core/repl/native-functions` does not resolve under `exports`.
'integration/repl/e2e/repl.spec.ts',
],
server: {
deps: {
// Transform the @nestjs/* packages that live in node_modules so their
// `@nestjs/core` imports reach the same TypeScript sources as the
// tests; loaded natively they get the compiled `.js`, a second copy
// of every class (ModuleRef, HttpAdapterHost).
inline: [/@nestjs\/(apollo|graphql|mongoose|typeorm)/],
},
},
testTimeout: 30_000,
hookTimeout: 30_000,
setupFiles: ['reflect-metadata'],
reporters: ['default'],
fileParallelism: false,
},
resolve: {
// The @nestjs/* packages that live in node_modules import the packages of
// this repository from where they are installed. When node_modules is
// linked to another checkout (e.g. in a git worktree), that is a second
// copy of every class (HttpAdapterHost), so they are resolved from here.
dedupe: [
'@nestjs/common',
'@nestjs/core',
'@nestjs/microservices',
'@nestjs/platform-express',
'@nestjs/platform-fastify',
'@nestjs/platform-socket.io',
'@nestjs/platform-ws',
'@nestjs/testing',
'@nestjs/websockets',
],
},
plugins: [resolveTypescriptSource()],
});