feat(react): add playwright to e2eTestRunner option (#18200)
This commit is contained in:
parent
f1a90bfd1c
commit
24b1ab5463
@ -111,8 +111,9 @@
|
|||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "none"],
|
"enum": ["cypress", "playwright", "none"],
|
||||||
"description": "Test runner to use for end to end (E2E) tests.",
|
"description": "Test runner to use for end to end (E2E) tests.",
|
||||||
|
"x-prompt": "Which E2E test runner would you like to use?",
|
||||||
"default": "cypress"
|
"default": "cypress"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"description": "Adds the specified E2E test runner.",
|
"description": "Adds the specified E2E test runner.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "none"],
|
"enum": ["cypress", "playwright", "none"],
|
||||||
"default": "cypress"
|
"default": "cypress"
|
||||||
},
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
|
|||||||
@ -47,6 +47,7 @@
|
|||||||
"react",
|
"react",
|
||||||
// These are installed by ensurePackage so missing in package.json
|
// These are installed by ensurePackage so missing in package.json
|
||||||
"@nx/cypress",
|
"@nx/cypress",
|
||||||
|
"@nx/playwright",
|
||||||
"@nx/jest",
|
"@nx/jest",
|
||||||
"@nx/rollup",
|
"@nx/rollup",
|
||||||
"@nx/storybook",
|
"@nx/storybook",
|
||||||
|
|||||||
@ -267,6 +267,24 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
].forEach(hasJsonValue);
|
].forEach(hasJsonValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should setup playwright', async () => {
|
||||||
|
await applicationGenerator(appTree, {
|
||||||
|
...schema,
|
||||||
|
directory: 'myDir',
|
||||||
|
e2eTestRunner: 'playwright',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
appTree.exists('apps/my-dir/my-app-e2e/playwright.config.ts')
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
appTree.exists('apps/my-dir/my-app-e2e/src/example.spec.ts')
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
readProjectConfiguration(appTree, 'my-app-e2e')?.targets?.e2e?.executor
|
||||||
|
).toEqual('@nx/playwright:playwright');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create Nx specific template', async () => {
|
it('should create Nx specific template', async () => {
|
||||||
@ -332,7 +350,7 @@ describe('app', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setup the nrwl web build builder', async () => {
|
it('should setup the nx web build builder', async () => {
|
||||||
await applicationGenerator(appTree, {
|
await applicationGenerator(appTree, {
|
||||||
...schema,
|
...schema,
|
||||||
name: 'my-app',
|
name: 'my-app',
|
||||||
@ -372,7 +390,7 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setup the nrwl vite builder if bundler is vite', async () => {
|
it('should setup the nx vite builder if bundler is vite', async () => {
|
||||||
await applicationGenerator(appTree, {
|
await applicationGenerator(appTree, {
|
||||||
...schema,
|
...schema,
|
||||||
name: 'my-app',
|
name: 'my-app',
|
||||||
@ -394,7 +412,7 @@ describe('app', () => {
|
|||||||
).toBeFalsy();
|
).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setup the nrwl web dev server builder', async () => {
|
it('should setup the nx web dev server builder', async () => {
|
||||||
await applicationGenerator(appTree, {
|
await applicationGenerator(appTree, {
|
||||||
...schema,
|
...schema,
|
||||||
name: 'my-app',
|
name: 'my-app',
|
||||||
@ -414,7 +432,7 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setup the nrwl vite dev server builder if bundler is vite', async () => {
|
it('should setup the nx vite dev server builder if bundler is vite', async () => {
|
||||||
await applicationGenerator(appTree, {
|
await applicationGenerator(appTree, {
|
||||||
...schema,
|
...schema,
|
||||||
name: 'my-app',
|
name: 'my-app',
|
||||||
@ -486,6 +504,25 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('--e2e-test-runner playwright', () => {
|
||||||
|
it('should setup playwright', async () => {
|
||||||
|
await applicationGenerator(appTree, {
|
||||||
|
...schema,
|
||||||
|
e2eTestRunner: 'playwright',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
appTree.exists('apps/my-app-e2e/playwright.config.ts')
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
appTree.exists('apps/my-app-e2e/src/example.spec.ts')
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
readProjectConfiguration(appTree, 'my-app-e2e')?.targets?.e2e?.executor
|
||||||
|
).toEqual('@nx/playwright:playwright');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('--pascalCaseFiles', () => {
|
describe('--pascalCaseFiles', () => {
|
||||||
it('should use upper case app file', async () => {
|
it('should use upper case app file', async () => {
|
||||||
await applicationGenerator(appTree, { ...schema, pascalCaseFiles: true });
|
await applicationGenerator(appTree, { ...schema, pascalCaseFiles: true });
|
||||||
@ -950,6 +987,21 @@ describe('app', () => {
|
|||||||
]
|
]
|
||||||
).toEqual('dist/my-app2');
|
).toEqual('dist/my-app2');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should setup playwright', async () => {
|
||||||
|
await applicationGenerator(appTree, {
|
||||||
|
...schema,
|
||||||
|
name: 'my-app3',
|
||||||
|
rootProject: true,
|
||||||
|
e2eTestRunner: 'playwright',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(appTree.exists('e2e/playwright.config.ts')).toBeTruthy();
|
||||||
|
expect(appTree.exists('e2e/src/example.spec.ts')).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
readProjectConfiguration(appTree, 'e2e')?.targets?.e2e?.executor
|
||||||
|
).toEqual('@nx/playwright:playwright');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('setup React app with --bundler=vite', () => {
|
describe('setup React app with --bundler=vite', () => {
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import { createApplicationFiles } from './lib/create-application-files';
|
|||||||
import { updateSpecConfig } from './lib/update-jest-config';
|
import { updateSpecConfig } from './lib/update-jest-config';
|
||||||
import { normalizeOptions } from './lib/normalize-options';
|
import { normalizeOptions } from './lib/normalize-options';
|
||||||
import { addProject, maybeJs } from './lib/add-project';
|
import { addProject, maybeJs } from './lib/add-project';
|
||||||
import { addCypress } from './lib/add-cypress';
|
|
||||||
import { addJest } from './lib/add-jest';
|
import { addJest } from './lib/add-jest';
|
||||||
import { addRouting } from './lib/add-routing';
|
import { addRouting } from './lib/add-routing';
|
||||||
import { setDefaults } from './lib/set-defaults';
|
import { setDefaults } from './lib/set-defaults';
|
||||||
@ -39,6 +38,7 @@ import { extractTsConfigBase } from '../../utils/create-ts-config';
|
|||||||
import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
||||||
import * as chalk from 'chalk';
|
import * as chalk from 'chalk';
|
||||||
import { showPossibleWarnings } from './lib/show-possible-warnings';
|
import { showPossibleWarnings } from './lib/show-possible-warnings';
|
||||||
|
import { addE2e } from './lib/add-e2e';
|
||||||
|
|
||||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -70,7 +70,7 @@ async function addLinting(host: Tree, options: NormalizedSchema) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
const installTask = await addDependenciesToPackageJson(
|
const installTask = addDependenciesToPackageJson(
|
||||||
host,
|
host,
|
||||||
extraEslintDependencies.dependencies,
|
extraEslintDependencies.dependencies,
|
||||||
extraEslintDependencies.devDependencies
|
extraEslintDependencies.devDependencies
|
||||||
@ -189,8 +189,8 @@ export async function applicationGenerator(
|
|||||||
const lintTask = await addLinting(host, options);
|
const lintTask = await addLinting(host, options);
|
||||||
tasks.push(lintTask);
|
tasks.push(lintTask);
|
||||||
|
|
||||||
const cypressTask = await addCypress(host, options);
|
const e2eTask = await addE2e(host, options);
|
||||||
tasks.push(cypressTask);
|
tasks.push(e2eTask);
|
||||||
|
|
||||||
if (options.unitTestRunner === 'jest') {
|
if (options.unitTestRunner === 'jest') {
|
||||||
const jestTask = await addJest(host, options);
|
const jestTask = await addJest(host, options);
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
import { ensurePackage, Tree } from '@nx/devkit';
|
|
||||||
import { webStaticServeGenerator } from '@nx/web';
|
|
||||||
import { nxVersion } from '../../../utils/versions';
|
|
||||||
import { NormalizedSchema } from '../schema';
|
|
||||||
|
|
||||||
export async function addCypress(host: Tree, options: NormalizedSchema) {
|
|
||||||
if (options.e2eTestRunner !== 'cypress') {
|
|
||||||
return () => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
await webStaticServeGenerator(host, {
|
|
||||||
buildTarget: `${options.projectName}:build`,
|
|
||||||
targetName: 'serve-static',
|
|
||||||
});
|
|
||||||
|
|
||||||
const { cypressProjectGenerator } = ensurePackage<
|
|
||||||
typeof import('@nx/cypress')
|
|
||||||
>('@nx/cypress', nxVersion);
|
|
||||||
|
|
||||||
return await cypressProjectGenerator(host, {
|
|
||||||
...options,
|
|
||||||
name: options.e2eProjectName,
|
|
||||||
directory: options.directory,
|
|
||||||
project: options.projectName,
|
|
||||||
bundler: options.bundler === 'rspack' ? 'webpack' : options.bundler,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
63
packages/react/src/generators/application/lib/add-e2e.ts
Normal file
63
packages/react/src/generators/application/lib/add-e2e.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
|
import {
|
||||||
|
addProjectConfiguration,
|
||||||
|
ensurePackage,
|
||||||
|
getPackageManagerCommand,
|
||||||
|
joinPathFragments,
|
||||||
|
readProjectConfiguration,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { webStaticServeGenerator } from '@nx/web';
|
||||||
|
|
||||||
|
import { nxVersion } from '../../../utils/versions';
|
||||||
|
import { NormalizedSchema } from '../schema';
|
||||||
|
|
||||||
|
export async function addE2e(
|
||||||
|
tree: Tree,
|
||||||
|
options: NormalizedSchema
|
||||||
|
): Promise<GeneratorCallback> {
|
||||||
|
switch (options.e2eTestRunner) {
|
||||||
|
case 'cypress':
|
||||||
|
webStaticServeGenerator(tree, {
|
||||||
|
buildTarget: `${options.projectName}:build`,
|
||||||
|
targetName: 'serve-static',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { cypressProjectGenerator } = ensurePackage<
|
||||||
|
typeof import('@nx/cypress')
|
||||||
|
>('@nx/cypress', nxVersion);
|
||||||
|
|
||||||
|
return await cypressProjectGenerator(tree, {
|
||||||
|
...options,
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
directory: options.directory,
|
||||||
|
project: options.projectName,
|
||||||
|
bundler: options.bundler === 'rspack' ? 'webpack' : options.bundler,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
case 'playwright':
|
||||||
|
const { configurationGenerator } = ensurePackage<
|
||||||
|
typeof import('@nx/playwright')
|
||||||
|
>('@nx/playwright', nxVersion);
|
||||||
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
||||||
|
root: options.e2eProjectRoot,
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
targets: {},
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
});
|
||||||
|
return configurationGenerator(tree, {
|
||||||
|
project: options.e2eProjectName,
|
||||||
|
skipFormat: true,
|
||||||
|
skipPackageJson: options.skipPackageJson,
|
||||||
|
directory: 'src',
|
||||||
|
js: false,
|
||||||
|
linter: options.linter,
|
||||||
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
|
webServerCommand: `${getPackageManagerCommand().exec} nx serve ${
|
||||||
|
options.name
|
||||||
|
}`,
|
||||||
|
});
|
||||||
|
case 'none':
|
||||||
|
default:
|
||||||
|
return () => {};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ import { assertValidStyle } from '../../../utils/assertion';
|
|||||||
import {
|
import {
|
||||||
extractLayoutDirectory,
|
extractLayoutDirectory,
|
||||||
getWorkspaceLayout,
|
getWorkspaceLayout,
|
||||||
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
normalizePath,
|
normalizePath,
|
||||||
Tree,
|
Tree,
|
||||||
@ -36,6 +37,9 @@ export function normalizeOptions<T extends Schema = Schema>(
|
|||||||
const appProjectRoot = options.rootProject
|
const appProjectRoot = options.rootProject
|
||||||
? '.'
|
? '.'
|
||||||
: normalizePath(`${appsDir}/${appDirectory}`);
|
: normalizePath(`${appsDir}/${appDirectory}`);
|
||||||
|
const e2eProjectRoot = options.rootProject
|
||||||
|
? 'e2e'
|
||||||
|
: joinPathFragments(appsDir, `${appDirectory}-e2e`);
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
@ -59,6 +63,7 @@ export function normalizeOptions<T extends Schema = Schema>(
|
|||||||
projectName: appProjectName,
|
projectName: appProjectName,
|
||||||
appProjectRoot,
|
appProjectRoot,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
|
e2eProjectRoot,
|
||||||
parsedTags,
|
parsedTags,
|
||||||
fileName,
|
fileName,
|
||||||
styledModule,
|
styledModule,
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export interface Schema {
|
|||||||
tags?: string;
|
tags?: string;
|
||||||
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
||||||
inSourceTests?: boolean;
|
inSourceTests?: boolean;
|
||||||
e2eTestRunner: 'cypress' | 'none';
|
e2eTestRunner: 'cypress' | 'playwright' | 'none';
|
||||||
linter: Linter;
|
linter: Linter;
|
||||||
pascalCaseFiles?: boolean;
|
pascalCaseFiles?: boolean;
|
||||||
classComponent?: boolean;
|
classComponent?: boolean;
|
||||||
@ -32,6 +32,7 @@ export interface NormalizedSchema<T extends Schema = Schema> extends T {
|
|||||||
projectName: string;
|
projectName: string;
|
||||||
appProjectRoot: string;
|
appProjectRoot: string;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
|
e2eProjectRoot: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
fileName: string;
|
fileName: string;
|
||||||
styledModule: null | SupportedStyles;
|
styledModule: null | SupportedStyles;
|
||||||
|
|||||||
@ -117,8 +117,9 @@
|
|||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "none"],
|
"enum": ["cypress", "playwright", "none"],
|
||||||
"description": "Test runner to use for end to end (E2E) tests.",
|
"description": "Test runner to use for end to end (E2E) tests.",
|
||||||
|
"x-prompt": "Which E2E test runner would you like to use?",
|
||||||
"default": "cypress"
|
"default": "cypress"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export interface InitSchema {
|
export interface InitSchema {
|
||||||
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
||||||
e2eTestRunner?: 'cypress' | 'none';
|
e2eTestRunner?: 'cypress' | 'playwright' | 'none';
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
skipHelperLibs?: boolean;
|
skipHelperLibs?: boolean;
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"description": "Adds the specified E2E test runner.",
|
"description": "Adds the specified E2E test runner.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "none"],
|
"enum": ["cypress", "playwright", "none"],
|
||||||
"default": "cypress"
|
"default": "cypress"
|
||||||
},
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user