feat(web): add playwright e2eTestRunner option (#18284)

This commit is contained in:
Caleb Ukle 2023-08-01 09:53:06 -05:00 committed by GitHub
parent e78575badc
commit 27923fd2d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 135 additions and 26 deletions

View File

@ -79,7 +79,8 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"x-prompt": "Which E2E test runner would you like to use?",
"description": "Test runner to use for end to end (e2e) tests",
"default": "cypress"
},

View File

@ -24,7 +24,8 @@
"e2eTestRunner": {
"description": "Adds the specified e2e test runner",
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"x-prompt": "Which E2E test runner would you like to use?",
"default": "cypress"
},
"skipFormat": {

View File

@ -3,6 +3,7 @@ import {
checkFilesExist,
cleanupProject,
createFile,
ensurePlaywrightBrowsersInstallation,
isNotWindows,
killPorts,
listFiles,
@ -98,6 +99,26 @@ describe('Web Components Applications', () => {
);
}, 500000);
it('should generate working playwright e2e app', async () => {
const appName = uniq('app');
runCLI(
`generate @nx/web:app ${appName} --bundler=webpack --e2eTestRunner=playwright --no-interactive`
);
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
expect(lintE2eResults).toContain('All files pass linting.');
if (isNotWindows() && runCypressTests()) {
ensurePlaywrightBrowsersInstallation();
const e2eResults = runCLI(`e2e ${appName}-e2e`);
expect(e2eResults).toContain(
`Successfully ran target e2e for project ${appName}-e2e`
);
expect(await killPorts()).toBeTruthy();
}
}, 500000);
it('should remove previous output before building', async () => {
const appName = uniq('app');
const libName = uniq('lib');

View File

@ -47,6 +47,7 @@
// Installed by ensurePackage
"@nx/linter",
"@nx/cypress",
"@nx/playwright",
"@nx/vite",
"@nx/webpack",
"@nx/jest"

View File

@ -8,6 +8,12 @@ import { Schema } from './schema';
// need to mock cypress otherwise it'll use the nx installed version from package.json
// which is v9 while we are testing for the new v10 version
jest.mock('@nx/cypress/src/utils/cypress-version');
jest.mock('@nx/devkit', () => {
return {
...jest.requireActual('@nx/devkit'),
ensurePackage: jest.fn((pkg) => jest.requireActual(pkg)),
};
});
describe('app', () => {
let tree: Tree;
let mockedInstalledCypressVersion: jest.Mock<
@ -135,6 +141,30 @@ describe('app', () => {
`);
});
it('should setup playwright e2e project', async () => {
await applicationGenerator(tree, {
name: 'cool-app',
e2eTestRunner: 'playwright',
unitTestRunner: 'none',
});
expect(readProjectConfiguration(tree, 'cool-app-e2e').targets.e2e)
.toMatchInlineSnapshot(`
{
"executor": "@nx/playwright:playwright",
"options": {
"config": "apps/cool-app-e2e/playwright.config.ts",
},
"outputs": [
"dist/.playwright/apps/cool-app-e2e",
],
}
`);
expect(
tree.exists('apps/cool-app-e2e/playwright.config.ts')
).toBeTruthy();
});
it('should generate files if bundler is vite', async () => {
await applicationGenerator(tree, {
name: 'myApp',

View File

@ -241,10 +241,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
}
if (options.linter === 'eslint') {
const { lintProjectGenerator } = await ensurePackage(
'@nx/linter',
nxVersion
);
const { lintProjectGenerator } = ensurePackage('@nx/linter', nxVersion);
const lintTask = await lintProjectGenerator(host, {
linter: options.linter,
project: options.projectName,
@ -260,7 +257,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
}
if (options.e2eTestRunner === 'cypress') {
const { cypressProjectGenerator } = await ensurePackage<
const { cypressProjectGenerator } = ensurePackage<
typeof import('@nx/cypress')
>('@nx/cypress', nxVersion);
const cypressTask = await cypressProjectGenerator(host, {
@ -271,11 +268,34 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
skipFormat: true,
});
tasks.push(cypressTask);
} else if (options.e2eTestRunner === 'playwright') {
const { configurationGenerator: playwrightConfigGenerator } = ensurePackage<
typeof import('@nx/playwright')
>('@nx/playwright', nxVersion);
addProjectConfiguration(host, options.e2eProjectName, {
root: options.e2eProjectRoot,
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
projectType: 'application',
targets: {},
implicitDependencies: [options.projectName],
});
const playwrightTask = await playwrightConfigGenerator(host, {
project: options.e2eProjectName,
skipFormat: true,
skipPackageJson: false,
directory: 'src',
js: false,
linter: options.linter,
setParserOptionsProject: options.setParserOptionsProject,
});
tasks.push(playwrightTask);
}
if (options.unitTestRunner === 'jest') {
const { configurationGenerator } = await ensurePackage<
typeof import('@nx/jest')
>('@nx/jest', nxVersion);
const { configurationGenerator } = ensurePackage<typeof import('@nx/jest')>(
'@nx/jest',
nxVersion
);
const jestTask = await configurationGenerator(host, {
project: options.projectName,
skipSerializers: true,

View File

@ -11,7 +11,7 @@ export interface Schema {
tags?: string;
unitTestRunner?: 'jest' | 'vitest' | 'none';
inSourceTests?: boolean;
e2eTestRunner?: 'cypress' | 'none';
e2eTestRunner?: 'cypress' | 'playwright' | 'none';
linter?: Linter;
standaloneConfig?: boolean;
setParserOptionsProject?: boolean;

View File

@ -82,7 +82,8 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"x-prompt": "Which E2E test runner would you like to use?",
"description": "Test runner to use for end to end (e2e) tests",
"default": "cypress"
},

View File

@ -1,15 +1,15 @@
import {
addDependenciesToPackageJson,
NxJsonConfiguration,
readJson,
Tree,
updateJson,
} from '@nx/devkit';
import { addDependenciesToPackageJson, readJson, Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { nxVersion } from '../../utils/versions';
import webInitGenerator from './init';
jest.mock('@nx/devkit', () => {
return {
...jest.requireActual('@nx/devkit'),
ensurePackage: jest.fn((pkg) => jest.requireActual(pkg)),
};
});
describe('init', () => {
let tree: Tree;
@ -45,4 +45,28 @@ describe('init', () => {
});
expect(tree.exists('jest.config.js')).toBe(false);
});
it('should init playwright', async () => {
await webInitGenerator(tree, {
e2eTestRunner: 'playwright',
});
expect(readJson(tree, 'package.json').devDependencies).toEqual(
expect.objectContaining({
'@nx/playwright': expect.any(String),
'@playwright/test': expect.any(String),
})
);
});
it('should init cypress', async () => {
await webInitGenerator(tree, {
e2eTestRunner: 'cypress',
});
expect(readJson(tree, 'package.json').devDependencies).toEqual(
expect.objectContaining({
'@nx/cypress': expect.any(String),
cypress: expect.any(String),
})
);
});
});

View File

@ -43,22 +43,31 @@ export async function webInitGenerator(tree: Tree, schema: Schema) {
tasks.push(jsInitTask);
if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') {
const { jestInitGenerator } = await ensurePackage('@nx/jest', nxVersion);
const { jestInitGenerator } = ensurePackage('@nx/jest', nxVersion);
const jestTask = await jestInitGenerator(tree, {
skipPackageJson: schema.skipPackageJson,
});
tasks.push(jestTask);
}
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
const { cypressInitGenerator } = await ensurePackage(
'@nx/cypress',
nxVersion
);
const { cypressInitGenerator } = ensurePackage('@nx/cypress', nxVersion);
const cypressTask = await cypressInitGenerator(tree, {
skipPackageJson: schema.skipPackageJson,
});
tasks.push(cypressTask);
} else if (schema.e2eTestRunner === 'playwright') {
const { initGenerator: playwrightInitGenerator } = ensurePackage<
typeof import('@nx/playwright')
>('@nx/playwright', nxVersion);
const playwrightConfigTask = await playwrightInitGenerator(tree, {
skipFormat: true,
skipPackageJson: schema.skipPackageJson,
});
tasks.push(playwrightConfigTask);
}
if (!schema.skipPackageJson) {
const installTask = updateDependencies(tree, schema);
tasks.push(installTask);

View File

@ -1,7 +1,7 @@
export interface Schema {
bundler?: 'webpack' | 'none' | 'vite';
unitTestRunner?: 'jest' | 'vitest' | 'none';
e2eTestRunner?: 'cypress' | 'none';
e2eTestRunner?: 'cypress' | 'playwright' | 'none';
skipFormat?: boolean;
skipPackageJson?: boolean;
}

View File

@ -21,7 +21,8 @@
"e2eTestRunner": {
"description": "Adds the specified e2e test runner",
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"x-prompt": "Which E2E test runner would you like to use?",
"default": "cypress"
},
"skipFormat": {