fix(angular): ensure crystal targets for testing when bundler=rspack (#30631)

## Current Behavior
Angular Rspack relies on Inferred Targets however, when scaffolding the
application, the unit test runners are being set up with executors.

## Expected Behavior
Ensure that when `bundler=rspack` unit test runners are being set up
with inference plugins
This commit is contained in:
Colum Ferry 2025-04-10 11:06:15 +01:00 committed by GitHub
parent d4ebf82ac8
commit c71a7832b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 66 additions and 11 deletions

View File

@ -40,7 +40,7 @@ export async function addLintingGenerator(
setParserOptionsProject: options.setParserOptionsProject,
skipFormat: true,
rootProject: rootProject,
addPlugin: false,
addPlugin: options.addPlugin ?? false,
addExplicitTargets: true,
skipPackageJson: options.skipPackageJson,
});

View File

@ -6,4 +6,5 @@ export interface AddLintingGeneratorSchema {
skipFormat?: boolean;
skipPackageJson?: boolean;
unitTestRunner?: string;
addPlugin?: boolean;
}

View File

@ -1246,6 +1246,7 @@ describe('app', () => {
]
`);
});
it('should generate a correct setup when --bundler=rspack including a correct config file and no build target', async () => {
await generateApp(appTree, 'app1', {
bundler: 'rspack',
@ -1257,6 +1258,42 @@ describe('app', () => {
expect(appTree.read('app1/rspack.config.ts', 'utf-8')).toMatchSnapshot();
});
it('should generate use crystal jest when --bundler=rspack', async () => {
await generateApp(appTree, 'app1', {
bundler: 'rspack',
unitTestRunner: UnitTestRunner.Jest,
});
const project = readProjectConfiguration(appTree, 'app1');
expect(project.targets.test).not.toBeDefined();
const nxJson = readNxJson(appTree);
const jestPlugin = nxJson.plugins.find(
(p) =>
(typeof p === 'string' && p === '@nx/jest/plugin') ||
(typeof p !== 'string' && p.plugin === '@nx/jest/plugin')
);
expect(jestPlugin).toBeDefined();
});
it('should generate use crystal vitest when --bundler=rspack', async () => {
await generateApp(appTree, 'app1', {
bundler: 'rspack',
unitTestRunner: UnitTestRunner.Vitest,
});
const project = readProjectConfiguration(appTree, 'app1');
expect(project.targets.test).not.toBeDefined();
const nxJson = readNxJson(appTree);
const vitePlugin = nxJson.plugins.find(
(p) =>
(typeof p === 'string' && p === '@nx/vite/plugin') ||
(typeof p !== 'string' && p.plugin === '@nx/vite/plugin')
);
expect(vitePlugin).toBeDefined();
});
it('should generate target options "browser" and "buildTarget"', async () => {
await generateApp(appTree, 'my-app', { standalone: true });

View File

@ -31,7 +31,6 @@ import {
updateEditorTsConfig,
} from './lib';
import type { Schema } from './schema';
import { tsNodeVersion } from '../../utils/versions';
export async function applicationGenerator(
tree: Tree,
@ -43,7 +42,7 @@ export async function applicationGenerator(
schema.bundler = 'webpack';
}
const options = await normalizeOptions(tree, schema);
const options = await normalizeOptions(tree, schema, isRspack);
const rootOffset = offsetFromRoot(options.appProjectRoot);
await jsInitGenerator(tree, {
@ -55,6 +54,7 @@ export async function applicationGenerator(
await angularInitGenerator(tree, {
...options,
skipFormat: true,
addPlugin: options.addPlugin,
});
if (!options.skipPackageJson) {

View File

@ -15,8 +15,8 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) {
// since e2e are separate projects, default to adding plugins
const nxJson = readNxJson(tree);
const addPlugin =
process.env.NX_ADD_PLUGINS !== 'false' &&
nxJson.useInferencePlugins !== false;
nxJson['useInferencePlugins'] !== false &&
process.env.NX_ADD_PLUGINS !== 'false';
const e2eWebServerInfo = getAngularE2EWebServerInfo(
tree,

View File

@ -16,5 +16,6 @@ export async function addLinting(host: Tree, options: NormalizedSchema) {
skipPackageJson: options.skipPackageJson,
unitTestRunner: options.unitTestRunner,
skipFormat: true,
addPlugin: options.addPlugin,
});
}

View File

@ -12,6 +12,7 @@ export async function addUnitTestRunner(host: Tree, options: NormalizedSchema) {
projectRoot: options.appProjectRoot,
skipPackageJson: options.skipPackageJson,
strict: options.strict,
addPlugin: options.addPlugin,
});
break;
case UnitTestRunner.Vitest:
@ -20,6 +21,7 @@ export async function addUnitTestRunner(host: Tree, options: NormalizedSchema) {
projectRoot: options.appProjectRoot,
skipPackageJson: options.skipPackageJson,
strict: options.strict,
addPlugin: options.addPlugin,
});
break;
}

View File

@ -1,4 +1,4 @@
import { joinPathFragments, type Tree } from '@nx/devkit';
import { joinPathFragments, readNxJson, type Tree } from '@nx/devkit';
import {
determineProjectNameAndRootOptions,
ensureRootProjectName,
@ -8,9 +8,16 @@ import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners';
import type { Schema } from '../schema';
import type { NormalizedSchema } from './normalized-schema';
function arePluginsExplicitlyDisabled(host: Tree) {
const { useInferencePlugins } = readNxJson(host);
const addPluginEnvVar = process.env.NX_ADD_PLUGINS;
return useInferencePlugins === false || addPluginEnvVar === 'false';
}
export async function normalizeOptions(
host: Tree,
options: Partial<Schema>
options: Partial<Schema>,
isRspack?: boolean
): Promise<NormalizedSchema> {
await ensureRootProjectName(options as Schema, 'application');
const { projectName: appProjectName, projectRoot: appProjectRoot } =
@ -31,8 +38,12 @@ export async function normalizeOptions(
const bundler = options.bundler ?? 'esbuild';
const addPlugin =
options.addPlugin ?? (!arePluginsExplicitlyDisabled(host) && isRspack);
// Set defaults and then overwrite with user options
return {
addPlugin,
style: 'css',
routing: true,
inlineStyle: false,

View File

@ -31,4 +31,5 @@ export interface Schema {
ssr?: boolean;
serverRouting?: boolean;
nxCloudToken?: string;
addPlugin?: boolean;
}

View File

@ -410,8 +410,8 @@ export async function convertToRspack(
);
}
}
serveTargetNames.push(targetName);
}
serveTargetNames.push(targetName);
}
const customWebpackConfigInfo = customWebpackConfigPath

View File

@ -11,6 +11,7 @@ export type AddJestOptions = {
projectRoot: string;
skipPackageJson: boolean;
strict: boolean;
addPlugin?: boolean;
};
export async function addJest(
@ -40,8 +41,8 @@ export async function addJest(
skipSerializers: false,
skipPackageJson: options.skipPackageJson,
skipFormat: true,
addPlugin: false,
addExplicitTargets: true,
addPlugin: options.addPlugin ?? false,
addExplicitTargets: !options.addPlugin,
});
const setupFile = joinPathFragments(

View File

@ -6,6 +6,7 @@ export type AddVitestOptions = {
projectRoot: string;
skipPackageJson: boolean;
strict: boolean;
addPlugin?: boolean;
};
export async function addVitest(
@ -22,6 +23,6 @@ export async function addVitest(
uiFramework: 'angular',
testEnvironment: 'jsdom',
coverageProvider: 'v8',
addPlugin: false,
addPlugin: options.addPlugin ?? false,
});
}