Skip to content

Commit 8d9234b

Browse files
authored
feat(misc): prompt for unit test runner when creating a workspace using --workspaces flag (#29743)
## Current Behavior Creating a new workspace does not prompt for the unit test runner. ## Expected Behavior Creating a new workspace should prompt for the unit test runner. For now, this new behavior will be behind the `--workspaces` flag. ## Related Issue(s) Fixes #
1 parent 86798a2 commit 8d9234b

File tree

13 files changed

+153
-17
lines changed

13 files changed

+153
-17
lines changed

docs/generated/cli/create-nx-workspace.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Install `create-nx-workspace` globally to invoke the command directly, or use `n
4444
| `--ssr` | boolean | Enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) for the Angular application. |
4545
| `--standaloneApi` | boolean | Use Standalone Components if generating an Angular app. (Default: `true`) |
4646
| `--style` | string | Stylesheet type to be used with certain stacks. |
47+
| `--unitTestRunner` | `jest`, `vitest`, `none` | Test runner to use for unit tests. |
4748
| `--useGitHub` | boolean | Will you be using GitHub as your git hosting provider? (Default: `false`) |
4849
| `--version` | boolean | Show version number. |
4950
| `--workspaces` | boolean | Use package manager workspaces. (Default: `false`) |

docs/generated/packages/nx/documents/create-nx-workspace.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Install `create-nx-workspace` globally to invoke the command directly, or use `n
4444
| `--ssr` | boolean | Enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) for the Angular application. |
4545
| `--standaloneApi` | boolean | Use Standalone Components if generating an Angular app. (Default: `true`) |
4646
| `--style` | string | Stylesheet type to be used with certain stacks. |
47+
| `--unitTestRunner` | `jest`, `vitest`, `none` | Test runner to use for unit tests. |
4748
| `--useGitHub` | boolean | Will you be using GitHub as your git hosting provider? (Default: `false`) |
4849
| `--version` | boolean | Show version number. |
4950
| `--workspaces` | boolean | Use package manager workspaces. (Default: `false`) |

docs/generated/packages/workspace/generators/new.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@
7070
"type": "boolean",
7171
"default": true
7272
},
73+
"unitTestRunner": {
74+
"description": "The tool to use for running unit tests.",
75+
"type": "string",
76+
"enum": ["jest", "vitest", "none"]
77+
},
7378
"e2eTestRunner": {
7479
"description": "The tool to use for running e2e tests.",
7580
"type": "string",

docs/generated/packages/workspace/generators/preset.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@
8787
"type": "boolean",
8888
"default": true
8989
},
90+
"unitTestRunner": {
91+
"description": "The tool to use for running unit tests.",
92+
"type": "string",
93+
"enum": ["jest", "vitest", "none"]
94+
},
9095
"e2eTestRunner": {
9196
"description": "The tool to use for running e2e tests.",
9297
"type": "string",

e2e/workspace-create/src/create-nx-workspace.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ describe('create-nx-workspace', () => {
223223
});
224224

225225
expectNoAngularDevkit();
226-
expectNoTsJestInJestConfig(wsName);
226+
checkFilesExist('vitest.workspace.ts');
227+
checkFilesDoNotExist('jest.config.ts');
227228
const packageJson = readJson('package.json');
228229
expect(packageJson.devDependencies['@nx/vite']).toBeDefined(); // vite should be default bundler
229230
expectCodeIsFormatted();

packages/angular/src/generators/application/lib/normalize-options.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export async function normalizeOptions(
3939
inlineTemplate: false,
4040
skipTests: options.unitTestRunner === UnitTestRunner.None,
4141
skipFormat: false,
42-
unitTestRunner: UnitTestRunner.Jest,
4342
e2eTestRunner: E2eTestRunner.Playwright,
4443
linter: Linter.EsLint,
4544
strict: true,
@@ -59,5 +58,6 @@ export async function normalizeOptions(
5958
!options.rootProject ? appProjectRoot : appProjectName
6059
),
6160
ssr: options.ssr ?? false,
61+
unitTestRunner: options.unitTestRunner ?? UnitTestRunner.Jest,
6262
};
6363
}

