Skip to content

Commit

Permalink
feat(testing): add lint target for playwright (#18233)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongemi authored Jul 21, 2023
1 parent b311cbf commit 8407d7a
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 14 deletions.
22 changes: 14 additions & 8 deletions e2e/playwright/src/playwright.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,37 @@ describe('Playwright E2E Test runner', () => {
afterAll(() => cleanupProject());

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

const results = runCLI(`e2e demo-e2e`);
expect(results).toContain('6 passed');
expect(results).toContain('Successfully ran target e2e for project');
const e2eResults = runCLI(`e2e demo-e2e`);
expect(e2eResults).toContain('6 passed');
expect(e2eResults).toContain('Successfully ran target e2e for project');

const lintResults = runCLI(`lint demo-e2e`);
expect(lintResults).toContain('All files pass linting');
},
TEN_MINS_MS
);

it(
'should test example app with js',
'should test and lint example app with js',
() => {
runCLI(
`g @nx/js:lib demo-js-e2e --unitTestRunner none --bundler none --js`
);
runCLI(`g @nx/playwright:configuration --project demo-js-e2e --js`);
ensurePlaywrightBrowsersInstallation();

const results = runCLI(`e2e demo-js-e2e`);
expect(results).toContain('6 passed');
expect(results).toContain('Successfully ran target e2e for project');
const e2eResults = runCLI(`e2e demo-js-e2e`);
expect(e2eResults).toContain('6 passed');
expect(e2eResults).toContain('Successfully ran target e2e for project');

const lintResults = runCLI(`lint demo-e2e`);
expect(lintResults).toContain('All files pass linting');
},
TEN_MINS_MS
);
Expand Down
4 changes: 3 additions & 1 deletion e2e/utils/get-env-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ export function ensurePlaywrightBrowsersInstallation() {
cwd: tmpProjPath(),
});
e2eConsoleLogger(
`Playwright browsers ${execSync('npx playwright --version')} installed.`
`Playwright browsers ${execSync('npx playwright --version')
.toString()
.trim()} installed.`
);
}

