Skip to content

Commit

Permalink
feat(angular): add playwright to e2eTestRunner option (#18163)
Browse files Browse the repository at this point in the history
  • Loading branch information
barbados-clemens committed Aug 2, 2023
1 parent b530560 commit 1dcb80d
Show file tree
Hide file tree
Showing 18 changed files with 196 additions and 26 deletions.
3 changes: 2 additions & 1 deletion docs/generated/packages/angular/generators/application.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,9 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"x-prompt": "Which E2E test runner would you like to use?",
"default": "cypress"
},
"tags": {
Expand Down
3 changes: 2 additions & 1 deletion docs/generated/packages/angular/generators/host.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"x-prompt": "Which E2E test runner would you like to use?",
"default": "cypress"
},
"tags": {
Expand Down
3 changes: 2 additions & 1 deletion docs/generated/packages/angular/generators/init.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,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",
"x-priority": "important"
Expand Down
3 changes: 2 additions & 1 deletion docs/generated/packages/angular/generators/remote.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"x-prompt": "Which E2E test runner would you like to use?",
"default": "cypress"
},
"tags": {
Expand Down
4 changes: 2 additions & 2 deletions e2e/angular-core/src/ng-add.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,8 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
// add other projects
const app1 = uniq('app1');
const lib1 = uniq('lib1');
runCommand(`ng g @schematics/angular:application ${app1}`);
runCommand(`ng g @schematics/angular:library ${lib1}`);
runCommand(`ng g @schematics/angular:application ${app1} --no-interactive`);
runCommand(`ng g @schematics/angular:library ${lib1} --no-interactive`);

runNgAdd('@nx/angular', '--npm-scope projscope');

Expand Down
18 changes: 18 additions & 0 deletions e2e/angular-core/src/projects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { names } from '@nx/devkit';
import {
checkFilesExist,
cleanupProject,
ensurePlaywrightBrowsersInstallation,
getSize,
killPorts,
killProcessAndPorts,
Expand Down Expand Up @@ -123,6 +124,23 @@ describe('Angular Projects', () => {
await killProcessAndPorts(esbProcess.pid, appPort);
}, 1000000);

it('should successfully work with playwright for e2e tests', async () => {
const app = uniq('app');

runCLI(
`generate @nx/angular:app ${app} --e2eTestRunner=playwright --no-interactive`
);

if (runCypressTests()) {
ensurePlaywrightBrowsersInstallation();
const e2eResults = runCLI(`e2e ${app}-e2e`);
expect(e2eResults).toContain(
`Successfully ran target e2e for project ${app}-e2e`
);
expect(await killPorts()).toBeTruthy();
}
}, 1000000);

it('should lint correctly with eslint and handle external HTML files and inline templates', async () => {
// check apps and lib pass linting for initial generated code
runCLI(`run-many --target lint --projects=${app1},${lib1} --parallel`);
Expand Down
1 change: 1 addition & 0 deletions packages/angular/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"semver",
// These are installed by ensurePackage so missing in package.json
"@nx/cypress",
"@nx/playwright",
"@nx/jest",
"@nx/rollup",
"@nx/storybook",
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
"webpack": "^5.80.0",
"webpack-merge": "^5.8.0",
"enquirer": "^2.3.6",
"@nx/cypress": "file:../cypress",
"@nx/devkit": "file:../devkit",
"@nx/cypress": "file:../cypress",
"@nx/jest": "file:../jest",
"@nx/js": "file:../js",
"@nx/linter": "file:../linter",
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,5 @@
},
"lint": {}
},
"implicitDependencies": ["workspace", "cypress", "jest"]
"implicitDependencies": ["workspace", "playwright", "cypress", "jest"]
}
36 changes: 36 additions & 0 deletions packages/angular/src/generators/application/application.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ import type { Schema } from './schema';
// which is v9 while we are testing for the new v10 version
jest.mock('@nx/cypress/src/utils/cypress-version');
jest.mock('enquirer');
jest.mock('@nx/devkit', () => {
const original = jest.requireActual('@nx/devkit');
return {
...original,
ensurePackage: (pkg: string) => jest.requireActual(pkg),
};
});

describe('app', () => {
let appTree: Tree;
Expand Down Expand Up @@ -128,6 +135,23 @@ describe('app', () => {
expect(tsconfigE2E).toMatchSnapshot('e2e tsconfig.json');
});

it('should setup playwright', async () => {
await generateApp(appTree, 'playwright-app', {
e2eTestRunner: E2eTestRunner.Playwright,
});

expect(
appTree.exists('apps/playwright-app-e2e/playwright.config.ts')
).toBeTruthy();
expect(
appTree.exists('apps/playwright-app-e2e/src/example.spec.ts')
).toBeTruthy();
expect(
readProjectConfiguration(appTree, 'playwright-app-e2e')?.targets?.e2e
?.executor
).toEqual('@nx/playwright:playwright');
});

it('should setup jest with serializers', async () => {
await generateApp(appTree);

Expand Down Expand Up @@ -869,6 +893,18 @@ describe('app', () => {
const project = readProjectConfiguration(appTree, 'my-app');
expect(project.targets.build.options['outputPath']).toBe('dist/my-app');
});

it('should generate playwright with root project', async () => {
await generateApp(appTree, 'root-app', {
e2eTestRunner: E2eTestRunner.Playwright,
rootProject: true,
});
expect(
readProjectConfiguration(appTree, 'e2e').targets.e2e.executor
).toEqual('@nx/playwright:playwright');
expect(appTree.exists('e2e/playwright.config.ts')).toBeTruthy();
expect(appTree.exists('e2e/src/example.spec.ts')).toBeTruthy();
});
});

it('should error correctly when Angular version does not support standalone', async () => {
Expand Down
33 changes: 32 additions & 1 deletion packages/angular/src/generators/application/lib/add-e2e.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { cypressProjectGenerator } from '@nx/cypress';
import type { Tree } from '@nx/devkit';
import {
addDependenciesToPackageJson,
addProjectConfiguration,
ensurePackage,
getPackageManagerCommand,
joinPathFragments,
readProjectConfiguration,
updateProjectConfiguration,
} from '@nx/devkit';
Expand All @@ -13,6 +16,9 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) {
removeScaffoldedE2e(tree, options, options.ngCliSchematicE2ERoot);

if (options.e2eTestRunner === 'cypress') {
const { cypressProjectGenerator } = ensurePackage<
typeof import('@nx/cypress')
>('@nx/cypress', nxVersion);
// TODO: This can call `@nx/web:static-config` generator when ready
addFileServerTarget(tree, options, 'serve-static');

Expand All @@ -25,6 +31,31 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) {
skipPackageJson: options.skipPackageJson,
skipFormat: true,
});
} else if (options.e2eTestRunner === 'playwright') {
const { configurationGenerator: playwrightConfigurationGenerator } =
ensurePackage<typeof import('@nx/playwright')>(
'@nx/playwright',
nxVersion
);
addProjectConfiguration(tree, options.e2eProjectName, {
root: options.e2eProjectRoot,
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
targets: {},
implicitDependencies: [options.name],
});
await playwrightConfigurationGenerator(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
}`,
webServerAddress: `http://localhost:${options.port ?? 4200}`,
});
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/angular/src/generators/application/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"x-prompt": "Which E2E test runner would you like to use?",
"default": "cypress"
},
"tags": {
Expand Down
3 changes: 2 additions & 1 deletion packages/angular/src/generators/host/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,9 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"x-prompt": "Which E2E test runner would you like to use?",
"default": "cypress"
},
"tags": {
Expand Down
88 changes: 76 additions & 12 deletions packages/angular/src/generators/init/init.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ jest.mock('@nx/devkit', () => ({
...jest.requireActual('@nx/devkit'),
// need to mock so it doesn't resolve what the workspace has installed
// and be able to test with different versions
ensurePackage: jest.fn(),
ensurePackage: jest.fn(() => ({
cypressInitGenerator: jest.fn(),
initGenerator: jest.fn(),
})),
}));
import {
ensurePackage,
NxJsonConfiguration,
readJson,
readNxJson,
Expand Down Expand Up @@ -171,21 +175,50 @@ describe('init', () => {
});

describe('--e2e-test-runner', () => {
describe('cypress', () => {
it('should add cypress dependencies', async () => {
describe('playwright', () => {
it('should call @nx/playwright:init', async () => {
// ACT
await init(tree, {
unitTestRunner: UnitTestRunner.None,
e2eTestRunner: E2eTestRunner.Cypress,
e2eTestRunner: E2eTestRunner.Playwright,
linter: Linter.EsLint,
skipFormat: false,
});

const { devDependencies } = readJson(tree, 'package.json');
expect(ensurePackage).toHaveBeenLastCalledWith(
'@nx/playwright',
'0.0.1'
);
});

it('should set defaults', async () => {
// ACT
await init(tree, {
unitTestRunner: UnitTestRunner.None,
e2eTestRunner: E2eTestRunner.Playwright,
linter: Linter.EsLint,
skipFormat: false,
});

const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');

// ASSERT
expect(devDependencies['@nx/cypress']).toBeDefined();
expect(devDependencies['cypress']).toBeDefined();
expect(generators['@nx/angular:application'].e2eTestRunner).toEqual(
'playwright'
);
});
});
describe('cypress', () => {
it('should call @nx/cypress:init', async () => {
// ACT
await init(tree, {
unitTestRunner: UnitTestRunner.None,
e2eTestRunner: E2eTestRunner.Cypress,
linter: Linter.EsLint,
skipFormat: false,
});

expect(ensurePackage).toHaveBeenLastCalledWith('@nx/cypress', '0.0.1');
});

it('should set defaults', async () => {
Expand Down Expand Up @@ -523,6 +556,38 @@ bar
});

describe('--e2e-test-runner', () => {
it('should call @nx/playwright:init', async () => {
// ACT
await init(tree, {
unitTestRunner: UnitTestRunner.None,
e2eTestRunner: E2eTestRunner.Playwright,
linter: Linter.EsLint,
skipFormat: false,
});

expect(ensurePackage).toHaveBeenLastCalledWith(
'@nx/playwright',
'0.0.1'
);
});

it('should set defaults', async () => {
// ACT
await init(tree, {
unitTestRunner: UnitTestRunner.None,
e2eTestRunner: E2eTestRunner.Playwright,
linter: Linter.EsLint,
skipFormat: false,
});

const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');

// ASSERT
expect(generators['@nx/angular:application'].e2eTestRunner).toEqual(
'playwright'
);
});

describe('cypress', () => {
it('should add cypress dependencies', async () => {
// ACT
Expand All @@ -532,12 +597,11 @@ bar
linter: Linter.EsLint,
skipFormat: false,
});

const { devDependencies } = readJson(tree, 'package.json');

// ASSERT
expect(devDependencies['@nx/cypress']).toBeDefined();
expect(devDependencies['cypress']).toBeDefined();
expect(ensurePackage).toHaveBeenLastCalledWith(
'@nx/cypress',
'0.0.1'
);
});

it('should set defaults', async () => {
Expand Down

1 comment on commit 1dcb80d

@vercel
Copy link

@vercel vercel bot commented on 1dcb80d Aug 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-git-master-nrwl.vercel.app
nx-five.vercel.app
nx-dev-nrwl.vercel.app
nx.dev

Please sign in to comment.