From 6f542f1fa44eb31c61d5581fdadccb32093ad4dc Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Wed, 19 Jul 2023 19:05:08 -0400 Subject: [PATCH] feat(testing): prompt e2eTestRunner playwright --- docs/generated/cli/create-nx-workspace.md | 8 +++ .../nx/documents/create-nx-workspace.md | 8 +++ .../packages/workspace/generators/new.json | 2 +- .../packages/workspace/generators/preset.json | 2 +- e2e/storybook/src/storybook-nested.test.ts | 1 + e2e/utils/create-project-utils.ts | 6 +++ .../src/create-nx-workspace.test.ts | 13 ++++- .../bin/create-nx-workspace.ts | 49 ++++++++++++++++++- .../init/implementation/react/index.ts | 2 +- packages/workspace/src/generators/new/new.ts | 2 +- .../workspace/src/generators/new/schema.json | 2 +- .../src/generators/preset/schema.d.ts | 2 +- .../src/generators/preset/schema.json | 2 +- 13 files changed, 89 insertions(+), 10 deletions(-) diff --git a/docs/generated/cli/create-nx-workspace.md b/docs/generated/cli/create-nx-workspace.md index ddb7a06eece486..74c10904808c6e 100644 --- a/docs/generated/cli/create-nx-workspace.md +++ b/docs/generated/cli/create-nx-workspace.md @@ -79,6 +79,14 @@ Type: `boolean` Generate a Dockerfile for the Node API +### e2eTestRunner + +Type: `string` + +Choices: [cypress, playwright, none] + +Test runner to use for end to end (E2E) tests. + ### framework Type: `string` diff --git a/docs/generated/packages/nx/documents/create-nx-workspace.md b/docs/generated/packages/nx/documents/create-nx-workspace.md index ddb7a06eece486..74c10904808c6e 100644 --- a/docs/generated/packages/nx/documents/create-nx-workspace.md +++ b/docs/generated/packages/nx/documents/create-nx-workspace.md @@ -79,6 +79,14 @@ Type: `boolean` Generate a Dockerfile for the Node API +### e2eTestRunner + +Type: `string` + +Choices: [cypress, playwright, none] + +Test runner to use for end to end (E2E) tests. + ### framework Type: `string` diff --git a/docs/generated/packages/workspace/generators/new.json b/docs/generated/packages/workspace/generators/new.json index 8a2e3b646eed3b..83420a5a10715c 100644 --- a/docs/generated/packages/workspace/generators/new.json +++ b/docs/generated/packages/workspace/generators/new.json @@ -73,7 +73,7 @@ "e2eTestRunner": { "description": "The tool to use for running e2e tests.", "type": "string", - "enum": ["cypress", "jest", "detox", "none"] + "enum": ["cypress", "playwright", "jest", "detox", "none"] } }, "additionalProperties": true, diff --git a/docs/generated/packages/workspace/generators/preset.json b/docs/generated/packages/workspace/generators/preset.json index 4d7ebca3659a02..2e1376287c3b9a 100644 --- a/docs/generated/packages/workspace/generators/preset.json +++ b/docs/generated/packages/workspace/generators/preset.json @@ -85,7 +85,7 @@ "e2eTestRunner": { "description": "The tool to use for running e2e tests.", "type": "string", - "enum": ["cypress", "jest", "detox", "none"] + "enum": ["cypress", "playwright", "jest", "detox", "none"] } }, "required": ["preset", "name"], diff --git a/e2e/storybook/src/storybook-nested.test.ts b/e2e/storybook/src/storybook-nested.test.ts index a40db2abfcd3fe..8ce7e6443a5d56 100644 --- a/e2e/storybook/src/storybook-nested.test.ts +++ b/e2e/storybook/src/storybook-nested.test.ts @@ -24,6 +24,7 @@ describe('Storybook generators and executors for standalone workspaces - using R style: 'css', bundler: 'vite', packageManager: getSelectedPackageManager(), + e2eTestRunner: 'none', }); runCLI( diff --git a/e2e/utils/create-project-utils.ts b/e2e/utils/create-project-utils.ts index e5df3310a42648..f9b9a604a6aaa7 100644 --- a/e2e/utils/create-project-utils.ts +++ b/e2e/utils/create-project-utils.ts @@ -138,6 +138,7 @@ export function runCreateWorkspace( standaloneApi, docker, nextAppDir, + e2eTestRunner, }: { preset: string; appName?: string; @@ -153,6 +154,7 @@ export function runCreateWorkspace( routing?: boolean; docker?: boolean; nextAppDir?: boolean; + e2eTestRunner?: 'cypress' | 'playwright' | 'jest' | 'detox' | 'none'; } ) { projName = name; @@ -198,6 +200,10 @@ export function runCreateWorkspace( command += ` --package-manager=${packageManager}`; } + if (e2eTestRunner) { + command += ` --e2eTestRunner=${e2eTestRunner}`; + } + if (extraArgs) { command += ` ${extraArgs}`; } diff --git a/e2e/workspace-create/src/create-nx-workspace.test.ts b/e2e/workspace-create/src/create-nx-workspace.test.ts index fc78558f8b8632..8dbd7f71260f77 100644 --- a/e2e/workspace-create/src/create-nx-workspace.test.ts +++ b/e2e/workspace-create/src/create-nx-workspace.test.ts @@ -31,6 +31,7 @@ describe('create-nx-workspace', () => { packageManager, standaloneApi: false, routing: false, + e2eTestRunner: 'none', }); checkFilesExist('package.json'); @@ -50,6 +51,7 @@ describe('create-nx-workspace', () => { packageManager, standaloneApi: true, routing: true, + e2eTestRunner: 'none', }); checkFilesExist('package.json'); @@ -68,6 +70,7 @@ describe('create-nx-workspace', () => { style: 'css', packageManager, bundler: 'vite', + e2eTestRunner: 'none', }); checkFilesExist('package.json'); @@ -77,7 +80,7 @@ describe('create-nx-workspace', () => { expectCodeIsFormatted(); }); - it('should create a workspace with a single react app with webpack at the root', () => { + it('should create a workspace with a single react app with webpack and playwright at the root', () => { const wsName = uniq('react'); runCreateWorkspace(wsName, { @@ -86,6 +89,7 @@ describe('create-nx-workspace', () => { style: 'css', packageManager, bundler: 'webpack', + e2eTestRunner: 'playwright', }); checkFilesExist('package.json'); @@ -144,6 +148,7 @@ describe('create-nx-workspace', () => { packageManager, standaloneApi: false, routing: true, + e2eTestRunner: 'none', }); expectCodeIsFormatted(); }); @@ -162,6 +167,7 @@ describe('create-nx-workspace', () => { packageManager, standaloneApi: false, routing: false, + e2eTestRunner: 'none', }) ).toThrow(); }); @@ -176,6 +182,7 @@ describe('create-nx-workspace', () => { appName, packageManager, bundler: 'webpack', + e2eTestRunner: 'none', }); expectNoAngularDevkit(); @@ -195,6 +202,7 @@ describe('create-nx-workspace', () => { appName, packageManager, bundler: 'vite', + e2eTestRunner: 'none', }); expectNoAngularDevkit(); @@ -213,6 +221,7 @@ describe('create-nx-workspace', () => { appName, nextAppDir: false, packageManager, + e2eTestRunner: 'none', }); checkFilesExist(`apps/${appName}/pages/index.tsx`); @@ -230,6 +239,7 @@ describe('create-nx-workspace', () => { nextAppDir: true, appName, packageManager, + e2eTestRunner: 'none', }); checkFilesExist('app/page.tsx'); @@ -247,6 +257,7 @@ describe('create-nx-workspace', () => { nextAppDir: false, appName, packageManager, + e2eTestRunner: 'none', }); checkFilesExist('pages/index.tsx'); diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index 5b3143c5093a0f..9c4336a2091035 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -49,6 +49,7 @@ interface ReactArguments extends BaseArguments { style: string; bundler: 'webpack' | 'vite' | 'rspack'; nextAppDir: boolean; + e2eTestRunner: 'none' | 'cypress' | 'playwright'; } interface AngularArguments extends BaseArguments { @@ -58,6 +59,7 @@ interface AngularArguments extends BaseArguments { style: string; routing: boolean; standaloneApi: boolean; + e2eTestRunner: 'none' | 'cypress' | 'playwright'; } interface NodeArguments extends BaseArguments { @@ -147,6 +149,11 @@ export const commandsObject: yargs.Argv = yargs .option('nextAppDir', { describe: chalk.dim`Enable the App Router for Next.js`, type: 'boolean', + }) + .option('e2eTestRunner', { + describe: chalk.dim`Test runner to use for end to end (E2E) tests.`, + choices: ['cypress', 'playwright', 'none'], + type: 'string', }), withNxCloud, withCI, @@ -448,6 +455,7 @@ async function determineReactOptions( let style: undefined | string = undefined; let appName: string; let bundler: undefined | 'webpack' | 'vite' | 'rspack' = undefined; + let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined; let nextAppDir = false; if (parsedArgs.preset && parsedArgs.preset !== Preset.React) { @@ -497,8 +505,10 @@ async function determineReactOptions( if (preset === Preset.ReactStandalone || preset === Preset.ReactMonorepo) { bundler = await determineReactBundler(parsedArgs); + e2eTestRunner = await determineE2eTestRunner(parsedArgs); } else if (preset === Preset.NextJs || preset === Preset.NextJsStandalone) { nextAppDir = await determineNextAppDir(parsedArgs); + e2eTestRunner = await determineE2eTestRunner(parsedArgs); } if (parsedArgs.style) { @@ -549,7 +559,7 @@ async function determineReactOptions( style = reply.style; } - return { preset, style, appName, bundler, nextAppDir }; + return { preset, style, appName, bundler, nextAppDir, e2eTestRunner }; } async function determineAngularOptions( @@ -559,6 +569,7 @@ async function determineAngularOptions( let style: string; let appName: string; let standaloneApi: boolean; + let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined; let routing: boolean; if (parsedArgs.preset && parsedArgs.preset !== Preset.Angular) { @@ -609,6 +620,8 @@ async function determineAngularOptions( style = reply.style; } + e2eTestRunner = await determineE2eTestRunner(parsedArgs); + if (parsedArgs.standaloneApi !== undefined) { standaloneApi = parsedArgs.standaloneApi; } else { @@ -655,7 +668,7 @@ async function determineAngularOptions( routing = reply.routing === 'Yes'; } - return { preset, style, appName, standaloneApi, routing }; + return { preset, style, appName, standaloneApi, routing, e2eTestRunner }; } async function determineNodeOptions( @@ -950,3 +963,35 @@ async function determineNodeFramework( ]); return reply.framework; } + +async function determineE2eTestRunner( + parsedArgs: yargs.Arguments<{ + e2eTestRunner?: 'none' | 'cypress' | 'playwright'; + }> +): Promise<'none' | 'cypress' | 'playwright'> { + if (parsedArgs.e2eTestRunner) return parsedArgs.e2eTestRunner; + const reply = await enquirer.prompt<{ + e2eTestRunner: 'none' | 'cypress' | 'playwright'; + }>([ + { + message: 'Test runner to use for end to end (E2E) tests', + type: 'autocomplete', + name: 'e2eTestRunner', + choices: [ + { + name: 'cypress', + message: 'Cypress [ https://www.cypress.io/ ]', + }, + { + name: 'playwright', + message: 'Playwright [ https://playwright.dev/ ]', + }, + { + name: 'none', + message: 'None', + }, + ], + }, + ]); + return reply.e2eTestRunner; +} diff --git a/packages/nx/src/command-line/init/implementation/react/index.ts b/packages/nx/src/command-line/init/implementation/react/index.ts index 44f7d8167bbd48..c1d9750088686b 100644 --- a/packages/nx/src/command-line/init/implementation/react/index.ts +++ b/packages/nx/src/command-line/init/implementation/react/index.ts @@ -185,7 +185,7 @@ function createTempWorkspace(options: NormalizedOptions) { options.isVite ? 'vite' : 'webpack' } --packageManager=${options.packageManager} ${ options.nxCloud ? '--nxCloud' : '--nxCloud=false' - }`, + } ${options.addE2e ? '--e2eTestRunner=cypress' : '--e2eTestRunner=none'}`, { stdio: [0, 1, 2] } ); diff --git a/packages/workspace/src/generators/new/new.ts b/packages/workspace/src/generators/new/new.ts index f409feb6e2efb7..d4483a5a1897f9 100644 --- a/packages/workspace/src/generators/new/new.ts +++ b/packages/workspace/src/generators/new/new.ts @@ -30,7 +30,7 @@ interface Schema { standaloneApi?: boolean; routing?: boolean; packageManager?: PackageManager; - e2eTestRunner?: 'cypress' | 'detox' | 'jest' | 'none'; + e2eTestRunner?: 'cypress' | 'playwright' | 'detox' | 'jest' | 'none'; } export interface NormalizedSchema extends Schema { diff --git a/packages/workspace/src/generators/new/schema.json b/packages/workspace/src/generators/new/schema.json index bf0d8bd40ac084..7e57cf06147546 100644 --- a/packages/workspace/src/generators/new/schema.json +++ b/packages/workspace/src/generators/new/schema.json @@ -76,7 +76,7 @@ "e2eTestRunner": { "description": "The tool to use for running e2e tests.", "type": "string", - "enum": ["cypress", "jest", "detox", "none"] + "enum": ["cypress", "playwright", "jest", "detox", "none"] } }, "additionalProperties": true diff --git a/packages/workspace/src/generators/preset/schema.d.ts b/packages/workspace/src/generators/preset/schema.d.ts index dd75bedfb54ff0..0f72d1030131c9 100644 --- a/packages/workspace/src/generators/preset/schema.d.ts +++ b/packages/workspace/src/generators/preset/schema.d.ts @@ -14,6 +14,6 @@ export interface Schema { nextAppDir?: boolean; routing?: boolean; standaloneApi?: boolean; - e2eTestRunner?: 'cypress' | 'jest' | 'detox' | 'none'; + e2eTestRunner?: 'cypress' | 'playwright' | 'jest' | 'detox' | 'none'; js?: boolean; } diff --git a/packages/workspace/src/generators/preset/schema.json b/packages/workspace/src/generators/preset/schema.json index bde4a44af32360..57a8f5a81ca463 100644 --- a/packages/workspace/src/generators/preset/schema.json +++ b/packages/workspace/src/generators/preset/schema.json @@ -88,7 +88,7 @@ "e2eTestRunner": { "description": "The tool to use for running e2e tests.", "type": "string", - "enum": ["cypress", "jest", "detox", "none"] + "enum": ["cypress", "playwright", "jest", "detox", "none"] } }, "required": ["preset", "name"]