Expand Down
1 change: 1 addition & 0 deletions packages/playwright/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
},
"dependencies": {
"@nx/devkit": "file:../devkit",
"@nx/linter": "file:../linter",
"tslib": "^2.3.0"
},
"peerDependencies": {
Expand Down
26 changes: 22 additions & 4 deletions packages/playwright/src/generators/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import {
convertNxGenerator,
formatFiles,
generateFiles,
GeneratorCallback,
offsetFromRoot,
readNxJson,
readProjectConfiguration,
runTasksInSerial,
toJS,
Tree,
updateNxJson,
Expand All @@ -13,11 +15,19 @@ import {
import * as path from 'path';
import { ConfigurationGeneratorSchema } from './schema';
import initGenerator from '../init/init';
import { addLinterToPlaywrightProject } from '../../utils/add-linter';

export async function configurationGenerator(
tree: Tree,
options: ConfigurationGeneratorSchema
) {
const tasks: GeneratorCallback[] = [];
tasks.push(
await initGenerator(tree, {
skipFormat: true,
skipPackageJson: options.skipPackageJson,
})
);
const projectConfig = readProjectConfiguration(tree, options.project);
generateFiles(tree, path.join(__dirname, 'files'), projectConfig.root, {
offsetFromRoot: offsetFromRoot(projectConfig.root),
Expand All @@ -29,6 +39,17 @@ export async function configurationGenerator(

addE2eTarget(tree, options);
setupE2ETargetDefaults(tree);
tasks.push(
await addLinterToPlaywrightProject(tree, {
project: options.project,
linter: options.linter,
skipPackageJson: options.skipPackageJson,
js: options.js,
directory: options.directory,
setParserOptionsProject: options.setParserOptionsProject,
rootProject: projectConfig.root === '.',
})
);

if (options.js) {
toJS(tree);
Expand All @@ -37,10 +58,7 @@ export async function configurationGenerator(
await formatFiles(tree);
}

return initGenerator(tree, {
skipFormat: true,
skipPackageJson: options.skipPackageJson,
});
return runTasksInSerial(...tasks);
}

function setupE2ETargetDefaults(tree: Tree) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defineConfig } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset';
<% if(!webServerCommand || !webServerAddress) { %>// eslint-disable-next-line @typescript-eslint/no-unused-vars <% } %>
import { workspaceRoot } from '@nx/devkit';

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/playwright/src/generators/configuration/schema.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import type { Linter } from '@nx/linter';

export interface ConfigurationGeneratorSchema {
project: string;
directory: string;
js: boolean; // default is false
skipFormat: boolean;
skipPackageJson: boolean;
linter: Linter;
setParserOptionsProject: boolean; // default is false
/**
* command to give playwright to run the web server
* @example: "npx nx serve my-fe-app"
Expand Down
11 changes: 11 additions & 0 deletions packages/playwright/src/generators/configuration/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@
"type": "string",
"description": "The address of the web server."
},
"linter": {
"description": "The tool to use for running lint checks.",
"type": "string",
"enum": ["eslint", "none"],
"default": "eslint"
},
"setParserOptionsProject": {
"type": "boolean",
"description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
"default": false
},
"skipFormat": {
"description": "Skip formatting files.",
"type": "boolean",
Expand Down
103 changes: 103 additions & 0 deletions packages/playwright/src/utils/add-linter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {
addDependenciesToPackageJson,
GeneratorCallback,
joinPathFragments,
readProjectConfiguration,
runTasksInSerial,
Tree,
updateJson,
} from '@nx/devkit';
import { Linter, lintProjectGenerator } from '@nx/linter';
import { globalJavaScriptOverrides } from '@nx/linter/src/generators/init/global-eslint-config';
import { eslintPluginPlaywrightVersion } from './versions';

export interface PlaywrightLinterOptions {
project: string;
linter: Linter;
setParserOptionsProject: boolean;
skipPackageJson: boolean;
rootProject: boolean;
js?: boolean;
/**
* Directory from the project root, where the playwright files will be located.
**/
directory: string;
}

export async function addLinterToPlaywrightProject(
tree: Tree,
options: PlaywrightLinterOptions
): Promise<GeneratorCallback> {
if (options.linter === Linter.None) {
return () => {};
}

const tasks: GeneratorCallback[] = [];
const projectConfig = readProjectConfiguration(tree, options.project);

if (!tree.exists(joinPathFragments(projectConfig.root, '.eslintrc.json'))) {
tasks.push(
await lintProjectGenerator(tree, {
project: options.project,
linter: options.linter,
skipFormat: true,
tsConfigPaths: [joinPathFragments(projectConfig.root, 'tsconfig.json')],
eslintFilePatterns: [
`${projectConfig.root}/**/*.${options.js ? 'js' : '{js,ts}'}`,
],
setParserOptionsProject: options.setParserOptionsProject,
skipPackageJson: options.skipPackageJson,
rootProject: options.rootProject,
})
);
}

if (!options.linter || options.linter !== Linter.EsLint) {
return runTasksInSerial(...tasks);
}

tasks.push(
!options.skipPackageJson
? addDependenciesToPackageJson(
tree,
{},
{ 'eslint-plugin-playwright': eslintPluginPlaywrightVersion }
)
: () => {}
);

updateJson(
tree,
joinPathFragments(projectConfig.root, '.eslintrc.json'),
(json) => {
if (options.rootProject) {
json.plugins = ['@nx'];
json.extends = ['plugin:playwright/recommended'];
} else {
json.extends = ['plugin:playwright/recommended', ...json.extends];
}
json.overrides ??= [];
const globals = options.rootProject ? [globalJavaScriptOverrides] : [];
const override = {
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
parserOptions: !options.setParserOptionsProject
? undefined
: {
project: `${projectConfig.root}/tsconfig.*?.json`,
},
rules: {},
};
const palywrightFiles = [
{
...override,
files: [`${options.directory}/**/*.{ts,js,tsx,jsx}`],
},
];
json.overrides.push(...globals);
json.overrides.push(...palywrightFiles);
return json;
}
);

return runTasksInSerial(...tasks);
}
2 changes: 1 addition & 1 deletion packages/playwright/src/utils/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface NxPlaywrightOptions {
* })
*
* @param pathToConfig will be used to construct the output paths for reporters and test results
* @param options optional confiuration options
* @param options optional configuration options
*/
export function nxE2EPreset(
pathToConfig: string,
Expand Down
1 change: 1 addition & 0 deletions packages/playwright/src/utils/versions.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const nxVersion = require('../../package.json').version;
export const playwrightVersion = '^1.36.0';
export const eslintPluginPlaywrightVersion = '^0.15.3';

1 comment on commit 8407d7a

@vercel
Copy link

@vercel vercel bot commented on 8407d7a Jul 21, 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.