packages/create-nx-workspace/bin/create-nx-workspace.ts

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ interface ReactArguments extends BaseArguments {
5353
bundler: 'webpack' | 'vite' | 'rspack';
5454
nextAppDir: boolean;
5555
nextSrcDir: boolean;
56+
unitTestRunner: 'none' | 'jest' | 'vitest';
5657
e2eTestRunner: 'none' | 'cypress' | 'playwright';
5758
}
5859

@@ -63,6 +64,7 @@ interface AngularArguments extends BaseArguments {
6364
style: string;
6465
routing: boolean;
6566
standaloneApi: boolean;
67+
unitTestRunner: 'none' | 'jest' | 'vitest';
6668
e2eTestRunner: 'none' | 'cypress' | 'playwright';
6769
bundler: 'webpack' | 'esbuild';
6870
ssr: boolean;
@@ -76,15 +78,17 @@ interface VueArguments extends BaseArguments {
7678
appName: string;
7779
framework: 'none' | 'nuxt';
7880
style: string;
81+
unitTestRunner: 'none' | 'vitest';
7982
e2eTestRunner: 'none' | 'cypress' | 'playwright';
8083
}
8184

8285
interface NodeArguments extends BaseArguments {
8386
stack: 'node';
8487
workspaceType: 'standalone' | 'integrated';
8588
appName: string;
86-
framework: 'express' | 'fastify' | 'koa' | 'nest';
89+
framework: 'none' | 'express' | 'fastify' | 'koa' | 'nest';
8790
docker: boolean;
91+
unitTestRunner: 'none' | 'jest';
8892
}
8993

9094
interface UnknownStackArguments extends BaseArguments {
@@ -190,6 +194,11 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
190194
choices: ['playwright', 'cypress', 'none'],
191195
type: 'string',
192196
})
197+
.option('unitTestRunner', {
198+
describe: chalk.dim`Test runner to use for unit tests.`,
199+
choices: ['jest', 'vitest', 'none'],
200+
type: 'string',
201+
})
193202
.option('ssr', {
194203
describe: chalk.dim`Enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) for the Angular application.`,
195204
type: 'boolean',
@@ -568,11 +577,12 @@ async function determineNoneOptions(
568577

569578
async function determineReactOptions(
570579
parsedArgs: yargs.Arguments<ReactArguments>
571-
): Promise<Partial<Arguments>> {
580+
): Promise<Partial<ReactArguments>> {
572581
let preset: Preset;
573582
let style: undefined | string = undefined;
574583
let appName: string;
575584
let bundler: undefined | 'webpack' | 'vite' | 'rspack' = undefined;
585+
let unitTestRunner: undefined | 'none' | 'jest' | 'vitest' = undefined;
576586
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
577587
let nextAppDir = false;
578588
let nextSrcDir = false;
@@ -633,17 +643,29 @@ async function determineReactOptions(
633643

634644
if (preset === Preset.ReactStandalone || preset === Preset.ReactMonorepo) {
635645
bundler = await determineReactBundler(parsedArgs);
646+
unitTestRunner = await determineUnitTestRunner(parsedArgs, {
647+
preferVitest: bundler === 'vite',
648+
});
636649
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
637650
} else if (preset === Preset.NextJs || preset === Preset.NextJsStandalone) {
638651
nextAppDir = await determineNextAppDir(parsedArgs);
639652
nextSrcDir = await determineNextSrcDir(parsedArgs);
653+
unitTestRunner = await determineUnitTestRunner(parsedArgs, {
654+
exclude: 'vitest',
655+
});
640656
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
641657
} else if (
642658
preset === Preset.RemixMonorepo ||
643-
preset === Preset.RemixStandalone ||
644-
preset === Preset.ReactNative ||
645-
preset === Preset.Expo
659+
preset === Preset.RemixStandalone
646660
) {
661+
unitTestRunner = await determineUnitTestRunner(parsedArgs, {
662+
preferVitest: true,
663+
});
664+
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
665+
} else if (preset === Preset.ReactNative || preset === Preset.Expo) {
666+
unitTestRunner = await determineUnitTestRunner(parsedArgs, {
667+
exclude: 'vitest',
668+
});
647669
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
648670
}
649671

@@ -715,6 +737,7 @@ async function determineReactOptions(
715737
bundler,
716738
nextAppDir,
717739
nextSrcDir,
740+
unitTestRunner,
718741
e2eTestRunner,
719742
linter,
720743
formatter,
@@ -724,10 +747,11 @@ async function determineReactOptions(
724747

725748
async function determineVueOptions(
726749
parsedArgs: yargs.Arguments<VueArguments>
727-
): Promise<Partial<Arguments>> {
750+
): Promise<Partial<VueArguments>> {
728751
let preset: Preset;
729752
let style: undefined | string = undefined;
730753
let appName: string;
754+
let unitTestRunner: undefined | 'none' | 'vitest' = undefined;
731755
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
732756
let linter: undefined | 'none' | 'eslint';
733757
let formatter: undefined | 'none' | 'prettier';
@@ -768,6 +792,9 @@ async function determineVueOptions(
768792
}
769793
}
770794

795+
unitTestRunner = await determineUnitTestRunner(parsedArgs, {
796+
exclude: 'jest',
797+
});
771798
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
772799

773800
if (parsedArgs.style) {
@@ -815,6 +842,7 @@ async function determineVueOptions(
815842
preset,
816843
style,
817844
appName,
845+
unitTestRunner,
818846
e2eTestRunner,
819847
linter,
820848
formatter,
@@ -824,10 +852,11 @@ async function determineVueOptions(
824852

825853
async function determineAngularOptions(
826854
parsedArgs: yargs.Arguments<AngularArguments>
827-
): Promise<Partial<Arguments>> {
855+
): Promise<Partial<AngularArguments>> {
828856
let preset: Preset;
829857
let style: string;
830858
let appName: string;
859+
let unitTestRunner: undefined | 'none' | 'jest' | 'vitest' = undefined;
831860
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
832861
let bundler: undefined | 'webpack' | 'esbuild' = undefined;
833862
let ssr: undefined | boolean = undefined;
@@ -965,6 +994,7 @@ async function determineAngularOptions(
965994
serverRouting = false;
966995
}
967996

997+
unitTestRunner = await determineUnitTestRunner(parsedArgs);
968998
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
969999

9701000
return {
@@ -973,6 +1003,7 @@ async function determineAngularOptions(
9731003
appName,
9741004
standaloneApi,
9751005
routing,
1006+
unitTestRunner,
9761007
e2eTestRunner,
9771008
bundler,
9781009
ssr,
@@ -983,14 +1014,14 @@ async function determineAngularOptions(
9831014

9841015
async function determineNodeOptions(
9851016
parsedArgs: yargs.Arguments<NodeArguments>
986-
): Promise<Partial<Arguments>> {
1017+
): Promise<Partial<NodeArguments>> {
9871018
let preset: Preset;
9881019
let appName: string;
9891020
let framework: 'express' | 'fastify' | 'koa' | 'nest' | 'none';
9901021
let docker: boolean;
9911022
let linter: undefined | 'none' | 'eslint';
9921023
let formatter: undefined | 'none' | 'prettier';
993-
1024+
let unitTestRunner: undefined | 'none' | 'jest' = undefined;
9941025
const workspaces = parsedArgs.workspaces ?? false;
9951026

9961027
if (parsedArgs.preset) {
@@ -1051,6 +1082,10 @@ async function determineNodeOptions(
10511082
docker = reply.docker === 'Yes';
10521083
}
10531084

1085+
unitTestRunner = await determineUnitTestRunner(parsedArgs, {
1086+
exclude: 'vitest',
1087+
});
1088+
10541089
if (workspaces) {
10551090
linter = await determineLinterOptions(parsedArgs);
10561091
formatter = await determineFormatterOptions(parsedArgs);
@@ -1067,6 +1102,7 @@ async function determineNodeOptions(
10671102
linter,
10681103
formatter,
10691104
workspaces,
1105+
unitTestRunner,
10701106
};
10711107
}
10721108

@@ -1358,6 +1394,60 @@ async function determineNodeFramework(
13581394
return reply.framework;
13591395
}
13601396

1397+
async function determineUnitTestRunner<T extends 'none' | 'jest' | 'vitest'>(
1398+
parsedArgs: yargs.Arguments<{
1399+
bundler?: 'vite' | string;
1400+
unitTestRunner?: T;
1401+
workspaces?: boolean;
1402+
}>,
1403+
options?: {
1404+
exclude?: 'jest' | 'vitest';
1405+
preferVitest?: boolean;
1406+
}
1407+
): Promise<T | undefined> {
1408+
if (parsedArgs.unitTestRunner) {
1409+
return parsedArgs.unitTestRunner;
1410+
} else if (!parsedArgs.workspaces) {
1411+
return undefined;
1412+
}
1413+
1414+
const reply = await enquirer.prompt<{
1415+
unitTestRunner: 'none' | 'jest' | 'vitest';
1416+
}>([
1417+
{
1418+
message: 'Which unit test runner would you like to use?',
1419+
type: 'autocomplete',
1420+
name: 'unitTestRunner',
1421+
skip: !parsedArgs.interactive || isCI(),
1422+
choices: [
1423+
{
1424+
name: 'none',
1425+
message: 'None',
1426+
},
1427+
{
1428+
name: 'jest',
1429+
message: 'Jest [ https://jestjs.io/ ]',
1430+
},
1431+
{
1432+
name: 'vitest',
1433+
message: 'Vitest [ https://vitest.dev/ ]',
1434+
},
1435+
]
1436+
.filter((t) => !options?.exclude || options.exclude !== t.name)
1437+
.sort((a, b) => {
1438+
if (a.name === 'none') return -1;
1439+
if (b.name === 'none') return 1;
1440+
if (options?.preferVitest && a.name === 'vitest') return -1;
1441+
if (options?.preferVitest && b.name === 'vitest') return 1;
1442+
return 0;
1443+
}),
1444+
initial: 0,
1445+
},
1446+
]);
1447+
1448+
return reply.unitTestRunner as T;
1449+
}
1450+
13611451
async function determineE2eTestRunner(
13621452
parsedArgs: yargs.Arguments<{
13631453
e2eTestRunner?: 'none' | 'cypress' | 'playwright';

packages/workspace/src/generators/new/generate-preset.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) {
8888
: null,
8989
parsedArgs.interactive ? '--interactive=true' : '--interactive=false',
9090
opts.routing !== undefined ? `--routing=${opts.routing}` : null,
91+
opts.unitTestRunner !== undefined
92+
? `--unitTestRunner=${opts.unitTestRunner}`
93+
: null,
9194
opts.e2eTestRunner !== undefined
9295
? `--e2eTestRunner=${opts.e2eTestRunner}`
9396
: null,

packages/workspace/src/generators/new/new.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ interface Schema {
3232
standaloneApi?: boolean;
3333
routing?: boolean;
3434
packageManager?: PackageManager;
35+
unitTestRunner?: 'jest' | 'vitest' | 'none';
3536
e2eTestRunner?: 'cypress' | 'playwright' | 'detox' | 'jest' | 'none';
3637
ssr?: boolean;
3738
serverRouting?: boolean;

0 commit comments

Comments
 (0)