Skip to content

Commit 8407d7a

Browse files
authored
feat(testing): add lint target for playwright (#18233)
1 parent b311cbf commit 8407d7a

File tree

10 files changed

+161
-14
lines changed

10 files changed

+161
-14
lines changed

e2e/playwright/src/playwright.test.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,37 @@ describe('Playwright E2E Test runner', () => {
1515
afterAll(() => cleanupProject());
1616

1717
it(
18-
'should test example app',
18+
'should test and lint example app',
1919
() => {
2020
runCLI(`g @nx/js:lib demo-e2e --unitTestRunner none --bundler none`);
2121
runCLI(`g @nx/playwright:configuration --project demo-e2e`);
2222
ensurePlaywrightBrowsersInstallation();
2323

24-
const results = runCLI(`e2e demo-e2e`);
25-
expect(results).toContain('6 passed');
26-
expect(results).toContain('Successfully ran target e2e for project');
24+
const e2eResults = runCLI(`e2e demo-e2e`);
25+
expect(e2eResults).toContain('6 passed');
26+
expect(e2eResults).toContain('Successfully ran target e2e for project');
27+
28+
const lintResults = runCLI(`lint demo-e2e`);
29+
expect(lintResults).toContain('All files pass linting');
2730
},
2831
TEN_MINS_MS
2932
);
3033

3134
it(
32-
'should test example app with js',
35+
'should test and lint example app with js',
3336
() => {
3437
runCLI(
3538
`g @nx/js:lib demo-js-e2e --unitTestRunner none --bundler none --js`
3639
);
3740
runCLI(`g @nx/playwright:configuration --project demo-js-e2e --js`);
3841
ensurePlaywrightBrowsersInstallation();
3942

40-
const results = runCLI(`e2e demo-js-e2e`);
41-
expect(results).toContain('6 passed');
42-
expect(results).toContain('Successfully ran target e2e for project');
43+
const e2eResults = runCLI(`e2e demo-js-e2e`);
44+
expect(e2eResults).toContain('6 passed');
45+
expect(e2eResults).toContain('Successfully ran target e2e for project');
46+
47+
const lintResults = runCLI(`lint demo-e2e`);
48+
expect(lintResults).toContain('All files pass linting');
4349
},
4450
TEN_MINS_MS
4551
);

e2e/utils/get-env-info.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ export function ensurePlaywrightBrowsersInstallation() {
118118
cwd: tmpProjPath(),
119119
});
120120
e2eConsoleLogger(
121-
`Playwright browsers ${execSync('npx playwright --version')} installed.`
121+
`Playwright browsers ${execSync('npx playwright --version')
122+
.toString()
123+
.trim()} installed.`
122124
);
123125
}
124126

packages/playwright/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
},
3131
"dependencies": {
3232
"@nx/devkit": "file:../devkit",
33+
"@nx/linter": "file:../linter",
3334
"tslib": "^2.3.0"
3435
},
3536
"peerDependencies": {

packages/playwright/src/generators/configuration/configuration.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import {
22
convertNxGenerator,
33
formatFiles,
44
generateFiles,
5+
GeneratorCallback,
56
offsetFromRoot,
67
readNxJson,
78
readProjectConfiguration,
9+
runTasksInSerial,
810
toJS,
911
Tree,
1012
updateNxJson,
@@ -13,11 +15,19 @@ import {
1315
import * as path from 'path';
1416
import { ConfigurationGeneratorSchema } from './schema';
1517
import initGenerator from '../init/init';
18+
import { addLinterToPlaywrightProject } from '../../utils/add-linter';
1619

1720
export async function configurationGenerator(
1821
tree: Tree,
1922
options: ConfigurationGeneratorSchema
2023
) {
24+
const tasks: GeneratorCallback[] = [];
25+
tasks.push(
26+
await initGenerator(tree, {
27+
skipFormat: true,
28+
skipPackageJson: options.skipPackageJson,
29+
})
30+
);
2131
const projectConfig = readProjectConfiguration(tree, options.project);
2232
generateFiles(tree, path.join(__dirname, 'files'), projectConfig.root, {
2333
offsetFromRoot: offsetFromRoot(projectConfig.root),
@@ -29,6 +39,17 @@ export async function configurationGenerator(
2939

3040
addE2eTarget(tree, options);
3141
setupE2ETargetDefaults(tree);
42+
tasks.push(
43+
await addLinterToPlaywrightProject(tree, {
44+
project: options.project,
45+
linter: options.linter,
46+
skipPackageJson: options.skipPackageJson,
47+
js: options.js,
48+
directory: options.directory,
49+
setParserOptionsProject: options.setParserOptionsProject,
50+
rootProject: projectConfig.root === '.',
51+
})
52+
);
3253

3354
if (options.js) {
3455
toJS(tree);
@@ -37,10 +58,7 @@ export async function configurationGenerator(
3758
await formatFiles(tree);
3859
}
3960

40-
return initGenerator(tree, {
41-
skipFormat: true,
42-
skipPackageJson: options.skipPackageJson,
43-
});
61+
return runTasksInSerial(...tasks);
4462
}
4563

4664
function setupE2ETargetDefaults(tree: Tree) {

packages/playwright/src/generators/configuration/files/playwright.config.ts.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { defineConfig } from '@playwright/test';
22
import { nxE2EPreset } from '@nx/playwright/preset';
3+
<% if(!webServerCommand || !webServerAddress) { %>// eslint-disable-next-line @typescript-eslint/no-unused-vars <% } %>
34
import { workspaceRoot } from '@nx/devkit';
45

56
/**

packages/playwright/src/generators/configuration/schema.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import type { Linter } from '@nx/linter';
2+
13
export interface ConfigurationGeneratorSchema {
24
project: string;
35
directory: string;
46
js: boolean; // default is false
57
skipFormat: boolean;
68
skipPackageJson: boolean;
9+
linter: Linter;
10+
setParserOptionsProject: boolean; // default is false
711
/**
812
* command to give playwright to run the web server
913
* @example: "npx nx serve my-fe-app"

packages/playwright/src/generators/configuration/schema.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@
3333
"type": "string",
3434
"description": "The address of the web server."
3535
},
36+
"linter": {
37+
"description": "The tool to use for running lint checks.",
38+
"type": "string",
39+
"enum": ["eslint", "none"],
40+
"default": "eslint"
41+
},
42+
"setParserOptionsProject": {
43+
"type": "boolean",
44+
"description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
45+
"default": false
46+
},
3647
"skipFormat": {
3748
"description": "Skip formatting files.",
3849
"type": "boolean",
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import {
2+
addDependenciesToPackageJson,
3+
GeneratorCallback,
4+
joinPathFragments,
5+
readProjectConfiguration,
6+
runTasksInSerial,
7+
Tree,
8+
updateJson,
9+
} from '@nx/devkit';
10+
import { Linter, lintProjectGenerator } from '@nx/linter';
11+
import { globalJavaScriptOverrides } from '@nx/linter/src/generators/init/global-eslint-config';
12+
import { eslintPluginPlaywrightVersion } from './versions';
13+
14+
export interface PlaywrightLinterOptions {
15+
project: string;
16+
linter: Linter;
17+
setParserOptionsProject: boolean;
18+
skipPackageJson: boolean;
19+
rootProject: boolean;
20+
js?: boolean;
21+
/**
22+
* Directory from the project root, where the playwright files will be located.
23+
**/
24+
directory: string;
25+
}
26+
27+
export async function addLinterToPlaywrightProject(
28+
tree: Tree,
29+
options: PlaywrightLinterOptions
30+
): Promise<GeneratorCallback> {
31+
if (options.linter === Linter.None) {
32+
return () => {};
33+
}
34+
35+
const tasks: GeneratorCallback[] = [];
36+
const projectConfig = readProjectConfiguration(tree, options.project);
37+
38+
if (!tree.exists(joinPathFragments(projectConfig.root, '.eslintrc.json'))) {
39+
tasks.push(
40+
await lintProjectGenerator(tree, {
41+
project: options.project,
42+
linter: options.linter,
43+
skipFormat: true,
44+
tsConfigPaths: [joinPathFragments(projectConfig.root, 'tsconfig.json')],
45+
eslintFilePatterns: [
46+
`${projectConfig.root}/**/*.${options.js ? 'js' : '{js,ts}'}`,
47+
],
48+
setParserOptionsProject: options.setParserOptionsProject,
49+
skipPackageJson: options.skipPackageJson,
50+
rootProject: options.rootProject,
51+
})
52+
);
53+
}
54+
55+
if (!options.linter || options.linter !== Linter.EsLint) {
56+
return runTasksInSerial(...tasks);
57+
}
58+
59+
tasks.push(
60+
!options.skipPackageJson
61+
? addDependenciesToPackageJson(
62+
tree,
63+
{},
64+
{ 'eslint-plugin-playwright': eslintPluginPlaywrightVersion }
65+
)
66+
: () => {}
67+
);
68+
69+
updateJson(
70+
tree,
71+
joinPathFragments(projectConfig.root, '.eslintrc.json'),
72+
(json) => {
73+
if (options.rootProject) {
74+
json.plugins = ['@nx'];
75+
json.extends = ['plugin:playwright/recommended'];
76+
} else {
77+
json.extends = ['plugin:playwright/recommended', ...json.extends];
78+
}
79+
json.overrides ??= [];
80+
const globals = options.rootProject ? [globalJavaScriptOverrides] : [];
81+
const override = {
82+
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
83+
parserOptions: !options.setParserOptionsProject
84+
? undefined
85+
: {
86+
project: `${projectConfig.root}/tsconfig.*?.json`,
87+
},
88+
rules: {},
89+
};
90+
const palywrightFiles = [
91+
{
92+
...override,
93+
files: [`${options.directory}/**/*.{ts,js,tsx,jsx}`],
94+
},
95+
];
96+
json.overrides.push(...globals);
97+
json.overrides.push(...palywrightFiles);
98+
return json;
99+
}
100+
);
101+
102+
return runTasksInSerial(...tasks);
103+
}

packages/playwright/src/utils/preset.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export interface NxPlaywrightOptions {
4141
* })
4242
*
4343
* @param pathToConfig will be used to construct the output paths for reporters and test results
44-
* @param options optional confiuration options
44+
* @param options optional configuration options
4545
*/
4646
export function nxE2EPreset(
4747
pathToConfig: string,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export const nxVersion = require('../../package.json').version;
22
export const playwrightVersion = '^1.36.0';
3+
export const eslintPluginPlaywrightVersion = '^0.15.3';

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy