@nx/playwright 0.0.0-pr-22179-271588f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +66 -0
  3. package/executors.json +9 -0
  4. package/generators.json +16 -0
  5. package/index.d.ts +3 -0
  6. package/index.js +9 -0
  7. package/migrations.json +16 -0
  8. package/package.json +66 -0
  9. package/plugin.d.ts +1 -0
  10. package/plugin.js +6 -0
  11. package/preset.d.ts +1 -0
  12. package/preset.js +4 -0
  13. package/src/executors/playwright/playwright.impl.d.ts +37 -0
  14. package/src/executors/playwright/playwright.impl.js +77 -0
  15. package/src/executors/playwright/schema.json +168 -0
  16. package/src/generators/configuration/configuration.d.ts +5 -0
  17. package/src/generators/configuration/configuration.js +153 -0
  18. package/src/generators/configuration/files/__directory__/example.spec.ts.template +8 -0
  19. package/src/generators/configuration/files/playwright.config.ts.template +75 -0
  20. package/src/generators/configuration/schema.d.ts +27 -0
  21. package/src/generators/configuration/schema.json +73 -0
  22. package/src/generators/init/init.d.ts +5 -0
  23. package/src/generators/init/init.js +51 -0
  24. package/src/generators/init/schema.d.ts +7 -0
  25. package/src/generators/init/schema.json +34 -0
  26. package/src/migrations/update-17-3-1/add-project-to-config.d.ts +2 -0
  27. package/src/migrations/update-17-3-1/add-project-to-config.js +95 -0
  28. package/src/migrations/update-18-1-0/remove-baseUrl-from-project-json.d.ts +2 -0
  29. package/src/migrations/update-18-1-0/remove-baseUrl-from-project-json.js +42 -0
  30. package/src/plugins/plugin.d.ts +7 -0
  31. package/src/plugins/plugin.js +205 -0
  32. package/src/utils/add-linter.d.ts +16 -0
  33. package/src/utils/add-linter.js +52 -0
  34. package/src/utils/preset.d.ts +30 -0
  35. package/src/utils/preset.js +60 -0
  36. package/src/utils/versions.d.ts +3 -0
  37. package/src/utils/versions.js +6 -0
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createNodes = exports.createDependencies = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const devkit_1 = require("@nx/devkit");
7
+ const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
8
+ const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
9
+ const workspace_context_1 = require("nx/src/utils/workspace-context");
10
+ const minimatch_1 = require("minimatch");
11
+ const cache_directory_1 = require("nx/src/utils/cache-directory");
12
+ const js_1 = require("@nx/js");
13
+ const config_utils_1 = require("@nx/devkit/src/utils/config-utils");
14
+ const cachePath = (0, path_1.join)(cache_directory_1.projectGraphCacheDirectory, 'playwright.hash');
15
+ const targetsCache = (0, fs_1.existsSync)(cachePath) ? readTargetsCache() : {};
16
+ const calculatedTargets = {};
17
+ function readTargetsCache() {
18
+ return (0, devkit_1.readJsonFile)(cachePath);
19
+ }
20
+ function writeTargetsToCache(targets) {
21
+ (0, devkit_1.writeJsonFile)(cachePath, targets);
22
+ }
23
+ const createDependencies = () => {
24
+ writeTargetsToCache(calculatedTargets);
25
+ return [];
26
+ };
27
+ exports.createDependencies = createDependencies;
28
+ exports.createNodes = [
29
+ '**/playwright.config.{js,ts,cjs,cts,mjs,mts}',
30
+ async (configFilePath, options, context) => {
31
+ const projectRoot = (0, path_1.dirname)(configFilePath);
32
+ // Do not create a project if package.json and project.json isn't there.
33
+ const siblingFiles = (0, fs_1.readdirSync)((0, path_1.join)(context.workspaceRoot, projectRoot));
34
+ if (!siblingFiles.includes('package.json') &&
35
+ !siblingFiles.includes('project.json')) {
36
+ return {};
37
+ }
38
+ const normalizedOptions = normalizeOptions(options);
39
+ const hash = (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, options, context, [
40
+ (0, js_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot)),
41
+ ]);
42
+ const targets = targetsCache[hash] ??
43
+ (await buildPlaywrightTargets(configFilePath, projectRoot, normalizedOptions, context));
44
+ calculatedTargets[hash] = targets;
45
+ return {
46
+ projects: {
47
+ [projectRoot]: {
48
+ root: projectRoot,
49
+ targets,
50
+ },
51
+ },
52
+ };
53
+ },
54
+ ];
55
+ async function buildPlaywrightTargets(configFilePath, projectRoot, options, context) {
56
+ // Playwright forbids importing the `@playwright/test` module twice. This would affect running the tests,
57
+ // but we're just reading the config so let's delete the variable they are using to detect this.
58
+ // See: https://github.com/microsoft/playwright/pull/11218/files
59
+ delete process['__pw_initiator__'];
60
+ const playwrightConfig = await (0, config_utils_1.loadConfigFile)((0, path_1.join)(context.workspaceRoot, configFilePath));
61
+ const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
62
+ const targets = {};
63
+ const baseTargetConfig = {
64
+ command: 'playwright test',
65
+ options: {
66
+ cwd: '{projectRoot}',
67
+ },
68
+ };
69
+ targets[options.targetName] = {
70
+ ...baseTargetConfig,
71
+ cache: true,
72
+ inputs: 'production' in namedInputs
73
+ ? ['default', '^production']
74
+ : ['default', '^default'],
75
+ outputs: getOutputs(projectRoot, playwrightConfig),
76
+ };
77
+ if (options.ciTargetName) {
78
+ const ciBaseTargetConfig = {
79
+ ...baseTargetConfig,
80
+ cache: true,
81
+ inputs: 'production' in namedInputs
82
+ ? ['default', '^production']
83
+ : ['default', '^default'],
84
+ outputs: getOutputs(projectRoot, playwrightConfig),
85
+ };
86
+ const testDir = playwrightConfig.testDir
87
+ ? (0, devkit_1.joinPathFragments)(projectRoot, playwrightConfig.testDir)
88
+ : projectRoot;
89
+ // Playwright defaults to the following pattern.
90
+ playwrightConfig.testMatch ??= '**/*.@(spec|test).?(c|m)[jt]s?(x)';
91
+ const dependsOn = [];
92
+ forEachTestFile((testFile) => {
93
+ const relativeToProjectRoot = (0, devkit_1.normalizePath)((0, path_1.relative)(projectRoot, testFile));
94
+ const targetName = `${options.ciTargetName}--${relativeToProjectRoot}`;
95
+ targets[targetName] = {
96
+ ...ciBaseTargetConfig,
97
+ command: `${baseTargetConfig.command} ${relativeToProjectRoot}`,
98
+ };
99
+ dependsOn.push({
100
+ target: targetName,
101
+ projects: 'self',
102
+ params: 'forward',
103
+ });
104
+ }, {
105
+ context,
106
+ path: testDir,
107
+ config: playwrightConfig,
108
+ });
109
+ targets[options.ciTargetName] ??= {};
110
+ targets[options.ciTargetName] = {
111
+ executor: 'nx:noop',
112
+ cache: ciBaseTargetConfig.cache,
113
+ inputs: ciBaseTargetConfig.inputs,
114
+ outputs: ciBaseTargetConfig.outputs,
115
+ dependsOn,
116
+ };
117
+ }
118
+ return targets;
119
+ }
120
+ async function forEachTestFile(cb, opts) {
121
+ const files = (0, workspace_context_1.getFilesInDirectoryUsingContext)(opts.context.workspaceRoot, opts.path);
122
+ const matcher = createMatcher(opts.config.testMatch);
123
+ const ignoredMatcher = opts.config.testIgnore
124
+ ? createMatcher(opts.config.testIgnore)
125
+ : () => false;
126
+ for (const file of files) {
127
+ if (matcher(file) && !ignoredMatcher(file)) {
128
+ cb(file);
129
+ }
130
+ }
131
+ }
132
+ function createMatcher(pattern) {
133
+ if (Array.isArray(pattern)) {
134
+ const matchers = pattern.map((p) => createMatcher(p));
135
+ return (path) => matchers.some((m) => m(path));
136
+ }
137
+ else if (pattern instanceof RegExp) {
138
+ return (path) => pattern.test(path);
139
+ }
140
+ else {
141
+ return (path) => {
142
+ try {
143
+ return (0, minimatch_1.minimatch)(path, pattern);
144
+ }
145
+ catch (e) {
146
+ throw new Error(`Error matching ${path} with ${pattern}: ${e.message}`);
147
+ }
148
+ };
149
+ }
150
+ }
151
+ function getOutputs(projectRoot, playwrightConfig) {
152
+ function getOutput(path) {
153
+ if (path.startsWith('..')) {
154
+ return (0, path_1.join)('{workspaceRoot}', (0, path_1.join)(projectRoot, path));
155
+ }
156
+ else {
157
+ return (0, path_1.join)('{projectRoot}', path);
158
+ }
159
+ }
160
+ const outputs = [];
161
+ const { reporter, outputDir } = playwrightConfig;
162
+ if (reporter) {
163
+ const DEFAULT_REPORTER_OUTPUT = getOutput('playwright-report');
164
+ if (reporter === 'html' || reporter === 'json') {
165
+ // Reporter is a string, so it uses the default output directory.
166
+ outputs.push(DEFAULT_REPORTER_OUTPUT);
167
+ }
168
+ else if (Array.isArray(reporter)) {
169
+ for (const r of reporter) {
170
+ const [, opts] = r;
171
+ // There are a few different ways to specify an output file or directory
172
+ // depending on the reporter. This is a best effort to find the output.
173
+ if (!opts) {
174
+ outputs.push(DEFAULT_REPORTER_OUTPUT);
175
+ }
176
+ else if (opts.outputFile) {
177
+ outputs.push(getOutput(opts.outputFile));
178
+ }
179
+ else if (opts.outputDir) {
180
+ outputs.push(getOutput(opts.outputDir));
181
+ }
182
+ else if (opts.outputFolder) {
183
+ outputs.push(getOutput(opts.outputFolder));
184
+ }
185
+ else {
186
+ outputs.push(DEFAULT_REPORTER_OUTPUT);
187
+ }
188
+ }
189
+ }
190
+ }
191
+ if (outputDir) {
192
+ outputs.push(getOutput(outputDir));
193
+ }
194
+ else {
195
+ outputs.push(getOutput('./test-results'));
196
+ }
197
+ return outputs;
198
+ }
199
+ function normalizeOptions(options) {
200
+ return {
201
+ ...options,
202
+ targetName: options.targetName ?? 'e2e',
203
+ ciTargetName: options.ciTargetName ?? 'e2e-ci',
204
+ };
205
+ }
@@ -0,0 +1,16 @@
1
+ import { GeneratorCallback, Tree } from '@nx/devkit';
2
+ import { Linter } from '@nx/eslint';
3
+ export interface PlaywrightLinterOptions {
4
+ project: string;
5
+ linter: Linter;
6
+ setParserOptionsProject: boolean;
7
+ skipPackageJson: boolean;
8
+ rootProject: boolean;
9
+ js?: boolean;
10
+ /**
11
+ * Directory from the project root, where the playwright files will be located.
12
+ **/
13
+ directory: string;
14
+ addPlugin?: boolean;
15
+ }
16
+ export declare function addLinterToPlaywrightProject(tree: Tree, options: PlaywrightLinterOptions): Promise<GeneratorCallback>;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addLinterToPlaywrightProject = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const eslint_1 = require("@nx/eslint");
6
+ const global_eslint_config_1 = require("@nx/eslint/src/generators/init/global-eslint-config");
7
+ const versions_1 = require("./versions");
8
+ const eslint_file_1 = require("@nx/eslint/src/generators/utils/eslint-file");
9
+ async function addLinterToPlaywrightProject(tree, options) {
10
+ if (options.linter === eslint_1.Linter.None) {
11
+ return () => { };
12
+ }
13
+ const tasks = [];
14
+ const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
15
+ const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
16
+ if (!eslintFile) {
17
+ tasks.push(await (0, eslint_1.lintProjectGenerator)(tree, {
18
+ project: options.project,
19
+ linter: options.linter,
20
+ skipFormat: true,
21
+ tsConfigPaths: [(0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json')],
22
+ setParserOptionsProject: options.setParserOptionsProject,
23
+ skipPackageJson: options.skipPackageJson,
24
+ rootProject: options.rootProject,
25
+ addPlugin: options.addPlugin,
26
+ }));
27
+ }
28
+ if (!options.linter || options.linter !== eslint_1.Linter.EsLint) {
29
+ return (0, devkit_1.runTasksInSerial)(...tasks);
30
+ }
31
+ tasks.push(!options.skipPackageJson
32
+ ? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { 'eslint-plugin-playwright': versions_1.eslintPluginPlaywrightVersion })
33
+ : () => { });
34
+ if ((0, eslint_file_1.isEslintConfigSupported)(tree)) {
35
+ (0, eslint_file_1.addExtendsToLintConfig)(tree, projectConfig.root, 'plugin:playwright/recommended');
36
+ if (options.rootProject) {
37
+ (0, eslint_file_1.addPluginsToLintConfig)(tree, projectConfig.root, '@nx');
38
+ (0, eslint_file_1.addOverrideToLintConfig)(tree, projectConfig.root, global_eslint_config_1.javaScriptOverride);
39
+ }
40
+ (0, eslint_file_1.addOverrideToLintConfig)(tree, projectConfig.root, {
41
+ files: [`${options.directory}/**/*.{ts,js,tsx,jsx}`],
42
+ parserOptions: !options.setParserOptionsProject
43
+ ? undefined
44
+ : {
45
+ project: `${projectConfig.root}/tsconfig.*?.json`,
46
+ },
47
+ rules: {},
48
+ });
49
+ }
50
+ return (0, devkit_1.runTasksInSerial)(...tasks);
51
+ }
52
+ exports.addLinterToPlaywrightProject = addLinterToPlaywrightProject;
@@ -0,0 +1,30 @@
1
+ export interface NxPlaywrightOptions {
2
+ /**
3
+ * The directory where the e2e tests are located.
4
+ * @default './src'
5
+ **/
6
+ testDir?: string;
7
+ }
8
+ /**
9
+ * nx E2E Preset for Playwright
10
+ * @description
11
+ * this preset contains the base configuration
12
+ * for your e2e tests that nx recommends.
13
+ * By default html reporter is configured
14
+ * along with the following browsers:
15
+ * - chromium
16
+ * - firefox
17
+ * - webkit
18
+ * These are generated by default.
19
+ *
20
+ * you can easily extend this within your playwright config via spreading the preset
21
+ * @example
22
+ * export default defineConfig({
23
+ * ...nxE2EPreset(__filename, options)
24
+ * // add your own config here
25
+ * })
26
+ *
27
+ * @param pathToConfig will be used to construct the output paths for reporters and test results
28
+ * @param options optional configuration options
29
+ */
30
+ export declare function nxE2EPreset(pathToConfig: string, options?: NxPlaywrightOptions): import("@playwright/test").PlaywrightTestConfig<{}, {}>;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nxE2EPreset = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const test_1 = require("@playwright/test");
8
+ /**
9
+ * nx E2E Preset for Playwright
10
+ * @description
11
+ * this preset contains the base configuration
12
+ * for your e2e tests that nx recommends.
13
+ * By default html reporter is configured
14
+ * along with the following browsers:
15
+ * - chromium
16
+ * - firefox
17
+ * - webkit
18
+ * These are generated by default.
19
+ *
20
+ * you can easily extend this within your playwright config via spreading the preset
21
+ * @example
22
+ * export default defineConfig({
23
+ * ...nxE2EPreset(__filename, options)
24
+ * // add your own config here
25
+ * })
26
+ *
27
+ * @param pathToConfig will be used to construct the output paths for reporters and test results
28
+ * @param options optional configuration options
29
+ */
30
+ function nxE2EPreset(pathToConfig, options) {
31
+ const normalizedPath = (0, node_fs_1.lstatSync)(pathToConfig).isDirectory()
32
+ ? pathToConfig
33
+ : (0, node_path_1.dirname)(pathToConfig);
34
+ const projectPath = (0, node_path_1.relative)(devkit_1.workspaceRoot, normalizedPath);
35
+ const offset = (0, node_path_1.relative)(normalizedPath, devkit_1.workspaceRoot);
36
+ const testResultOuputDir = (0, node_path_1.join)(offset, 'dist', '.playwright', projectPath, 'test-output');
37
+ const reporterOutputDir = (0, node_path_1.join)(offset, 'dist', '.playwright', projectPath, 'playwright-report');
38
+ return (0, test_1.defineConfig)({
39
+ testDir: options?.testDir ?? './src',
40
+ outputDir: testResultOuputDir,
41
+ /* Run tests in files in parallel */
42
+ fullyParallel: true,
43
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
44
+ forbidOnly: !!process.env.CI,
45
+ /* Retry on CI only */
46
+ retries: process.env.CI ? 2 : 0,
47
+ /* Opt out of parallel tests on CI. */
48
+ workers: process.env.CI ? 1 : undefined,
49
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
50
+ reporter: [
51
+ [
52
+ 'html',
53
+ {
54
+ outputFolder: reporterOutputDir,
55
+ },
56
+ ],
57
+ ],
58
+ });
59
+ }
60
+ exports.nxE2EPreset = nxE2EPreset;
@@ -0,0 +1,3 @@
1
+ export declare const nxVersion: any;
2
+ export declare const playwrightVersion = "^1.36.0";
3
+ export declare const eslintPluginPlaywrightVersion = "^0.15.3";
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.eslintPluginPlaywrightVersion = exports.playwrightVersion = exports.nxVersion = void 0;
4
+ exports.nxVersion = require('../../package.json').version;
5
+ exports.playwrightVersion = '^1.36.0';
6
+ exports.eslintPluginPlaywrightVersion = '^0.15.3';