@nx/playwright 21.0.0-beta.0 → 21.0.0-beta.10

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/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": "21.0.0-beta.0",
3
+ "version": "21.0.0-beta.10",
4
4
  "type": "commonjs",
5
5
  "homepage": "https://nx.dev",
6
6
  "private": false,
@@ -35,26 +35,18 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@phenomnomnominal/tsquery": "~5.0.1",
38
- "@nx/devkit": "21.0.0-beta.0",
39
- "@nx/eslint": "21.0.0-beta.0",
40
- "@nx/js": "21.0.0-beta.0",
38
+ "@nx/devkit": "21.0.0-beta.10",
39
+ "@nx/eslint": "21.0.0-beta.10",
40
+ "@nx/js": "21.0.0-beta.10",
41
41
  "tslib": "^2.3.0",
42
42
  "minimatch": "9.0.3"
43
43
  },
44
44
  "peerDependencies": {
45
- "@playwright/test": "^1.36.0",
46
- "@nx/webpack": "file:../webpack",
47
- "@nx/vite": "file:../vite"
45
+ "@playwright/test": "^1.36.0"
48
46
  },
49
47
  "peerDependenciesMeta": {
50
48
  "@playwright/test": {
51
49
  "optional": true
52
- },
53
- "@nx/webpack": {
54
- "optional": true
55
- },
56
- "@nx/vite": {
57
- "optional": true
58
50
  }
59
51
  },
60
52
  "executors": "./executors.json",
@@ -115,10 +115,10 @@ async function configurationGeneratorInternal(tree, rawOptions) {
115
115
  name: importPath,
116
116
  version: '0.0.1',
117
117
  private: true,
118
- nx: {
119
- name: options.project,
120
- },
121
118
  };
119
+ if (options.project !== importPath) {
120
+ packageJson.nx = { name: options.project };
121
+ }
122
122
  (0, devkit_1.writeJson)(tree, packageJsonPath, packageJson);
123
123
  }
124
124
  ignoreTestOutput(tree);
@@ -26,13 +26,13 @@ export default defineConfig({
26
26
  webServer: {
27
27
  command: '<%= webServerCommand %>',
28
28
  url: '<%= webServerAddress %>',
29
- reuseExistingServer: !process.env.CI,
29
+ reuseExistingServer: true,
30
30
  cwd: workspaceRoot
31
31
  },<% } else {%>
32
32
  // webServer: {
33
33
  // command: 'npm run start',
34
34
  // url: 'http://127.0.0.1:3000',
35
- // reuseExistingServer: !process.env.CI,
35
+ // reuseExistingServer: true,
36
36
  // cwd: workspaceRoot,
37
37
  // },<% } %>
38
38
  projects: [
@@ -84,8 +84,9 @@ async function default_1(tree) {
84
84
  : 'preview', projectToMigrate.configFileType === 'webpack'
85
85
  ? 'serveStaticTargetName'
86
86
  : 'previewTargetName', projectToMigrate.configFileType === 'webpack'
87
- ? (await getDynamicImportedModule('@nx/webpack/src/plugins/plugin', '@nx/webpack should be installed when attempting to setup @nx/playwright with a webpack config file.')).createNodesV2
88
- : (await getDynamicImportedModule('@nx/vite/plugin', '@nx/vite should be installed when attempting to setup @nx/playwright with a vite config file.')).createNodesV2)) ??
87
+ ? require('@nx/webpack/plugin').createNodesV2
88
+ : require('@nx/vite/plugin')
89
+ .createNodesV2)) ??
89
90
  getServeStaticLikeTarget(tree, graph, projectToMigrate.projectName, projectToMigrate.configFileType === 'webpack'
90
91
  ? '@nx/web:file-server'
91
92
  : '@nx/vite:preview-server');
@@ -131,14 +132,6 @@ async function default_1(tree) {
131
132
  await (0, add_e2e_ci_target_defaults_1.default)(tree);
132
133
  await (0, devkit_1.formatFiles)(tree);
133
134
  }
134
- async function getDynamicImportedModule(moduleName, error) {
135
- try {
136
- return (await Promise.resolve(`${moduleName}`).then(s => require(s)));
137
- }
138
- catch {
139
- throw new Error(error);
140
- }
141
- }
142
135
  async function getServeStaticTargetNameForConfigFile(tree, pluginName, configFile, defaultTargetName, targetNamePluginOption, createNodesV2) {
143
136
  const nxJson = (0, devkit_1.readNxJson)(tree);
144
137
  const matchingPluginRegistrations = nxJson.plugins?.filter((p) => typeof p === 'string' ? p === pluginName : p.plugin === pluginName);
@@ -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, node_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);
@@ -78,12 +85,12 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
78
85
  let metadata;
79
86
  const testOutput = getTestOutput(playwrightConfig);
80
87
  const reporterOutputs = getReporterOutputs(playwrightConfig);
88
+ const webserverCommandTasks = getWebserverCommandTasks(playwrightConfig);
81
89
  const baseTargetConfig = {
82
90
  command: 'playwright test',
83
91
  options: {
84
92
  cwd: '{projectRoot}',
85
93
  },
86
- parallelism: false,
87
94
  metadata: {
88
95
  technologies: ['playwright'],
89
96
  description: 'Runs Playwright Tests',
@@ -97,6 +104,12 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
97
104
  },
98
105
  },
99
106
  };
107
+ if (webserverCommandTasks.length) {
108
+ baseTargetConfig.dependsOn = getDependsOn(webserverCommandTasks);
109
+ }
110
+ else {
111
+ baseTargetConfig.parallelism = false;
112
+ }
100
113
  targets[options.targetName] = {
101
114
  ...baseTargetConfig,
102
115
  cache: true,
@@ -174,7 +187,6 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
174
187
  inputs: ciBaseTargetConfig.inputs,
175
188
  outputs: ciBaseTargetConfig.outputs,
176
189
  dependsOn,
177
- parallelism: false,
178
190
  metadata: {
179
191
  technologies: ['playwright'],
180
192
  description: 'Runs Playwright Tests in CI',
@@ -189,6 +201,9 @@ async function buildPlaywrightTargets(configFilePath, projectRoot, options, cont
189
201
  },
190
202
  },
191
203
  };
204
+ if (!webserverCommandTasks.length) {
205
+ targets[options.ciTargetName].parallelism = false;
206
+ }
192
207
  ciTargetGroup.push(options.ciTargetName);
193
208
  }
194
209
  return { targets, metadata };
@@ -290,6 +305,53 @@ function addSubfolderToOutput(output, subfolder) {
290
305
  }
291
306
  return (0, node_path_1.join)(output, subfolder);
292
307
  }
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
+ }
293
355
  function normalizeOutput(path, workspaceRoot, projectRoot) {
294
356
  const fullProjectRoot = (0, node_path_1.resolve)(workspaceRoot, projectRoot);
295
357
  const fullPath = (0, node_path_1.resolve)(fullProjectRoot, path);
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
- }