@nx/playwright 20.0.10 → 20.1.0-beta.1

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/playwright",
3
- "version": "20.0.10",
3
+ "version": "20.1.0-beta.1",
4
4
  "type": "commonjs",
5
5
  "homepage": "https://nx.dev",
6
6
  "private": false,
@@ -35,11 +35,11 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@phenomnomnominal/tsquery": "~5.0.1",
38
- "@nx/devkit": "20.0.10",
39
- "@nx/eslint": "20.0.10",
40
- "@nx/webpack": "20.0.10",
41
- "@nx/vite": "20.0.10",
42
- "@nx/js": "20.0.10",
38
+ "@nx/devkit": "20.1.0-beta.1",
39
+ "@nx/eslint": "20.1.0-beta.1",
40
+ "@nx/webpack": "20.1.0-beta.1",
41
+ "@nx/vite": "20.1.0-beta.1",
42
+ "@nx/js": "20.1.0-beta.1",
43
43
  "tslib": "^2.3.0",
44
44
  "minimatch": "9.0.3"
45
45
  },
@@ -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,23 +3,22 @@ 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");
9
+ const package_manager_workspaces_1 = require("@nx/js/src/utils/package-manager-workspaces");
10
+ const ensure_typescript_1 = require("@nx/js/src/utils/typescript/ensure-typescript");
7
11
  const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
8
- const versions_1 = require("@nx/js/src/utils/versions");
9
12
  const child_process_1 = require("child_process");
10
13
  const path = require("path");
11
14
  const add_linter_1 = require("../../utils/add-linter");
12
- const versions_2 = require("../../utils/versions");
15
+ const versions_1 = require("../../utils/versions");
13
16
  const init_1 = require("../init/init");
14
17
  function configurationGenerator(tree, options) {
15
18
  return configurationGeneratorInternal(tree, { addPlugin: false, ...options });
16
19
  }
