diff --git a/e2e/vite/src/vite.test.ts b/e2e/vite/src/vite.test.ts index fa4d6ab534899..7d65c332dbab5 100644 --- a/e2e/vite/src/vite.test.ts +++ b/e2e/vite/src/vite.test.ts @@ -292,6 +292,8 @@ export default defineConfig({ }, environment: 'jsdom', include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['junit'], + outputFile: 'junit.xml', coverage: { enabled: true, reportsDirectory: 'coverage', @@ -313,6 +315,7 @@ export default defineConfig({ expect(results).toContain( `Successfully ran target test for project ${lib}` ); + expect(results).toContain(`JUNIT report written`); }, 100_000); it('should be able to run tests with inSourceTests set to true', async () => { diff --git a/packages/vite/src/executors/test/vitest.impl.ts b/packages/vite/src/executors/test/vitest.impl.ts index 8eac882ed160b..733a4388b7dcc 100644 --- a/packages/vite/src/executors/test/vitest.impl.ts +++ b/packages/vite/src/executors/test/vitest.impl.ts @@ -1,7 +1,14 @@ -import { ExecutorContext, workspaceRoot } from '@nrwl/devkit'; +import { + ExecutorContext, + logger, + stripIndents, + workspaceRoot, +} from '@nrwl/devkit'; import { CoverageOptions, File, Reporter } from 'vitest'; +import { loadConfigFromFile } from 'vite'; import { VitestExecutorOptions } from './schema'; -import { relative } from 'path'; +import { join, relative } from 'path'; +import { existsSync } from 'fs'; class NxReporter implements Reporter { deferred: { @@ -46,27 +53,9 @@ export async function* vitestExecutor( 'return import("vitest/node")' )() as Promise); - const projectRoot = context.projectGraph.nodes[context.projectName].data.root; - const offset = relative(workspaceRoot, context.cwd); - const nxReporter = new NxReporter(options.watch); - // if reportsDirectory is not provides vitest will remove all files in the project root - // when coverage is enabled in the vite.config.ts - const coverage: CoverageOptions = options.reportsDirectory - ? { - enabled: options.coverage, - reportsDirectory: options.reportsDirectory, - } - : {}; - const settings = { - ...options, - // when running nx from the project root, the root will get appended to the cwd. - // creating an invalid path and no tests will be found. - // instead if we are not at the root, let the cwd be root. - root: offset === '' ? projectRoot : '', - reporters: [...(options.reporters ?? []), 'default', nxReporter], - coverage, - }; + const settings = await getSettings(options, context); + settings.reporters.push(nxReporter); const ctx = await startVitest(options.mode, [], settings); @@ -98,4 +87,69 @@ export async function* vitestExecutor( }; } +async function getSettings( + options: VitestExecutorOptions, + context: ExecutorContext +) { + const projectRoot = context.projectGraph.nodes[context.projectName].data.root; + const offset = relative(workspaceRoot, context.cwd); + // if reportsDirectory is not provides vitest will remove all files in the project root + // when coverage is enabled in the vite.config.ts + const coverage: CoverageOptions = options.reportsDirectory + ? { + enabled: options.coverage, + reportsDirectory: options.reportsDirectory, + } + : {}; + + const viteConfigPath = options.config + ? join(context.root, options.config) + : findViteConfig(join(context.root, projectRoot)); + + const resolved = await loadConfigFromFile( + { + mode: options.mode, + command: 'serve', + }, + viteConfigPath + ); + + if (!viteConfigPath || !resolved?.config?.test) { + logger.warn(stripIndents`Unable to load test config from config file ${ + resolved.path ?? viteConfigPath + } +Some settings may not be applied as expected. +You can manually set the config in the project, ${ + context.projectName + }, configuration. + `); + } + + const settings = { + ...options, + // when running nx from the project root, the root will get appended to the cwd. + // creating an invalid path and no tests will be found. + // instead if we are not at the root, let the cwd be root. + root: offset === '' ? projectRoot : '', + reporters: [ + ...(options.reporters ?? []), + ...((resolved?.config?.test?.reporters as string[]) ?? []), + 'default', + ] as (string | Reporter)[], + coverage: { ...resolved?.config?.test?.coverage, ...coverage }, + }; + + return settings; +} + +function findViteConfig(projectRootFullPath: string): string { + const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts']; + + for (const ext of allowsExt) { + if (existsSync(join(projectRootFullPath, `vite.config.${ext}`))) { + return join(projectRootFullPath, `vite.config.${ext}`); + } + } +} + export default vitestExecutor;