Skip to content

Commit

Permalink
feat(angular): add playwright to e2eTestRunner option
Browse files Browse the repository at this point in the history
  • Loading branch information
barbados-clemens committed Jul 19, 2023
1 parent 8d160b2 commit 4e108a0
Show file tree
Hide file tree
Showing 18 changed files with 134 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"default": "cypress"
},
Expand Down
2 changes: 1 addition & 1 deletion docs/generated/packages/angular/generators/host.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"default": "cypress"
},
Expand Down
2 changes: 1 addition & 1 deletion docs/generated/packages/angular/generators/remote.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"default": "cypress"
},
Expand Down
1 change: 0 additions & 1 deletion packages/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
"webpack": "^5.80.0",
"webpack-merge": "5.7.3",
"enquirer": "^2.3.6",
"@nx/cypress": "file:../cypress",
"@nx/devkit": "file:../devkit",
"@nx/jest": "file:../jest",
"@nx/js": "file:../js",
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
31 changes: 30 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,29 @@ 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,
webServerCommand: `${getPackageManagerCommand().exec} nx serve ${
options.name
}`,
webServerAddress: `http://localhost:${options.port ?? 4200}`,
});
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/angular/src/generators/application/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"default": "cypress"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/src/generators/host/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"default": "cypress"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/src/generators/remote/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
},
"e2eTestRunner": {
"type": "string",
"enum": ["cypress", "none"],
"enum": ["cypress", "playwright", "none"],
"description": "Test runner to use for end to end (E2E) tests.",
"default": "cypress"
},
Expand Down
1 change: 1 addition & 0 deletions packages/angular/src/utils/test-runners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export enum UnitTestRunner {

export enum E2eTestRunner {
Cypress = 'cypress',
Playwright = 'playwright',
None = 'none',
}
4 changes: 2 additions & 2 deletions packages/playwright/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"Playwright",
"CLI"
],
"main": "./index",
"typings": "./index.d.ts",
"main": "./src/index",
"typings": "./src/index.d.ts",
"author": "Victor Savkin",
"license": "MIT",
"bugs": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export async function configurationGenerator(
generateFiles(tree, path.join(__dirname, 'files'), projectConfig.root, {
offsetFromRoot: offsetFromRoot(projectConfig.root),
projectRoot: projectConfig.root,
webServerCommand: options.webServerCommand ?? null,
webServerAddress: options.webServerAddress ?? null,
...options,
});

Expand Down Expand Up @@ -67,8 +69,10 @@ function addE2eTarget(tree: Tree, options: ConfigurationGeneratorSchema) {
throw new Error(`Project ${options.project} already has an e2e target.
Rename or remove the existing e2e target.`);
}
projectConfig.targets ??= {};
projectConfig.targets.e2e = {
executor: '@nx/playwright:playwright',
outputs: [`dist/playwright/${projectConfig.root}`],
options: {},
};
updateProjectConfiguration(tree, options.project, projectConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { defineConfig, devices } from '@playwright/test';
*/
export default defineConfig({
testDir: './<%= directory %>',
outputDir: '<%= offsetFromRoot %>dist/playwright/<%= projectRoot %>/test-output',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
Expand All @@ -25,7 +26,7 @@ export default defineConfig({
'html',
{
outputFolder:
'<%= offsetFromRoot %>/dist/playwright/<%= projectRoot %>/playwright-report',
'<%= offsetFromRoot %>dist/playwright/<%= projectRoot %>/playwright-report',
},
],
],
Expand Down Expand Up @@ -76,10 +77,14 @@ export default defineConfig({
// },
],

/* Run your local dev server before starting the tests */
// webServer: {
/* Run your local dev server before starting the tests */<% if(webServerCommand && webServerAddress) {%>
webServer: {
command: '<%= webServerCommand %>',
url: '<%= webServerAddress %>',
reuseExistingServer: !process.env.CI,
},<% } else {%>// webServer: {
// command: 'npm run start',
// url: 'http://127.0.0.1:3000',
// reuseExistingServer: !process.env.CI,
// },
// },<% } %>
});
10 changes: 10 additions & 0 deletions packages/playwright/src/generators/configuration/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,14 @@ export interface ConfigurationGeneratorSchema {
js: boolean; // default is false
skipFormat: boolean;
skipPackageJson: boolean;
/**
* command to give playwright to run the web server
* @example: "npx nx serve my-fe-app"
**/
webServerCommand?: string;
/**
* address
* @example: "http://localhost:4200"
**/
webServerAddress?: string;
}
8 changes: 8 additions & 0 deletions packages/playwright/src/generators/configuration/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
"description": "Generate JavaScript files rather than TypeScript files.",
"default": false
},
"webServerCommand": {
"type": "string",
"description": "The command to start the web server."
},
"webServerAddress": {
"type": "string",
"description": "The address of the web server."
},
"skipFormat": {
"description": "Skip formatting files.",
"type": "boolean",
Expand Down
25 changes: 25 additions & 0 deletions packages/playwright/src/generators/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
GeneratorCallback,
runTasksInSerial,
Tree,
updateJson,
} from '@nx/devkit';
import { InitGeneratorSchema } from './schema';
import { nxVersion, playwrightVersion } from '../../utils/versions';
Expand All @@ -26,6 +27,30 @@ export async function initGenerator(tree: Tree, options: InitGeneratorSchema) {
if (!options.skipFormat) {
await formatFiles(tree);
}

if (tree.exists('.vscode/extensions.json')) {
updateJson(tree, '.vscode/extensions.json', (json) => {
json.recommendations ??= [];

const recs = new Set(json.recommendations);
recs.add('ms-playwright.playwright');

json.recommendations = Array.from(recs);
return json;
});
} else {
tree.write(
'.vscode/extensions.json',
JSON.stringify(
{
recommendations: ['ms-playwright.playwright'],
},
null,
2
)
);
}

return runTasksInSerial(...tasks);
}

Expand Down
2 changes: 2 additions & 0 deletions packages/playwright/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export {
playwrightExecutor,
PlaywrightExecutorSchema,
} from './executors/playwright/playwright';
export { initGenerator } from './generators/init/init';
export { configurationGenerator } from './generators/configuration/configuration';

0 comments on commit 4e108a0

Please sign in to comment.