17
- async function configurationGeneratorInternal(tree, options) {
18
- (0, ts_solution_setup_1.assertNotUsingTsSolutionSetup)(tree, 'playwright', 'configuration');
19
- const nxJson = (0, devkit_1.readNxJson)(tree);
20
- options.addPlugin ??=
21
- process.env.NX_ADD_PLUGINS !== 'false' &&
22
- nxJson.useInferencePlugins !== false;
20
+ async function configurationGeneratorInternal(tree, rawOptions) {
21
+ const options = await normalizeOptions(tree, rawOptions);
23
22
  const tasks = [];
24
23
  tasks.push(await (0, init_1.initGenerator)(tree, {
25
24
  skipFormat: true,
@@ -27,7 +26,6 @@ async function configurationGeneratorInternal(tree, options) {
27
26
  addPlugin: options.addPlugin,
28
27
  }));
29
28
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
30
- const hasTsConfig = tree.exists((0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json'));
31
29
  const offsetFromProjectRoot = (0, devkit_1.offsetFromRoot)(projectConfig.root);
32
30
  (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'files'), projectConfig.root, {
33
31
  offsetFromRoot: offsetFromProjectRoot,
@@ -36,13 +34,14 @@ async function configurationGeneratorInternal(tree, options) {
36
34
  webServerAddress: options.webServerAddress ?? null,
37
35
  ...options,
38
36
  });
39
- if (!hasTsConfig) {
40
- tree.write(`${projectConfig.root}/tsconfig.json`, JSON.stringify({
37
+ const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
38
+ const tsconfigPath = (0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json');
39
+ if (!tree.exists(tsconfigPath)) {
40
+ const tsconfig = {
41
41
  extends: (0, js_1.getRelativePathToRootTsConfig)(tree, projectConfig.root),
42
42
  compilerOptions: {
43
43
  allowJs: true,
44
44
  outDir: `${offsetFromProjectRoot}dist/out-tsc`,
45
- module: 'commonjs',
46
45
  sourceMap: false,
47
46
  },
48
47
  include: [
@@ -55,7 +54,37 @@ async function configurationGeneratorInternal(tree, options) {
55
54
  'src/**/*.test.js',
56
55
  'src/**/*.d.ts',
57
56
  ],
58
- }, null, 2));
57
+ };
58
+ if (isTsSolutionSetup) {
59
+ tsconfig.compilerOptions.outDir = 'dist';
60
+ tsconfig.compilerOptions.tsBuildInfoFile = 'dist/tsconfig.tsbuildinfo';
61
+ if (!options.rootProject) {
62
+ // add the project tsconfog to the workspace root tsconfig.json references
63
+ (0, devkit_1.updateJson)(tree, 'tsconfig.json', (json) => {
64
+ json.references ??= [];
65
+ json.references.push({ path: './' + projectConfig.root });
66
+ return json;
67
+ });
68
+ }
69
+ }
70
+ else {
71
+ tsconfig.compilerOptions.outDir = `${offsetFromProjectRoot}dist/out-tsc`;
72
+ tsconfig.compilerOptions.module = 'commonjs';
73
+ }
74
+ (0, devkit_1.writeJson)(tree, tsconfigPath, tsconfig);
75
+ }
76
+ if (isTsSolutionSetup) {
77
+ const packageJsonPath = (0, devkit_1.joinPathFragments)(projectConfig.root, 'package.json');
78
+ if (!tree.exists(packageJsonPath)) {
79
+ const importPath = (0, project_name_and_root_utils_1.resolveImportPath)(tree, projectConfig.name, projectConfig.root);
80
+ const packageJson = {
81
+ name: importPath,
82
+ version: '0.0.1',
83
+ private: true,
84
+ };
85
+ (0, devkit_1.writeJson)(tree, packageJsonPath, packageJson);
86
+ }
87
+ ignoreTestOutput(tree);
59
88
  }
60
89
  const hasPlugin = (0, devkit_1.readNxJson)(tree).plugins?.some((p) => typeof p === 'string'
61
90
  ? p === '@nx/playwright/plugin'
@@ -75,14 +104,14 @@ async function configurationGeneratorInternal(tree, options) {
75
104
  addPlugin: options.addPlugin,
76
105
  }));
77
106
  if (options.js) {
78
- const { ModuleKind } = (0, devkit_1.ensurePackage)('typescript', versions_1.typescriptVersion);
107
+ const { ModuleKind } = (0, ensure_typescript_1.ensureTypescript)();
79
108
  (0, devkit_1.toJS)(tree, { extension: '.cjs', module: ModuleKind.CommonJS });
80
109
  }
81
110
  recommendVsCodeExtensions(tree);
82
111
  if (!options.skipPackageJson) {
83
112
  tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
84
113
  // required since used in playwright config
85
- '@nx/devkit': versions_2.nxVersion,
114
+ '@nx/devkit': versions_1.nxVersion,
86
115
  }));
87
116
  }
88
117
  if (!options.skipInstall) {
@@ -91,8 +120,46 @@ async function configurationGeneratorInternal(tree, options) {
91
120
  if (!options.skipFormat) {
92
121
  await (0, devkit_1.formatFiles)(tree);
93
122
  }
123
+ if (isTsSolutionSetup) {
124
+ const projectPackageManagerWorkspaceState = (0, package_manager_workspaces_1.getProjectPackageManagerWorkspaceState)(tree, projectConfig.root);
125
+ if (projectPackageManagerWorkspaceState !== 'included') {
126
+ tasks.push((0, package_manager_workspaces_1.getProjectPackageManagerWorkspaceStateWarningTask)(projectPackageManagerWorkspaceState, tree.root));
127
+ }
128
+ }
94
129
  return (0, devkit_1.runTasksInSerial)(...tasks);
95
130
  }
131
+ async function normalizeOptions(tree, options) {
132
+ const nxJson = (0, devkit_1.readNxJson)(tree);
133
+ const addPlugin = options.addPlugin ??
134
+ (process.env.NX_ADD_PLUGINS !== 'false' &&
135
+ nxJson.useInferencePlugins !== false);
136
+ const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
137
+ let linter = options.linter;
138
+ if (isTsSolutionSetup) {
139
+ linter ??= await (0, prompt_1.promptWhenInteractive)({
140
+ type: 'select',
141
+ name: 'linter',
142
+ message: `Which linter would you like to use?`,
143
+ choices: [{ name: 'none' }, { name: 'eslint' }],
144
+ initial: 0,
145
+ }, { linter: 'none' }).then(({ linter }) => linter);
146
+ }
147
+ else {
148
+ linter ??= await (0, prompt_1.promptWhenInteractive)({
149
+ type: 'select',
150
+ name: 'linter',
151
+ message: `Which linter would you like to use?`,
152
+ choices: [{ name: 'eslint' }, { name: 'none' }],
153
+ initial: 0,
154
+ }, { linter: 'eslint' }).then(({ linter }) => linter);
155
+ }
156
+ return {
157
+ ...options,
158
+ addPlugin,
159
+ linter,
160
+ directory: options.directory ?? 'e2e',
161
+ };
162
+ }
96
163
  function getBrowsersInstallTask() {
97
164
  return () => {
98
165
  devkit_1.output.log({
@@ -154,4 +221,15 @@ Rename or remove the existing e2e target.`);
154
221
  };
155
222
  (0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
156
223
  }
224
+ function ignoreTestOutput(tree) {
225
+ if (!tree.exists('.gitignore')) {
226
+ devkit_1.logger.warn(`Couldn't find a root .gitignore file to update.`);
227
+ }
228
+ let content = tree.read('.gitignore', 'utf-8');
229
+ if (/^test-output$/gm.test(content)) {
230
+ return;
231
+ }
232
+ content = `${content}\ntest-output\n`;
233
+ tree.write('.gitignore', content);
234
+ }
157
235
  exports.default = configurationGenerator;
@@ -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.",
@@ -4,14 +4,12 @@ exports.initGenerator = initGenerator;
4
4
  exports.initGeneratorInternal = initGeneratorInternal;
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const add_plugin_1 = require("@nx/devkit/src/utils/add-plugin");
7
- const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
8
7
  const plugin_1 = require("../../plugins/plugin");
9
8
  const versions_1 = require("../../utils/versions");
10
9
  function initGenerator(tree, options) {
11
10
  return initGeneratorInternal(tree, { addPlugin: false, ...options });
12
11
  }
13
12
  async function initGeneratorInternal(tree, options) {
14
- (0, ts_solution_setup_1.assertNotUsingTsSolutionSetup)(tree, 'playwright', 'init');
15
13
  const tasks = [];
16
14
  const nxJson = (0, devkit_1.readNxJson)(tree);
17
15
  const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
@@ -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,7 @@ 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
+ return (0, node_fs_1.existsSync)(cachePath) ? (0, devkit_1.readJsonFile)(cachePath) : {};
18
18
  }
19
19
  function writeTargetsToCache(cachePath, results) {
20
20
  (0, devkit_1.writeJsonFile)(cachePath, results);
@@ -24,7 +24,7 @@ exports.createNodesV2 = [
24
24
  playwrightConfigGlob,
25
25
  async (configFilePaths, options, context) => {
26
26
  const optionsHash = (0, file_hasher_1.hashObject)(options);
27
- const cachePath = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `playwright-${optionsHash}.hash`);
27
+ const cachePath = (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, `playwright-${optionsHash}.hash`);
28
28
  const targetsCache = readTargetsCache(cachePath);
29
29
  try {
30
30
  return await (0, devkit_1.createNodesFromFiles)((configFile, options, context) => createNodesInternal(configFile, options, context, targetsCache), configFilePaths, options, context);
@@ -46,9 +46,9 @@ exports.createNodes = [
46
46
  },
47
47
  ];
48
48
  async function createNodesInternal(configFilePath, options, context, targetsCache) {
49
- const projectRoot = (0, path_1.dirname)(configFilePath);
49
+ const projectRoot = (0, node_path_1.dirname)(configFilePath);
50
50
  // 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));
51
+ const siblingFiles = (0, node_fs_1.readdirSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot));
52
52
  if (!siblingFiles.includes('package.json') &&
53
53
  !siblingFiles.includes('project.json')) {
54
54
  return {};
@@ -72,10 +72,12 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
72
72
  // but we're just reading the config so let's delete the variable they are using to detect this.
73
73
  // See: https://github.com/microsoft/playwright/pull/11218/files
74
74
  delete process['__pw_initiator__'];
75
- const playwrightConfig = await (0, config_utils_1.loadConfigFile)((0, path_1.join)(context.workspaceRoot, configFilePath));
75
+ const playwrightConfig = await (0, config_utils_1.loadConfigFile)((0, node_path_1.join)(context.workspaceRoot, configFilePath));
76
76
  const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
77
77
  const targets = {};
78
78
  let metadata;
79
+ const testOutput = getTestOutput(playwrightConfig);
80
+ const reporterOutputs = getReporterOutputs(playwrightConfig);
79
81
  const baseTargetConfig = {
80
82
  command: 'playwright test',
81
83
  options: {
@@ -104,7 +106,7 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
104
106
  : ['default', '^default']),
105
107
  { externalDependencies: ['@playwright/test'] },
106
108
  ],
107
- outputs: getOutputs(projectRoot, playwrightConfig),
109
+ outputs: getTargetOutputs(testOutput, reporterOutputs, projectRoot),
108
110
  };
109
111
  if (options.ciTargetName) {
110
112
  const ciBaseTargetConfig = {
@@ -116,7 +118,7 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
116
118
  : ['default', '^default']),
117
119
  { externalDependencies: ['@playwright/test'] },
118
120
  ],
119
- outputs: getOutputs(projectRoot, playwrightConfig),
121
+ outputs: getTargetOutputs(testOutput, reporterOutputs, projectRoot),
120
122
  };
121
123
  const groupName = 'E2E (CI)';
122
124
  metadata = { targetGroups: { [groupName]: [] } };
@@ -128,12 +130,20 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
128
130
  playwrightConfig.testMatch ??= '**/*.@(spec|test).?(c|m)[jt]s?(x)';
129
131
  const dependsOn = [];
130
132
  await forEachTestFile((testFile) => {
131
- const relativeSpecFilePath = (0, devkit_1.normalizePath)((0, path_1.relative)(projectRoot, testFile));
133
+ const outputSubfolder = (0, node_path_1.relative)(projectRoot, testFile)
134
+ .replace(/[\/\\]/g, '-')
135
+ .replace(/\./g, '-');
136
+ const relativeSpecFilePath = (0, devkit_1.normalizePath)((0, node_path_1.relative)(projectRoot, testFile));
132
137
  const targetName = `${options.ciTargetName}--${relativeSpecFilePath}`;
133
138
  ciTargetGroup.push(targetName);
134
139
  targets[targetName] = {
135
140
  ...ciBaseTargetConfig,
136
- command: `${baseTargetConfig.command} ${relativeSpecFilePath}`,
141
+ options: {
142
+ ...ciBaseTargetConfig.options,
143
+ env: getOutputEnvVars(reporterOutputs, outputSubfolder),
144
+ },
145
+ outputs: getTargetOutputs(testOutput, reporterOutputs, projectRoot, outputSubfolder),
146
+ command: `${baseTargetConfig.command} ${relativeSpecFilePath} --output=${(0, node_path_1.join)(testOutput, outputSubfolder)}`,
137
147
  metadata: {
138
148
  technologies: ['playwright'],
139
149
  description: `Runs Playwright Tests in ${relativeSpecFilePath} in CI`,
@@ -214,58 +224,84 @@ function createMatcher(pattern) {
214
224
  };
215
225
  }
216
226
  }
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
- }
227
+ function normalizeOptions(options) {
228
+ return {
229
+ ...options,
230
+ targetName: options.targetName ?? 'e2e',
231
+ ciTargetName: options.ciTargetName ?? 'e2e-ci',
232
+ };
233
+ }
234
+ function getTestOutput(playwrightConfig) {
235
+ const { outputDir } = playwrightConfig;
236
+ if (outputDir) {
237
+ return outputDir;
238
+ }
239
+ else {
240
+ return './test-results';
225
241
  }
242
+ }
243
+ function getReporterOutputs(playwrightConfig) {
226
244
  const outputs = [];
227
- const { reporter, outputDir } = playwrightConfig;
245
+ const { reporter } = playwrightConfig;
228
246
  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);
247
+ const DEFAULT_REPORTER_OUTPUT = 'playwright-report';
248
+ if (reporter === 'html') {
249
+ outputs.push([reporter, DEFAULT_REPORTER_OUTPUT]);
250
+ }
251
+ else if (reporter === 'json') {
252
+ outputs.push([reporter, DEFAULT_REPORTER_OUTPUT]);
233
253
  }
234
254
  else if (Array.isArray(reporter)) {
235
255
  for (const r of reporter) {
236
- const [, opts] = r;
256
+ const [reporter, opts] = r;
237
257
  // There are a few different ways to specify an output file or directory
238
258
  // 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));
259
+ if (opts?.outputFile) {
260
+ outputs.push([reporter, opts.outputFile]);
244
261
  }
245
- else if (opts.outputDir) {
246
- outputs.push(getOutput(opts.outputDir));
262
+ else if (opts?.outputDir) {
263
+ outputs.push([reporter, opts.outputDir]);
247
264
  }
248
- else if (opts.outputFolder) {
249
- outputs.push(getOutput(opts.outputFolder));
265
+ else if (opts?.outputFolder) {
266
+ outputs.push([reporter, opts.outputFolder]);
250
267
  }
251
268
  else {
252
- outputs.push(DEFAULT_REPORTER_OUTPUT);
269
+ outputs.push([reporter, DEFAULT_REPORTER_OUTPUT]);
253
270
  }
254
271
  }
255
272
  }
256
273
  }
257
- if (outputDir) {
258
- outputs.push(getOutput(outputDir));
274
+ return outputs;
275
+ }
276
+ function getTargetOutputs(testOutput, reporterOutputs, projectRoot, scope) {
277
+ const outputs = new Set();
278
+ outputs.add(normalizeOutput(projectRoot, scope ? (0, node_path_1.join)(testOutput, scope) : testOutput));
279
+ for (const [, output] of reporterOutputs) {
280
+ outputs.add(normalizeOutput(projectRoot, scope ? (0, node_path_1.join)(output, scope) : output));
281
+ }
282
+ return Array.from(outputs);
283
+ }
284
+ function normalizeOutput(projectRoot, path) {
285
+ if (path.startsWith('..')) {
286
+ return (0, node_path_1.join)('{workspaceRoot}', (0, node_path_1.join)(projectRoot, path));
259
287
  }
260
288
  else {
261
- outputs.push(getOutput('./test-results'));
289
+ return (0, node_path_1.join)('{projectRoot}', path);
262
290
  }
263
- return outputs;
264
291
  }
265
- function normalizeOptions(options) {
266
- return {
267
- ...options,
268
- targetName: options.targetName ?? 'e2e',
269
- ciTargetName: options.ciTargetName ?? 'e2e-ci',
270
- };
292
+ function getOutputEnvVars(reporterOutputs, outputSubfolder) {
293
+ const env = {};
294
+ for (let [reporter, output] of reporterOutputs) {
295
+ if (outputSubfolder) {
296
+ const isFile = (0, node_path_1.parse)(output).ext !== '';
297
+ const envVarName = `PLAYWRIGHT_${reporter.toUpperCase()}_OUTPUT_${isFile ? 'FILE' : 'DIR'}`;
298
+ env[envVarName] = (0, node_path_1.join)(output, outputSubfolder);
299
+ // Also set PLAYWRIGHT_HTML_REPORT for Playwright prior to 1.45.0.
300
+ // HTML prior to this version did not follow the pattern of "PLAYWRIGHT_<REPORTER>_OUTPUT_<FILE|DIR>".
301
+ if (reporter === 'html') {
302
+ env['PLAYWRIGHT_HTML_REPORT'] = env[envVarName];
303
+ }
304
+ }
305
+ }
306
+ return env;
271
307
  }
@@ -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,