@nx/playwright 0.0.0-pr-31222-862e973 → 0.0.0-pr-31313-387cdca

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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2017-2024 Narwhal Technologies Inc.
3
+ Copyright (c) 2017-2025 Narwhal Technologies Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
package/generators.json CHANGED
@@ -10,7 +10,8 @@
10
10
  "init": {
11
11
  "factory": "./src/generators/init/init#initGeneratorInternal",
12
12
  "schema": "./src/generators/init/schema.json",
13
- "description": "Initializes a Playwright project in the current workspace"
13
+ "description": "Initializes a Playwright project in the current workspace",
14
+ "hidden": true
14
15
  },
15
16
  "convert-to-inferred": {
16
17
  "factory": "./src/generators/convert-to-inferred/convert-to-inferred",
package/migrations.json CHANGED
@@ -1,17 +1,5 @@
1
1
  {
2
2
  "generators": {
3
- "17-3-1-add-project-to-config": {
4
- "cli": "nx",
5
- "version": "17.3.1-beta.0",
6
- "description": "Add project property to playwright config",
7
- "implementation": "./src/migrations/update-17-3-1/add-project-to-config"
8
- },
9
- "18-1-0-remove-baseUrl-from-project-json": {
10
- "cli": "nx",
11
- "version": "18.1.0-beta.3",
12
- "description": "Remove invalid baseUrl option from @nx/playwright:playwright targets in project.json.",
13
- "implementation": "./src/migrations/update-18-1-0/remove-baseUrl-from-project-json"
14
- },
15
3
  "19-6-0-use-serve-static-preview-for-command": {
16
4
  "cli": "nx",
17
5
  "version": "19.6.0-beta.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/playwright",
3
- "version": "0.0.0-pr-31222-862e973",
3
+ "version": "0.0.0-pr-31313-387cdca",
4
4
  "type": "commonjs",
5
5
  "homepage": "https://nx.dev",
6
6
  "private": false,
@@ -35,11 +35,9 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@phenomnomnominal/tsquery": "~5.0.1",
38
- "@nx/devkit": "0.0.0-pr-31222-862e973",
39
- "@nx/eslint": "0.0.0-pr-31222-862e973",
40
- "@nx/webpack": "0.0.0-pr-31222-862e973",
41
- "@nx/vite": "0.0.0-pr-31222-862e973",
42
- "@nx/js": "0.0.0-pr-31222-862e973",
38
+ "@nx/devkit": "0.0.0-pr-31313-387cdca",
39
+ "@nx/eslint": "0.0.0-pr-31313-387cdca",
40
+ "@nx/js": "0.0.0-pr-31313-387cdca",
43
41
  "tslib": "^2.3.0",
44
42
  "minimatch": "9.0.3"
45
43
  },
@@ -17,7 +17,7 @@ async function playwrightExecutor(options, context) {
17
17
  (0, child_process_1.execSync)(`${pmc.exec} playwright install`, {
18
18
  cwd: devkit_1.workspaceRoot,
19
19
  stdio: 'inherit',
20
- windowsHide: true,
20
+ windowsHide: false,
21
21
  });
22
22
  }
23
23
  const args = createArgs(options);
@@ -1,5 +1,5 @@
1
1
  import { GeneratorCallback, Tree } from '@nx/devkit';
2
- import { ConfigurationGeneratorSchema } from './schema';
2
+ import type { ConfigurationGeneratorSchema } from './schema';
3
3
  export declare function configurationGenerator(tree: Tree, options: ConfigurationGeneratorSchema): Promise<GeneratorCallback>;
4
- export declare function configurationGeneratorInternal(tree: Tree, options: ConfigurationGeneratorSchema): Promise<GeneratorCallback>;
4
+ export declare function configurationGeneratorInternal(tree: Tree, rawOptions: ConfigurationGeneratorSchema): Promise<GeneratorCallback>;
5
5
  export default configurationGenerator;
@@ -3,21 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.configurationGenerator = configurationGenerator;
4
4
  exports.configurationGeneratorInternal = configurationGeneratorInternal;
5
5
  const devkit_1 = require("@nx/devkit");
6
+ const project_name_and_root_utils_1 = require("@nx/devkit/src/generators/project-name-and-root-utils");
7
+ const prompt_1 = require("@nx/devkit/src/generators/prompt");
6
8
  const js_1 = require("@nx/js");
7
- const versions_1 = require("@nx/js/src/utils/versions");
9
+ const generator_prompts_1 = require("@nx/js/src/utils/generator-prompts");
10
+ const package_manager_workspaces_1 = require("@nx/js/src/utils/package-manager-workspaces");
11
+ const ensure_typescript_1 = require("@nx/js/src/utils/typescript/ensure-typescript");
12
+ const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
8
13
  const child_process_1 = require("child_process");
9
14
  const path = require("path");
10
15
  const add_linter_1 = require("../../utils/add-linter");
11
- const versions_2 = require("../../utils/versions");
16
+ const versions_1 = require("../../utils/versions");
12
17
  const init_1 = require("../init/init");
18
+ const eslint_file_1 = require("@nx/eslint/src/generators/utils/eslint-file");
13
19
  function configurationGenerator(tree, options) {
14
20
  return configurationGeneratorInternal(tree, { addPlugin: false, ...options });
15
21
  }
16
- async function configurationGeneratorInternal(tree, options) {
17
- const nxJson = (0, devkit_1.readNxJson)(tree);
18
- options.addPlugin ??=
19
- process.env.NX_ADD_PLUGINS !== 'false' &&
20
- nxJson.useInferencePlugins !== false;
22
+ async function configurationGeneratorInternal(tree, rawOptions) {
23
+ const options = await normalizeOptions(tree, rawOptions);
21
24
  const tasks = [];
22
25
  tasks.push(await (0, init_1.initGenerator)(tree, {
23
26
  skipFormat: true,
@@ -25,7 +28,6 @@ async function configurationGeneratorInternal(tree, options) {
25
28
  addPlugin: options.addPlugin,
26
29
  }));
27
30
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
28
- const hasTsConfig = tree.exists((0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json'));
29
31
  const offsetFromProjectRoot = (0, devkit_1.offsetFromRoot)(projectConfig.root);
30
32
  (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'files'), projectConfig.root, {
31
33
  offsetFromRoot: offsetFromProjectRoot,
@@ -34,13 +36,43 @@ async function configurationGeneratorInternal(tree, options) {
34
36
  webServerAddress: options.webServerAddress ?? null,
35
37
  ...options,
36
38
  });
37
- if (!hasTsConfig) {
38
- tree.write(`${projectConfig.root}/tsconfig.json`, JSON.stringify({
39
+ const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
40
+ const tsconfigPath = (0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json');
41
+ if (tree.exists(tsconfigPath)) {
42
+ if (isTsSolutionSetup) {
43
+ const tsconfig = {
44
+ extends: (0, js_1.getRelativePathToRootTsConfig)(tree, projectConfig.root),
45
+ compilerOptions: {
46
+ allowJs: true,
47
+ outDir: 'out-tsc/playwright',
48
+ sourceMap: false,
49
+ },
50
+ include: [
51
+ (0, devkit_1.joinPathFragments)(options.directory, '**/*.ts'),
52
+ (0, devkit_1.joinPathFragments)(options.directory, '**/*.js'),
53
+ 'playwright.config.ts',
54
+ ],
55
+ exclude: ['out-tsc', 'test-output'],
56
+ };
57
+ // skip eslint from typechecking since it extends from root file that is outside rootDir
58
+ if (options.linter === 'eslint') {
59
+ tsconfig.exclude.push('eslint.config.js', 'eslint.config.mjs', 'eslint.config.cjs');
60
+ }
61
+ (0, devkit_1.writeJson)(tree, (0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.e2e.json'), tsconfig);
62
+ (0, devkit_1.updateJson)(tree, tsconfigPath, (json) => {
63
+ // add the project tsconfig to the workspace root tsconfig.json references
64
+ json.references ??= [];
65
+ json.references.push({ path: './tsconfig.e2e.json' });
66
+ return json;
67
+ });
68
+ }
69
+ }
70
+ else {
71
+ const tsconfig = {
39
72
  extends: (0, js_1.getRelativePathToRootTsConfig)(tree, projectConfig.root),
40
73
  compilerOptions: {
41
74
  allowJs: true,
42
75
  outDir: `${offsetFromProjectRoot}dist/out-tsc`,
43
- module: 'commonjs',
44
76
  sourceMap: false,
45
77
  },
46
78
  include: [
@@ -53,7 +85,44 @@ async function configurationGeneratorInternal(tree, options) {
53
85
  'src/**/*.test.js',
54
86
  'src/**/*.d.ts',
55
87
  ],
56
- }, null, 2));
88
+ };
89
+ if (isTsSolutionSetup) {
90
+ tsconfig.exclude = ['out-tsc', 'test-output'];
91
+ // skip eslint from typechecking since it extends from root file that is outside rootDir
92
+ if (options.linter === 'eslint') {
93
+ tsconfig.exclude.push('eslint.config.js', 'eslint.config.mjs', 'eslint.config.cjs');
94
+ }
95
+ tsconfig.compilerOptions.outDir = 'out-tsc/playwright';
96
+ if (!options.rootProject) {
97
+ (0, devkit_1.updateJson)(tree, 'tsconfig.json', (json) => {
98
+ // add the project tsconfig to the workspace root tsconfig.json references
99
+ json.references ??= [];
100
+ json.references.push({ path: './' + projectConfig.root });
101
+ return json;
102
+ });
103
+ }
104
+ }
105
+ else {
106
+ tsconfig.compilerOptions.outDir = `${offsetFromProjectRoot}dist/out-tsc`;
107
+ tsconfig.compilerOptions.module = 'commonjs';
108
+ }
109
+ (0, devkit_1.writeJson)(tree, tsconfigPath, tsconfig);
110
+ }
111
+ if (isTsSolutionSetup) {
112
+ const packageJsonPath = (0, devkit_1.joinPathFragments)(projectConfig.root, 'package.json');
113
+ if (!tree.exists(packageJsonPath)) {
114
+ const importPath = (0, project_name_and_root_utils_1.resolveImportPath)(tree, projectConfig.name, projectConfig.root);
115
+ const packageJson = {
116
+ name: importPath,
117
+ version: '0.0.1',
118
+ private: true,
119
+ };
120
+ if (options.project !== importPath) {
121
+ packageJson.nx = { name: options.project };
122
+ }
123
+ (0, devkit_1.writeJson)(tree, packageJsonPath, packageJson);
124
+ }
125
+ ignoreTestOutput(tree, options);
57
126
  }
58
127
  const hasPlugin = (0, devkit_1.readNxJson)(tree).plugins?.some((p) => typeof p === 'string'
59
128
  ? p === '@nx/playwright/plugin'
@@ -73,14 +142,14 @@ async function configurationGeneratorInternal(tree, options) {
73
142
  addPlugin: options.addPlugin,
74
143
  }));
75
144
  if (options.js) {
76
- const { ModuleKind } = (0, devkit_1.ensurePackage)('typescript', versions_1.typescriptVersion);
145
+ const { ModuleKind } = (0, ensure_typescript_1.ensureTypescript)();
77
146
  (0, devkit_1.toJS)(tree, { extension: '.cjs', module: ModuleKind.CommonJS });
78
147
  }
79
148
  recommendVsCodeExtensions(tree);
80
149
  if (!options.skipPackageJson) {
81
150
  tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
82
151
  // required since used in playwright config
83
- '@nx/devkit': versions_2.nxVersion,
152
+ '@nx/devkit': versions_1.nxVersion,
84
153
  }));
85
154
  }
86
155
  if (!options.skipInstall) {
@@ -89,8 +158,55 @@ async function configurationGeneratorInternal(tree, options) {
89
158
  if (!options.skipFormat) {
90
159
  await (0, devkit_1.formatFiles)(tree);
91
160
  }
161
+ if (isTsSolutionSetup) {
162
+ const projectPackageManagerWorkspaceState = (0, package_manager_workspaces_1.getProjectPackageManagerWorkspaceState)(tree, projectConfig.root);
163
+ if (projectPackageManagerWorkspaceState !== 'included') {
164
+ tasks.push((0, package_manager_workspaces_1.getProjectPackageManagerWorkspaceStateWarningTask)(projectPackageManagerWorkspaceState, tree.root));
165
+ }
166
+ }
92
167
  return (0, devkit_1.runTasksInSerial)(...tasks);
93
168
  }
169
+ async function normalizeOptions(tree, options) {
170
+ const nxJson = (0, devkit_1.readNxJson)(tree);
171
+ const addPlugin = options.addPlugin ??
172
+ (process.env.NX_ADD_PLUGINS !== 'false' &&
173
+ nxJson.useInferencePlugins !== false);
174
+ const linter = await (0, generator_prompts_1.normalizeLinterOption)(tree, options.linter);
175
+ if (!options.webServerCommand || !options.webServerAddress) {
176
+ const { webServerCommand, webServerAddress } = await promptForMissingServeData(options.project);
177
+ options.webServerCommand = webServerCommand;
178
+ options.webServerAddress = webServerAddress;
179
+ }
180
+ return {
181
+ ...options,
182
+ addPlugin,
183
+ linter,
184
+ directory: options.directory ?? 'e2e',
185
+ };
186
+ }
187
+ async function promptForMissingServeData(projectName) {
188
+ const { command, port } = await (0, prompt_1.promptWhenInteractive)([
189
+ {
190
+ type: 'input',
191
+ name: 'command',
192
+ message: 'What command should be run to serve the application locally?',
193
+ initial: `npx nx serve ${projectName}`,
194
+ },
195
+ {
196
+ type: 'numeral',
197
+ name: 'port',
198
+ message: 'What port will the application be served on?',
199
+ initial: 3000,
200
+ },
201
+ ], {
202
+ command: `npx nx serve ${projectName}`,
203
+ port: 3000,
204
+ });
205
+ return {
206
+ webServerCommand: command,
207
+ webServerAddress: `http://localhost:${port}`,
208
+ };
209
+ }
94
210
  function getBrowsersInstallTask() {
95
211
  return () => {
96
212
  devkit_1.output.log({
@@ -100,7 +216,7 @@ function getBrowsersInstallTask() {
100
216
  const pmc = (0, devkit_1.getPackageManagerCommand)();
101
217
  (0, child_process_1.execSync)(`${pmc.exec} playwright install`, {
102
218
  cwd: devkit_1.workspaceRoot,
103
- windowsHide: true,
219
+ windowsHide: false,
104
220
  });
105
221
  };
106
222
  }
@@ -152,4 +268,20 @@ Rename or remove the existing e2e target.`);
152
268
  };
153
269
  (0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
154
270
  }
271
+ function ignoreTestOutput(tree, options) {
272
+ // Make sure playwright outputs are not linted.
273
+ if (options.linter === 'eslint') {
274
+ (0, eslint_file_1.addIgnoresToLintConfig)(tree, '', ['**/test-output']);
275
+ }
276
+ // Handle gitignore
277
+ if (!tree.exists('.gitignore')) {
278
+ devkit_1.logger.warn(`Couldn't find a root .gitignore file to update.`);
279
+ }
280
+ let content = tree.read('.gitignore', 'utf-8');
281
+ if (/^test-output$/gm.test(content)) {
282
+ return;
283
+ }
284
+ content = `${content}\ntest-output\n`;
285
+ tree.write('.gitignore', content);
286
+ }
155
287
  exports.default = configurationGenerator;
@@ -1,7 +1,6 @@
1
1
  import { defineConfig, devices } from '@playwright/test';
2
2
  import { nxE2EPreset } from '@nx/playwright/preset';
3
- <% if(!webServerCommand || !webServerAddress) { %>// eslint-disable-next-line @typescript-eslint/no-unused-vars <% } %>
4
- import { workspaceRoot } from '@nx/devkit';
3
+ <% if (webServerCommand && webServerAddress) { %>import { workspaceRoot } from '@nx/devkit';<% } %>
5
4
 
6
5
  // For CI, you may want to set BASE_URL to the deployed application.
7
6
  const baseURL = process.env['BASE_URL'] || '<% if(webServerAddress) {%><%= webServerAddress %><% } else {%>http://localhost:3000<% } %>';
@@ -27,13 +26,13 @@ export default defineConfig({
27
26
  webServer: {
28
27
  command: '<%= webServerCommand %>',
29
28
  url: '<%= webServerAddress %>',
30
- reuseExistingServer: !process.env.CI,
29
+ reuseExistingServer: true,
31
30
  cwd: workspaceRoot
32
31
  },<% } else {%>
33
32
  // webServer: {
34
33
  // command: 'npm run start',
35
34
  // url: 'http://127.0.0.1:3000',
36
- // reuseExistingServer: !process.env.CI,
35
+ // reuseExistingServer: true,
37
36
  // cwd: workspaceRoot,
38
37
  // },<% } %>
39
38
  projects: [
@@ -5,13 +5,13 @@ export interface ConfigurationGeneratorSchema {
5
5
  /**
6
6
  * this is relative to the projectRoot
7
7
  **/
8
- directory: string;
9
- js: boolean; // default is false
10
- skipFormat: boolean;
11
- skipPackageJson: boolean;
8
+ directory?: string;
9
+ js?: boolean; // default is false
10
+ skipFormat?: boolean;
11
+ skipPackageJson?: boolean;
12
12
  skipInstall?: boolean;
13
- linter: Linter | LinterType;
14
- setParserOptionsProject: boolean; // default is false
13
+ linter?: Linter | LinterType;
14
+ setParserOptionsProject?: boolean; // default is false
15
15
  /**
16
16
  * command to give playwright to run the web server
17
17
  * @example: "npx nx serve my-fe-app"
@@ -25,3 +25,10 @@ export interface ConfigurationGeneratorSchema {
25
25
  rootProject?: boolean;
26
26
  addPlugin?: boolean;
27
27
  }
28
+
29
+ export interface NormalizedGeneratorOptions
30
+ extends ConfigurationGeneratorSchema {
31
+ addPlugin: boolean;
32
+ directory: string;
33
+ linter: Linter | LinterType;
34
+ }
@@ -20,6 +20,12 @@
20
20
  "x-priority": "important",
21
21
  "default": "e2e"
22
22
  },
23
+ "linter": {
24
+ "description": "The tool to use for running lint checks.",
25
+ "type": "string",
26
+ "enum": ["none", "eslint"],
27
+ "x-priority": "important"
28
+ },
23
29
  "js": {
24
30
  "type": "boolean",
25
31
  "description": "Generate JavaScript files rather than TypeScript files.",
@@ -33,12 +39,6 @@
33
39
  "type": "string",
34
40
  "description": "The address of the web server."
35
41
  },
36
- "linter": {
37
- "description": "The tool to use for running lint checks.",
38
- "type": "string",
39
- "enum": ["eslint", "none"],
40
- "default": "eslint"
41
- },
42
42
  "setParserOptionsProject": {
43
43
  "type": "boolean",
44
44
  "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = addE2eCiTargetDefaults;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const target_defaults_utils_1 = require("@nx/devkit/src/generators/target-defaults-utils");
6
- const internal_api_1 = require("nx/src/project-graph/plugins/internal-api");
6
+ const loaded_nx_plugin_1 = require("nx/src/project-graph/plugins/loaded-nx-plugin");
7
7
  const devkit_internals_1 = require("nx/src/devkit-internals");
8
8
  const tsquery_1 = require("@phenomnomnominal/tsquery");
9
9
  const path_1 = require("path");
@@ -19,7 +19,7 @@ async function addE2eCiTargetDefaults(tree) {
19
19
  for (const plugin of matchingPluginRegistrations) {
20
20
  let projectConfigs;
21
21
  try {
22
- const loadedPlugin = new internal_api_1.LoadedNxPlugin({ createNodesV2, name: pluginName }, plugin);
22
+ const loadedPlugin = new loaded_nx_plugin_1.LoadedNxPlugin({ createNodesV2, name: pluginName }, plugin);
23
23
  projectConfigs = await (0, devkit_internals_1.retrieveProjectConfigurations)([loadedPlugin], tree.root, nxJson);
24
24
  }
25
25
  catch (e) {
@@ -4,11 +4,9 @@ exports.default = default_1;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const tsquery_1 = require("@phenomnomnominal/tsquery");
6
6
  const add_e2e_ci_target_defaults_1 = require("./add-e2e-ci-target-defaults");
7
- const internal_api_1 = require("nx/src/project-graph/plugins/internal-api");
7
+ const loaded_nx_plugin_1 = require("nx/src/project-graph/plugins/loaded-nx-plugin");
8
8
  const retrieve_workspace_files_1 = require("nx/src/project-graph/utils/retrieve-workspace-files");
9
9
  const error_types_1 = require("nx/src/project-graph/error-types");
10
- const plugin_1 = require("@nx/webpack/src/plugins/plugin");
11
- const plugin_2 = require("@nx/vite/plugin");
12
10
  async function default_1(tree) {
13
11
  const graph = await (0, devkit_1.createProjectGraphAsync)();
14
12
  const collectedProjects = [];
@@ -86,8 +84,9 @@ async function default_1(tree) {
86
84
  : 'preview', projectToMigrate.configFileType === 'webpack'
87
85
  ? 'serveStaticTargetName'
88
86
  : 'previewTargetName', projectToMigrate.configFileType === 'webpack'
89
- ? plugin_1.createNodesV2
90
- : plugin_2.createNodesV2)) ??
87
+ ? require('@nx/webpack/plugin').createNodesV2
88
+ : require('@nx/vite/plugin')
89
+ .createNodesV2)) ??
91
90
  getServeStaticLikeTarget(tree, graph, projectToMigrate.projectName, projectToMigrate.configFileType === 'webpack'
92
91
  ? '@nx/web:file-server'
93
92
  : '@nx/vite:preview-server');
@@ -143,7 +142,7 @@ async function getServeStaticTargetNameForConfigFile(tree, pluginName, configFil
143
142
  for (const plugin of matchingPluginRegistrations) {
144
143
  let projectConfigs;
145
144
  try {
146
- const loadedPlugin = new internal_api_1.LoadedNxPlugin({ createNodesV2, name: pluginName }, plugin);
145
+ const loadedPlugin = new loaded_nx_plugin_1.LoadedNxPlugin({ createNodesV2, name: pluginName }, plugin);
147
146
  projectConfigs = await (0, retrieve_workspace_files_1.retrieveProjectConfigurations)([loadedPlugin], tree.root, nxJson);
148
147
  }
149
148
  catch (e) {
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createNodes = exports.createNodesV2 = void 0;
4
- const fs_1 = require("fs");
5
- const path_1 = require("path");
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
6
  const devkit_1 = require("@nx/devkit");
7
7
  const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
8
8
  const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
@@ -14,7 +14,14 @@ const config_utils_1 = require("@nx/devkit/src/utils/config-utils");
14
14
  const file_hasher_1 = require("nx/src/hasher/file-hasher");
15
15
  const pmc = (0, devkit_1.getPackageManagerCommand)();
16
16
  function readTargetsCache(cachePath) {
17
- return (0, fs_1.existsSync)(cachePath) ? (0, devkit_1.readJsonFile)(cachePath) : {};
17
+ try {
18
+ return process.env.NX_CACHE_PROJECT_GRAPH !== 'false'
19
+ ? (0, devkit_1.readJsonFile)(cachePath)
20
+ : {};
21
+ }
22
+ catch {
23
+ return {};
24
+ }
18
25
  }
19
26
  function writeTargetsToCache(cachePath, results) {
20
27
  (0, devkit_1.writeJsonFile)(cachePath, results);
@@ -24,7 +31,7 @@ exports.createNodesV2 = [
24
31
  playwrightConfigGlob,
25
32
  async (configFilePaths, options, context) => {
26
33
  const optionsHash = (0, file_hasher_1.hashObject)(options);
27
- const cachePath = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `playwright-${optionsHash}.hash`);
34
+ const cachePath = (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, `playwright-${optionsHash}.hash`);
28
35
  const targetsCache = readTargetsCache(cachePath);
29
36
  try {
30
37
  return await (0, devkit_1.createNodesFromFiles)((configFile, options, context) => createNodesInternal(configFile, options, context, targetsCache), configFilePaths, options, context);
@@ -46,15 +53,15 @@ exports.createNodes = [
46
53
  },
47
54
  ];
48
55
  async function createNodesInternal(configFilePath, options, context, targetsCache) {
49
- const projectRoot = (0, path_1.dirname)(configFilePath);
56
+ const projectRoot = (0, node_path_1.dirname)(configFilePath);
50
57
  // Do not create a project if package.json and project.json isn't there.
51
- const siblingFiles = (0, fs_1.readdirSync)((0, path_1.join)(context.workspaceRoot, projectRoot));
58
+ const siblingFiles = (0, node_fs_1.readdirSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot));
52
59
  if (!siblingFiles.includes('package.json') &&
53
60
  !siblingFiles.includes('project.json')) {
54
61
  return {};
55
62
  }
56
63
  const normalizedOptions = normalizeOptions(options);
57
- const hash = await (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, options, context, [(0, js_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot))]);
64
+ const hash = await (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, normalizedOptions, context, [(0, js_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot))]);
58
65
  targetsCache[hash] ??= await buildPlaywrightTargets(configFilePath, projectRoot, normalizedOptions, context);
59
66
  const { targets, metadata } = targetsCache[hash];
60
67
  return {
@@ -72,16 +79,18 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
72
79
  // but we're just reading the config so let's delete the variable they are using to detect this.
73
80
  // See: https://github.com/microsoft/playwright/pull/11218/files
74
81
  delete process['__pw_initiator__'];
75
- const playwrightConfig = await (0, config_utils_1.loadConfigFile)((0, path_1.join)(context.workspaceRoot, configFilePath));
82
+ const playwrightConfig = await (0, config_utils_1.loadConfigFile)((0, node_path_1.join)(context.workspaceRoot, configFilePath));
76
83
  const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
77
84
  const targets = {};
78
85
  let metadata;
86
+ const testOutput = getTestOutput(playwrightConfig);
87
+ const reporterOutputs = getReporterOutputs(playwrightConfig);
88
+ const webserverCommandTasks = getWebserverCommandTasks(playwrightConfig);
79
89
  const baseTargetConfig = {
80
90
  command: 'playwright test',
81
91
  options: {
82
92
  cwd: '{projectRoot}',
83
93
  },
84
- parallelism: false,
85
94
  metadata: {
86
95
  technologies: ['playwright'],
87
96
  description: 'Runs Playwright Tests',
@@ -95,6 +104,12 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
95
104
  },
96
105
  },
97
106
  };
107
+ if (webserverCommandTasks.length) {
108
+ baseTargetConfig.dependsOn = getDependsOn(webserverCommandTasks);
109
+ }
110
+ else {
111
+ baseTargetConfig.parallelism = false;
112
+ }
98
113
  targets[options.targetName] = {
99
114
  ...baseTargetConfig,
100
115
  cache: true,
@@ -104,7 +119,7 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
104
119
  : ['default', '^default']),
105
120
  { externalDependencies: ['@playwright/test'] },
106
121
  ],
107
- outputs: getOutputs(projectRoot, playwrightConfig),
122
+ outputs: getTargetOutputs(testOutput, reporterOutputs, context.workspaceRoot, projectRoot),
108
123
  };
109
124
  if (options.ciTargetName) {
110
125
  const ciBaseTargetConfig = {
@@ -116,7 +131,7 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
116
131
  : ['default', '^default']),
117
132
  { externalDependencies: ['@playwright/test'] },
118
133
  ],
119
- outputs: getOutputs(projectRoot, playwrightConfig),
134
+ outputs: getTargetOutputs(testOutput, reporterOutputs, context.workspaceRoot, projectRoot),
120
135
  };
121
136
  const groupName = 'E2E (CI)';
122
137
  metadata = { targetGroups: { [groupName]: [] } };
@@ -128,12 +143,20 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
128
143
  playwrightConfig.testMatch ??= '**/*.@(spec|test).?(c|m)[jt]s?(x)';
129
144
  const dependsOn = [];
130
145
  await forEachTestFile((testFile) => {
131
- const relativeSpecFilePath = (0, devkit_1.normalizePath)((0, path_1.relative)(projectRoot, testFile));
146
+ const outputSubfolder = (0, node_path_1.relative)(projectRoot, testFile)
147
+ .replace(/[\/\\]/g, '-')
148
+ .replace(/\./g, '-');
149
+ const relativeSpecFilePath = (0, devkit_1.normalizePath)((0, node_path_1.relative)(projectRoot, testFile));
132
150
  const targetName = `${options.ciTargetName}--${relativeSpecFilePath}`;
133
151
  ciTargetGroup.push(targetName);
134
152
  targets[targetName] = {
135
153
  ...ciBaseTargetConfig,
136
- command: `${baseTargetConfig.command} ${relativeSpecFilePath}`,
154
+ options: {
155
+ ...ciBaseTargetConfig.options,
156
+ env: getOutputEnvVars(reporterOutputs, outputSubfolder),
157
+ },
158
+ outputs: getTargetOutputs(testOutput, reporterOutputs, context.workspaceRoot, projectRoot, outputSubfolder),
159
+ command: `${baseTargetConfig.command} ${relativeSpecFilePath} --output=${(0, node_path_1.join)(testOutput, outputSubfolder)}`,
137
160
  metadata: {
138
161
  technologies: ['playwright'],
139
162
  description: `Runs Playwright Tests in ${relativeSpecFilePath} in CI`,
@@ -164,7 +187,6 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
164
187
  inputs: ciBaseTargetConfig.inputs,
165
188
  outputs: ciBaseTargetConfig.outputs,
166
189
  dependsOn,
167
- parallelism: false,
168
190
  metadata: {
169
191
  technologies: ['playwright'],
170
192
  description: 'Runs Playwright Tests in CI',
@@ -179,6 +201,9 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
179
201
  },
180
202
  },
181
203
  };
204
+ if (!webserverCommandTasks.length) {
205
+ targets[options.ciTargetName].parallelism = false;
206
+ }
182
207
  ciTargetGroup.push(options.ciTargetName);
183
208
  }
184
209
  return { targets, metadata };
@@ -214,58 +239,141 @@ function createMatcher(pattern) {
214
239
  };
215
240
  }
216
241
  }
217
- function getOutputs(projectRoot, playwrightConfig) {
218
- function getOutput(path) {
219
- if (path.startsWith('..')) {
220
- return (0, path_1.join)('{workspaceRoot}', (0, path_1.join)(projectRoot, path));
221
- }
222
- else {
223
- return (0, path_1.join)('{projectRoot}', path);
224
- }
242
+ function normalizeOptions(options) {
243
+ return {
244
+ ...options,
245
+ targetName: options?.targetName ?? 'e2e',
246
+ ciTargetName: options?.ciTargetName ?? 'e2e-ci',
247
+ };
248
+ }
249
+ function getTestOutput(playwrightConfig) {
250
+ const { outputDir } = playwrightConfig;
251
+ if (outputDir) {
252
+ return outputDir;
253
+ }
254
+ else {
255
+ return './test-results';
225
256
  }
257
+ }
258
+ function getReporterOutputs(playwrightConfig) {
226
259
  const outputs = [];
227
- const { reporter, outputDir } = playwrightConfig;
260
+ const { reporter } = playwrightConfig;
228
261
  if (reporter) {
229
- const DEFAULT_REPORTER_OUTPUT = getOutput('playwright-report');
230
- if (reporter === 'html' || reporter === 'json') {
231
- // Reporter is a string, so it uses the default output directory.
232
- outputs.push(DEFAULT_REPORTER_OUTPUT);
262
+ const DEFAULT_REPORTER_OUTPUT = 'playwright-report';
263
+ if (reporter === 'html') {
264
+ outputs.push([reporter, DEFAULT_REPORTER_OUTPUT]);
265
+ }
266
+ else if (reporter === 'json') {
267
+ outputs.push([reporter, DEFAULT_REPORTER_OUTPUT]);
233
268
  }
234
269
  else if (Array.isArray(reporter)) {
235
270
  for (const r of reporter) {
236
- const [, opts] = r;
271
+ const [reporter, opts] = r;
237
272
  // There are a few different ways to specify an output file or directory
238
273
  // depending on the reporter. This is a best effort to find the output.
239
- if (!opts) {
240
- outputs.push(DEFAULT_REPORTER_OUTPUT);
241
- }
242
- else if (opts.outputFile) {
243
- outputs.push(getOutput(opts.outputFile));
274
+ if (opts?.outputFile) {
275
+ outputs.push([reporter, opts.outputFile]);
244
276
  }
245
- else if (opts.outputDir) {
246
- outputs.push(getOutput(opts.outputDir));
277
+ else if (opts?.outputDir) {
278
+ outputs.push([reporter, opts.outputDir]);
247
279
  }
248
- else if (opts.outputFolder) {
249
- outputs.push(getOutput(opts.outputFolder));
280
+ else if (opts?.outputFolder) {
281
+ outputs.push([reporter, opts.outputFolder]);
250
282
  }
251
283
  else {
252
- outputs.push(DEFAULT_REPORTER_OUTPUT);
284
+ outputs.push([reporter, DEFAULT_REPORTER_OUTPUT]);
253
285
  }
254
286
  }
255
287
  }
256
288
  }
257
- if (outputDir) {
258
- outputs.push(getOutput(outputDir));
289
+ return outputs;
290
+ }
291
+ function getTargetOutputs(testOutput, reporterOutputs, workspaceRoot, projectRoot, subFolder) {
292
+ const outputs = new Set();
293
+ outputs.add(normalizeOutput(addSubfolderToOutput(testOutput, subFolder), workspaceRoot, projectRoot));
294
+ for (const [, output] of reporterOutputs) {
295
+ outputs.add(normalizeOutput(addSubfolderToOutput(output, subFolder), workspaceRoot, projectRoot));
259
296
  }
260
- else {
261
- outputs.push(getOutput('./test-results'));
297
+ return Array.from(outputs);
298
+ }
299
+ function addSubfolderToOutput(output, subfolder) {
300
+ if (!subfolder)
301
+ return output;
302
+ const parts = (0, node_path_1.parse)(output);
303
+ if (parts.ext !== '') {
304
+ return (0, node_path_1.join)(parts.dir, subfolder, parts.base);
262
305
  }
263
- return outputs;
306
+ return (0, node_path_1.join)(output, subfolder);
264
307
  }
265
- function normalizeOptions(options) {
266
- return {
267
- ...options,
268
- targetName: options.targetName ?? 'e2e',
269
- ciTargetName: options.ciTargetName ?? 'e2e-ci',
270
- };
308
+ function getWebserverCommandTasks(playwrightConfig) {
309
+ if (!playwrightConfig.webServer) {
310
+ return [];
311
+ }
312
+ const tasks = [];
313
+ const webServer = Array.isArray(playwrightConfig.webServer)
314
+ ? playwrightConfig.webServer
315
+ : [playwrightConfig.webServer];
316
+ for (const server of webServer) {
317
+ if (!server.reuseExistingServer) {
318
+ continue;
319
+ }
320
+ const task = parseTaskFromCommand(server.command);
321
+ if (task) {
322
+ tasks.push(task);
323
+ }
324
+ }
325
+ return tasks;
326
+ }
327
+ function parseTaskFromCommand(command) {
328
+ const nxRunRegex = /^(?:(?:npx|yarn|bun|pnpm|pnpm exec|pnpx) )?nx run (\S+:\S+)$/;
329
+ const infixRegex = /^(?:(?:npx|yarn|bun|pnpm|pnpm exec|pnpx) )?nx (\S+ \S+)$/;
330
+ const nxRunMatch = command.match(nxRunRegex);
331
+ if (nxRunMatch) {
332
+ const [project, target] = nxRunMatch[1].split(':');
333
+ return { project, target };
334
+ }
335
+ const infixMatch = command.match(infixRegex);
336
+ if (infixMatch) {
337
+ const [target, project] = infixMatch[1].split(' ');
338
+ return { project, target };
339
+ }
340
+ return null;
341
+ }
342
+ function getDependsOn(tasks) {
343
+ const projectsPerTask = new Map();
344
+ for (const { project, target } of tasks) {
345
+ if (!projectsPerTask.has(target)) {
346
+ projectsPerTask.set(target, []);
347
+ }
348
+ projectsPerTask.get(target).push(project);
349
+ }
350
+ return Array.from(projectsPerTask.entries()).map(([target, projects]) => ({
351
+ projects,
352
+ target,
353
+ }));
354
+ }
355
+ function normalizeOutput(path, workspaceRoot, projectRoot) {
356
+ const fullProjectRoot = (0, node_path_1.resolve)(workspaceRoot, projectRoot);
357
+ const fullPath = (0, node_path_1.resolve)(fullProjectRoot, path);
358
+ const pathRelativeToProjectRoot = (0, devkit_1.normalizePath)((0, node_path_1.relative)(fullProjectRoot, fullPath));
359
+ if (pathRelativeToProjectRoot.startsWith('..')) {
360
+ return (0, devkit_1.joinPathFragments)('{workspaceRoot}', (0, node_path_1.relative)(workspaceRoot, fullPath));
361
+ }
362
+ return (0, devkit_1.joinPathFragments)('{projectRoot}', pathRelativeToProjectRoot);
363
+ }
364
+ function getOutputEnvVars(reporterOutputs, outputSubfolder) {
365
+ const env = {};
366
+ for (let [reporter, output] of reporterOutputs) {
367
+ if (outputSubfolder) {
368
+ const isFile = (0, node_path_1.parse)(output).ext !== '';
369
+ const envVarName = `PLAYWRIGHT_${reporter.toUpperCase()}_OUTPUT_${isFile ? 'FILE' : 'DIR'}`;
370
+ env[envVarName] = addSubfolderToOutput(output, outputSubfolder);
371
+ // Also set PLAYWRIGHT_HTML_REPORT for Playwright prior to 1.45.0.
372
+ // HTML prior to this version did not follow the pattern of "PLAYWRIGHT_<REPORTER>_OUTPUT_<FILE|DIR>".
373
+ if (reporter === 'html') {
374
+ env['PLAYWRIGHT_HTML_REPORT'] = env[envVarName];
375
+ }
376
+ }
377
+ }
378
+ return env;
271
379
  }
@@ -8,7 +8,7 @@ const versions_1 = require("./versions");
8
8
  const eslint_file_1 = require("@nx/eslint/src/generators/utils/eslint-file");
9
9
  const flat_config_1 = require("@nx/eslint/src/utils/flat-config");
10
10
  async function addLinterToPlaywrightProject(tree, options) {
11
- if (options.linter === eslint_1.Linter.None) {
11
+ if (options.linter === 'none') {
12
12
  return () => { };
13
13
  }
14
14
  const tasks = [];
@@ -26,7 +26,7 @@ async function addLinterToPlaywrightProject(tree, options) {
26
26
  addPlugin: options.addPlugin,
27
27
  }));
28
28
  }
29
- if (!options.linter || options.linter !== eslint_1.Linter.EsLint) {
29
+ if (!options.linter || options.linter !== 'eslint') {
30
30
  return (0, devkit_1.runTasksInSerial)(...tasks);
31
31
  }
32
32
  tasks.push(!options.skipPackageJson
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nxE2EPreset = nxE2EPreset;
4
4
  const devkit_1 = require("@nx/devkit");
5
+ const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
6
+ const test_1 = require("@playwright/test");
5
7
  const node_fs_1 = require("node:fs");
6
8
  const node_path_1 = require("node:path");
7
- const test_1 = require("@playwright/test");
8
9
  /**
9
10
  * nx E2E Preset for Playwright
10
11
  * @description
@@ -33,8 +34,13 @@ function nxE2EPreset(pathToConfig, options) {
33
34
  : (0, node_path_1.dirname)(pathToConfig);
34
35
  const projectPath = (0, node_path_1.relative)(devkit_1.workspaceRoot, normalizedPath);
35
36
  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');
37
+ const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)();
38
+ const testResultOuputDir = isTsSolutionSetup
39
+ ? 'test-output/playwright/output'
40
+ : (0, node_path_1.join)(offset, 'dist', '.playwright', projectPath, 'test-output');
41
+ const reporterOutputDir = isTsSolutionSetup
42
+ ? 'test-output/playwright/report'
43
+ : (0, node_path_1.join)(offset, 'dist', '.playwright', projectPath, 'playwright-report');
38
44
  return (0, test_1.defineConfig)({
39
45
  testDir: options?.testDir ?? './src',
40
46
  outputDir: testResultOuputDir,
package/README.md DELETED
@@ -1,66 +0,0 @@
1
- <p style="text-align: center;">
2
- <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
4
- <img alt="Nx - Smart Monorepos · Fast CI" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
5
- </picture>
6
- </p>
7
-
8
- <div style="text-align: center;">
9
-
10
- [![CircleCI](https://circleci.com/gh/nrwl/nx.svg?style=svg)](https://circleci.com/gh/nrwl/nx)
11
- [![License](https://img.shields.io/npm/l/@nx/workspace.svg?style=flat-square)]()
12
- [![NPM Version](https://badge.fury.io/js/%40nrwl%2Fworkspace.svg)](https://www.npmjs.com/@nx/workspace)
13
- [![Semantic Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)]()
14
- [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
15
- [![Join the chat at https://gitter.im/nrwl-nx/community](https://badges.gitter.im/nrwl-nx/community.svg)](https://gitter.im/nrwl-nx/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
16
- [![Join us on the Official Nx Discord Server](https://img.shields.io/discord/1143497901675401286?label=discord)](https://go.nx.dev/community)
17
-
18
- </div>
19
-
20
-
21
- <hr>
22
-
23
- # Nx: Smart Monorepos · Fast CI
24
-
25
- Nx is a build system, optimized for monorepos, with plugins for popular frameworks and tools and advanced CI capabilities including caching and distribution.
26
-
27
- ## Getting Started
28
-
29
- ### Creating an Nx Workspace
30
-
31
- **Using `npx`**
32
-
33
- ```bash
34
- npx create-nx-workspace
35
- ```
36
-
37
- **Using `npm init`**
38
-
39
- ```bash
40
- npm init nx-workspace
41
- ```
42
-
43
- **Using `yarn create`**
44
-
45
- ```bash
46
- yarn create nx-workspace
47
- ```
48
-
49
- ### Adding Nx to an Existing Repository
50
-
51
- Run:
52
-
53
- ```bash
54
- npx nx@latest init
55
- ```
56
-
57
- ## Documentation & Resources
58
-
59
- - [Nx.Dev: Documentation, Guides, Tutorials](https://nx.dev)
60
- - [Intro to Nx](https://nx.dev/getting-started/intro)
61
- - [Official Nx YouTube Channel](https://www.youtube.com/@NxDevtools)
62
- - [Blog Posts About Nx](https://nx.dev/blog)
63
-
64
- <p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-courses-and-videos.svg"
65
- width="100%" alt="Nx - Smart Monorepos · Fast CI"></a></p>
66
-
@@ -1,2 +0,0 @@
1
- import { Tree } from '@nx/devkit';
2
- export default function update(tree: Tree): Promise<void>;
@@ -1,95 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = update;
4
- const devkit_1 = require("@nx/devkit");
5
- const ts = require("typescript");
6
- const tsquery_1 = require("@phenomnomnominal/tsquery");
7
- async function update(tree) {
8
- const projects = (0, devkit_1.getProjects)(tree);
9
- projects.forEach((project) => {
10
- // Check if the project contains playwright config
11
- const configPath = (0, devkit_1.joinPathFragments)(project.root, 'playwright.config.ts');
12
- if (tree.exists(configPath)) {
13
- addProjectIfExists(tree, (0, devkit_1.joinPathFragments)(configPath));
14
- }
15
- });
16
- }
17
- function addProjectIfExists(tree, configFilePath) {
18
- const configFileContent = tree.read(configFilePath, 'utf-8');
19
- const sourceFile = tsquery_1.tsquery.ast(configFileContent);
20
- const printer = ts.createPrinter();
21
- const updatedStatements = updateOrCreateImportStatement(sourceFile, '@playwright/test', ['devices']);
22
- const exportAssignment = tsquery_1.tsquery.query(sourceFile, 'ExportAssignment')[0];
23
- if (!exportAssignment) {
24
- // No export found in the file
25
- return;
26
- }
27
- const exportAssignemntObject = exportAssignment.expression;
28
- if (!(ts.isCallExpression(exportAssignemntObject) &&
29
- exportAssignemntObject.getText(sourceFile).startsWith('defineConfig') &&
30
- exportAssignemntObject.arguments.length > 0)) {
31
- // Export is not a call expression with defineConfig ex. export default defineConfig({ ... })
32
- return;
33
- }
34
- let firstArgument = exportAssignemntObject.arguments[0];
35
- if (!ts.isObjectLiteralExpression(firstArgument)) {
36
- // First argument is not an object literal ex. defineConfig('foo')
37
- return;
38
- }
39
- const projectProperty = tsquery_1.tsquery.query(exportAssignemntObject, 'PropertyAssignment > Identifier[name="projects"]')[0];
40
- if (projectProperty) {
41
- // Projects property already exists in the config
42
- return;
43
- }
44
- // Add projects property to the config
45
- const projectsArray = ts.factory.createArrayLiteralExpression([
46
- createProperty('chromium', 'Desktop Chrome'),
47
- createProperty('firefox', 'Desktop Firefox'),
48
- createProperty('webkit', 'Desktop Safari'),
49
- ], true);
50
- const newProjectsProperty = ts.factory.createPropertyAssignment('projects', projectsArray);
51
- const newObj = ts.factory.createObjectLiteralExpression([
52
- ...firstArgument.properties,
53
- newProjectsProperty,
54
- ]);
55
- const newCallExpression = ts.factory.updateCallExpression(exportAssignemntObject, exportAssignemntObject.expression, exportAssignemntObject.typeArguments, [newObj]);
56
- const newExportAssignment = ts.factory.updateExportAssignment(exportAssignment, exportAssignment.modifiers, newCallExpression);
57
- const transformedStatements = updatedStatements.map((statement) => {
58
- return statement === exportAssignment ? newExportAssignment : statement;
59
- });
60
- const transformedSourceFile = ts.factory.updateSourceFile(sourceFile, transformedStatements);
61
- const updatedConfigFileContent = printer.printFile(transformedSourceFile);
62
- tree.write(configFilePath, updatedConfigFileContent);
63
- }
64
- function createProperty(name, device) {
65
- return ts.factory.createObjectLiteralExpression([
66
- ts.factory.createPropertyAssignment('name', ts.factory.createStringLiteral(name)),
67
- ts.factory.createPropertyAssignment('use', ts.factory.createObjectLiteralExpression([
68
- ts.factory.createSpreadAssignment(ts.factory.createElementAccessExpression(ts.factory.createIdentifier('devices'), ts.factory.createStringLiteral(device))),
69
- ])),
70
- ]);
71
- }
72
- function updateOrCreateImportStatement(sourceFile, moduleName, importNames) {
73
- let importDeclarationFound = false;
74
- const newStatements = sourceFile.statements.map((statement) => {
75
- if (ts.isImportDeclaration(statement) &&
76
- statement.moduleSpecifier.getText(sourceFile) === `'${moduleName}'`) {
77
- importDeclarationFound = true;
78
- const existingSpecifiers = statement.importClause?.namedBindings &&
79
- ts.isNamedImports(statement.importClause.namedBindings)
80
- ? statement.importClause.namedBindings.elements.map((e) => e.name.text)
81
- : [];
82
- // Merge with new import names, avoiding duplicates
83
- const mergedImportNames = Array.from(new Set([...existingSpecifiers, ...importNames]));
84
- // Create new import specifiers
85
- const importSpecifiers = mergedImportNames.map((name) => ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(name)));
86
- return ts.factory.updateImportDeclaration(statement, statement.modifiers, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports(importSpecifiers)), statement.moduleSpecifier, undefined);
87
- }
88
- return statement;
89
- });
90
- if (!importDeclarationFound) {
91
- const importDeclaration = ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports(importNames.map((name) => ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(name))))), ts.factory.createStringLiteral(moduleName));
92
- newStatements.push(importDeclaration);
93
- }
94
- return newStatements;
95
- }
@@ -1,2 +0,0 @@
1
- import { type Tree } from '@nx/devkit';
2
- export default function (tree: Tree): Promise<void>;
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = default_1;
4
- const devkit_1 = require("@nx/devkit");
5
- const executor_options_utils_1 = require("@nx/devkit/src/generators/executor-options-utils");
6
- async function default_1(tree) {
7
- (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nx/playwright:playwright', (options, projectName, targetName, configurationName) => {
8
- if (options?.['baseUrl']) {
9
- const project = (0, devkit_1.readProjectConfiguration)(tree, projectName);
10
- if (configurationName) {
11
- delete project.targets[targetName].configurations[configurationName]['baseUrl'];
12
- }
13
- else {
14
- delete project.targets[targetName].options['baseUrl'];
15
- }
16
- (0, devkit_1.updateProjectConfiguration)(tree, projectName, project);
17
- }
18
- });
19
- const nxJson = (0, devkit_1.readNxJson)(tree);
20
- for (const [targetNameOrExecutor, target] of Object.entries(nxJson.targetDefaults)) {
21
- if (targetNameOrExecutor === '@nx/playwright:playwright' ||
22
- (target.executor && target.executor === '@nx/playwright:playwright')) {
23
- let updated = false;
24
- if (target.options?.['baseUrl']) {
25
- delete nxJson.targetDefaults[targetNameOrExecutor].options['baseUrl'];
26
- updated = true;
27
- }
28
- if (target.configurations) {
29
- for (const [configurationName, configuration] of Object.entries(target.configurations)) {
30
- if (configuration['baseUrl']) {
31
- delete nxJson.targetDefaults[targetNameOrExecutor].configurations[configurationName]['baseUrl'];
32
- updated = true;
33
- }
34
- }
35
- }
36
- if (updated) {
37
- (0, devkit_1.updateNxJson)(tree, nxJson);
38
- }
39
- }
40
- }
41
- await (0, devkit_1.formatFiles)(tree);
42
- }