@nx/playwright 23.0.0-pr.35413.460eeef → 23.0.0-rc.0
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/{index.d.ts → dist/index.d.ts} +0 -1
- package/{plugin.d.ts → dist/plugin.d.ts} +0 -1
- package/{preset.d.ts → dist/preset.d.ts} +0 -1
- package/{src → dist/src}/executors/merge-reports/merge-reports.impl.d.ts +0 -1
- package/{src → dist/src}/executors/merge-reports/merge-reports.impl.js +8 -2
- package/{src → dist/src}/executors/playwright/playwright.impl.d.ts +0 -1
- package/{src → dist/src}/executors/playwright/playwright.impl.js +2 -0
- package/{src → dist/src}/executors/playwright/schema.json +1 -0
- package/{src → dist/src}/generators/configuration/configuration.d.ts +0 -1
- package/{src → dist/src}/generators/configuration/configuration.js +55 -27
- package/{src/generators/configuration/files/playwright.config.ts.template → dist/src/generators/configuration/files/playwright.config.mts.template} +10 -3
- package/{src → dist/src}/generators/convert-to-inferred/convert-to-inferred.d.ts +0 -1
- package/{src → dist/src}/generators/convert-to-inferred/convert-to-inferred.js +5 -3
- package/{src → dist/src}/generators/init/init.d.ts +0 -1
- package/{src → dist/src}/generators/init/init.js +5 -3
- package/{src → dist/src}/generators/init/schema.json +1 -1
- package/dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.d.ts +9 -0
- package/dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.js +225 -0
- package/dist/src/plugins/plugin.d.ts +7 -0
- package/{src → dist/src}/plugins/plugin.js +57 -28
- package/{src → dist/src}/utils/add-linter.d.ts +0 -1
- package/{src → dist/src}/utils/add-linter.js +12 -14
- package/dist/src/utils/assert-supported-playwright-version.d.ts +2 -0
- package/dist/src/utils/assert-supported-playwright-version.js +8 -0
- package/dist/src/utils/deprecation.d.ts +3 -0
- package/dist/src/utils/deprecation.js +16 -0
- package/{src → dist/src}/utils/preset.d.ts +4 -2
- package/{src → dist/src}/utils/preset.js +15 -3
- package/{src → dist/src}/utils/reporters.d.ts +0 -1
- package/dist/src/utils/versions.d.ts +5 -0
- package/dist/src/utils/versions.js +9 -0
- package/executors.json +4 -4
- package/generators.json +6 -6
- package/migrations.json +8 -1
- package/package.json +61 -34
- package/index.d.ts.map +0 -1
- package/plugin.d.ts.map +0 -1
- package/preset.d.ts.map +0 -1
- package/src/executors/merge-reports/merge-reports.impl.d.ts.map +0 -1
- package/src/executors/playwright/playwright.impl.d.ts.map +0 -1
- package/src/generators/configuration/configuration.d.ts.map +0 -1
- package/src/generators/convert-to-inferred/convert-to-inferred.d.ts.map +0 -1
- package/src/generators/init/init.d.ts.map +0 -1
- package/src/migrations/update-19-6-0/use-serve-static-preview-for-command.d.ts +0 -1
- package/src/migrations/update-19-6-0/use-serve-static-preview-for-command.d.ts.map +0 -1
- package/src/migrations/update-19-6-0/use-serve-static-preview-for-command.js +0 -0
- package/src/plugins/plugin.d.ts +0 -8
- package/src/plugins/plugin.d.ts.map +0 -1
- package/src/utils/add-linter.d.ts.map +0 -1
- package/src/utils/preset.d.ts.map +0 -1
- package/src/utils/reporters.d.ts.map +0 -1
- package/src/utils/versions.d.ts +0 -4
- package/src/utils/versions.d.ts.map +0 -1
- package/src/utils/versions.js +0 -6
- /package/{LICENSE → dist/LICENSE} +0 -0
- /package/{PLUGIN.md → dist/PLUGIN.md} +0 -0
- /package/{index.js → dist/index.js} +0 -0
- /package/{plugin.js → dist/plugin.js} +0 -0
- /package/{preset.js → dist/preset.js} +0 -0
- /package/{src → dist/src}/executors/merge-reports/schema.d.ts +0 -0
- /package/{src → dist/src}/executors/merge-reports/schema.json +0 -0
- /package/{src → dist/src}/generators/configuration/files/__directory__/example.spec.ts.template +0 -0
- /package/{src → dist/src}/generators/configuration/schema.d.ts +0 -0
- /package/{src → dist/src}/generators/configuration/schema.json +0 -0
- /package/{src → dist/src}/generators/convert-to-inferred/schema.json +0 -0
- /package/{src → dist/src}/generators/init/schema.d.ts +0 -0
- /package/{src → dist/src}/utils/reporters.js +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
export { playwrightExecutor, PlaywrightExecutorSchema, } from './src/executors/playwright/playwright.impl';
|
|
2
2
|
export { initGenerator } from './src/generators/init/init';
|
|
3
3
|
export { configurationGenerator } from './src/generators/configuration/configuration';
|
|
4
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.mergeReportsExecutor = mergeReportsExecutor;
|
|
4
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
4
5
|
const devkit_1 = require("@nx/devkit");
|
|
5
|
-
const config_utils_1 = require("@nx/devkit/src/utils/config-utils");
|
|
6
6
|
const node_child_process_1 = require("node:child_process");
|
|
7
7
|
const node_fs_1 = require("node:fs");
|
|
8
8
|
const node_path_1 = require("node:path");
|
|
9
|
+
const semver_1 = require("semver");
|
|
9
10
|
const reporters_1 = require("../../utils/reporters");
|
|
11
|
+
const versions_1 = require("../../utils/versions");
|
|
10
12
|
async function mergeReportsExecutor(options, context) {
|
|
13
|
+
const installed = (0, internal_1.getInstalledPackageVersion)('@playwright/test');
|
|
14
|
+
if (installed && (0, semver_1.lt)(installed, versions_1.minPlaywrightVersionForBlobReports)) {
|
|
15
|
+
throw new Error(`The "@nx/playwright:merge-reports" executor requires "@playwright/test" version ${versions_1.minPlaywrightVersionForBlobReports} or greater (the version that introduced the "blob" reporter and the "merge-reports" CLI). You are currently using version ${installed}.`);
|
|
16
|
+
}
|
|
11
17
|
const { config, expectedSuites } = options;
|
|
12
18
|
const projectRoot = (0, node_path_1.join)(context.root, context.projectsConfigurations.projects[context.projectName].root);
|
|
13
19
|
const configPath = (0, node_path_1.join)(projectRoot, config);
|
|
14
|
-
const playwrightConfig = await (0,
|
|
20
|
+
const playwrightConfig = await (0, internal_1.loadConfigFile)(configPath);
|
|
15
21
|
const reporterOutputs = (0, reporters_1.getReporterOutputs)(playwrightConfig);
|
|
16
22
|
const blobReporterOutput = reporterOutputs.find(([reporter]) => reporter === 'blob');
|
|
17
23
|
if (!blobReporterOutput) {
|
|
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.playwrightExecutor = playwrightExecutor;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
const child_process_1 = require("child_process");
|
|
6
|
+
const deprecation_1 = require("../../utils/deprecation");
|
|
6
7
|
async function playwrightExecutor(options, context) {
|
|
8
|
+
(0, deprecation_1.warnPlaywrightExecutorDeprecation)();
|
|
7
9
|
const projectRoot = context.projectGraph?.nodes?.[context?.projectName]?.data?.root;
|
|
8
10
|
if (!projectRoot) {
|
|
9
11
|
throw new Error(`Unable to find the Project Root for ${context.projectName}. Is it set in the project.json?`);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"version": 2,
|
|
4
4
|
"title": "Playwright executor",
|
|
5
5
|
"description": "Run Playwright tests.",
|
|
6
|
+
"x-deprecated": "The `@nx/playwright:playwright` executor is deprecated and will be removed in Nx v24. Run `nx g @nx/playwright:convert-to-inferred` to migrate to the `@nx/playwright/plugin` inferred targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.",
|
|
6
7
|
"type": "object",
|
|
7
8
|
"properties": {
|
|
8
9
|
"browser": {
|
|
@@ -3,4 +3,3 @@ import type { ConfigurationGeneratorSchema } from './schema';
|
|
|
3
3
|
export declare function configurationGenerator(tree: Tree, options: ConfigurationGeneratorSchema): Promise<GeneratorCallback>;
|
|
4
4
|
export declare function configurationGeneratorInternal(tree: Tree, rawOptions: ConfigurationGeneratorSchema): Promise<GeneratorCallback>;
|
|
5
5
|
export default configurationGenerator;
|
|
6
|
-
//# sourceMappingURL=configuration.d.ts.map
|
|
@@ -3,24 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.configurationGenerator = configurationGenerator;
|
|
4
4
|
exports.configurationGeneratorInternal = configurationGeneratorInternal;
|
|
5
5
|
const tslib_1 = require("tslib");
|
|
6
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
6
7
|
const devkit_1 = require("@nx/devkit");
|
|
7
|
-
const project_name_and_root_utils_1 = require("@nx/devkit/src/generators/project-name-and-root-utils");
|
|
8
|
-
const prompt_1 = require("@nx/devkit/src/generators/prompt");
|
|
9
8
|
const js_1 = require("@nx/js");
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const ensure_typescript_1 = require("@nx/js/src/utils/typescript/ensure-typescript");
|
|
13
|
-
const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
|
|
9
|
+
const internal_2 = require("@nx/js/internal");
|
|
10
|
+
const deprecation_1 = require("../../utils/deprecation");
|
|
14
11
|
const child_process_1 = require("child_process");
|
|
15
12
|
const path = tslib_1.__importStar(require("path"));
|
|
16
13
|
const add_linter_1 = require("../../utils/add-linter");
|
|
14
|
+
const assert_supported_playwright_version_1 = require("../../utils/assert-supported-playwright-version");
|
|
17
15
|
const versions_1 = require("../../utils/versions");
|
|
18
16
|
const init_1 = require("../init/init");
|
|
19
|
-
const
|
|
17
|
+
const internal_3 = require("@nx/eslint/internal");
|
|
20
18
|
function configurationGenerator(tree, options) {
|
|
21
19
|
return configurationGeneratorInternal(tree, { addPlugin: false, ...options });
|
|
22
20
|
}
|
|
23
21
|
async function configurationGeneratorInternal(tree, rawOptions) {
|
|
22
|
+
(0, assert_supported_playwright_version_1.assertSupportedPlaywrightVersion)(tree);
|
|
24
23
|
const options = await normalizeOptions(tree, rawOptions);
|
|
25
24
|
const tasks = [];
|
|
26
25
|
tasks.push(await (0, init_1.initGenerator)(tree, {
|
|
@@ -30,14 +29,25 @@ async function configurationGeneratorInternal(tree, rawOptions) {
|
|
|
30
29
|
}));
|
|
31
30
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
32
31
|
const offsetFromProjectRoot = (0, devkit_1.offsetFromRoot)(projectConfig.root);
|
|
32
|
+
const isTsSolutionSetup = (0, internal_2.isUsingTsSolutionSetup)(tree);
|
|
33
|
+
// Always emit `playwright.config.mts`. Node forces `.mts` to ESM
|
|
34
|
+
// regardless of workspace `type`, so Playwright's runtime routes it
|
|
35
|
+
// through the ESM loader (`requireOrImport` -> dynamic `import()`),
|
|
36
|
+
// bypassing the pirates CJS-compile path that breaks ESM-shape `.ts`
|
|
37
|
+
// configs. Nx's native TS strip loads `.mts` directly via `loadTsFile`.
|
|
38
|
+
// Playwright's configLoader auto-discovers `.mts` (extension list at
|
|
39
|
+
// configLoader.js:313 is `.ts/.js/.mts/.mjs/.cts/.cjs`).
|
|
33
40
|
(0, devkit_1.generateFiles)(tree, path.join(__dirname, 'files'), projectConfig.root, {
|
|
34
41
|
offsetFromRoot: offsetFromProjectRoot,
|
|
35
42
|
projectRoot: projectConfig.root,
|
|
36
43
|
webServerCommand: options.webServerCommand ?? null,
|
|
37
44
|
webServerAddress: options.webServerAddress ?? null,
|
|
45
|
+
isTsSolutionSetup,
|
|
38
46
|
...options,
|
|
39
47
|
});
|
|
40
|
-
const
|
|
48
|
+
const playwrightConfigFile = options.js
|
|
49
|
+
? 'playwright.config.mjs'
|
|
50
|
+
: 'playwright.config.mts';
|
|
41
51
|
const tsconfigPath = (0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json');
|
|
42
52
|
if (tree.exists(tsconfigPath)) {
|
|
43
53
|
if (isTsSolutionSetup) {
|
|
@@ -51,7 +61,7 @@ async function configurationGeneratorInternal(tree, rawOptions) {
|
|
|
51
61
|
include: [
|
|
52
62
|
(0, devkit_1.joinPathFragments)(options.directory, '**/*.ts'),
|
|
53
63
|
(0, devkit_1.joinPathFragments)(options.directory, '**/*.js'),
|
|
54
|
-
|
|
64
|
+
playwrightConfigFile,
|
|
55
65
|
],
|
|
56
66
|
exclude: ['out-tsc', 'test-output'],
|
|
57
67
|
};
|
|
@@ -79,7 +89,7 @@ async function configurationGeneratorInternal(tree, rawOptions) {
|
|
|
79
89
|
include: [
|
|
80
90
|
'**/*.ts',
|
|
81
91
|
'**/*.js',
|
|
82
|
-
|
|
92
|
+
playwrightConfigFile,
|
|
83
93
|
'src/**/*.spec.ts',
|
|
84
94
|
'src/**/*.spec.js',
|
|
85
95
|
'src/**/*.test.ts',
|
|
@@ -112,7 +122,7 @@ async function configurationGeneratorInternal(tree, rawOptions) {
|
|
|
112
122
|
if (isTsSolutionSetup) {
|
|
113
123
|
const packageJsonPath = (0, devkit_1.joinPathFragments)(projectConfig.root, 'package.json');
|
|
114
124
|
if (!tree.exists(packageJsonPath)) {
|
|
115
|
-
const importPath = (0,
|
|
125
|
+
const importPath = (0, internal_1.resolveImportPath)(tree, projectConfig.name, projectConfig.root);
|
|
116
126
|
const packageJson = {
|
|
117
127
|
name: importPath,
|
|
118
128
|
version: '0.0.1',
|
|
@@ -129,6 +139,7 @@ async function configurationGeneratorInternal(tree, rawOptions) {
|
|
|
129
139
|
? p === '@nx/playwright/plugin'
|
|
130
140
|
: p.plugin === '@nx/playwright/plugin');
|
|
131
141
|
if (!hasPlugin) {
|
|
142
|
+
(0, deprecation_1.warnPlaywrightExecutorGenerating)();
|
|
132
143
|
addE2eTarget(tree, options);
|
|
133
144
|
setupE2ETargetDefaults(tree);
|
|
134
145
|
}
|
|
@@ -143,8 +154,8 @@ async function configurationGeneratorInternal(tree, rawOptions) {
|
|
|
143
154
|
addPlugin: options.addPlugin,
|
|
144
155
|
}));
|
|
145
156
|
if (options.js) {
|
|
146
|
-
const { ModuleKind } = (0,
|
|
147
|
-
(0, devkit_1.toJS)(tree, { extension: '.
|
|
157
|
+
const { ModuleKind } = (0, internal_2.ensureTypescript)();
|
|
158
|
+
(0, devkit_1.toJS)(tree, { extension: '.mjs', module: ModuleKind.ESNext });
|
|
148
159
|
}
|
|
149
160
|
recommendVsCodeExtensions(tree);
|
|
150
161
|
if (!options.skipPackageJson) {
|
|
@@ -160,9 +171,9 @@ async function configurationGeneratorInternal(tree, rawOptions) {
|
|
|
160
171
|
await (0, devkit_1.formatFiles)(tree);
|
|
161
172
|
}
|
|
162
173
|
if (isTsSolutionSetup) {
|
|
163
|
-
const projectPackageManagerWorkspaceState = (0,
|
|
174
|
+
const projectPackageManagerWorkspaceState = (0, internal_2.getProjectPackageManagerWorkspaceState)(tree, projectConfig.root);
|
|
164
175
|
if (projectPackageManagerWorkspaceState !== 'included') {
|
|
165
|
-
tasks.push((0,
|
|
176
|
+
tasks.push((0, internal_2.getProjectPackageManagerWorkspaceStateWarningTask)(projectPackageManagerWorkspaceState, tree.root));
|
|
166
177
|
}
|
|
167
178
|
}
|
|
168
179
|
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
@@ -172,7 +183,7 @@ async function normalizeOptions(tree, options) {
|
|
|
172
183
|
const addPlugin = options.addPlugin ??
|
|
173
184
|
(process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
174
185
|
nxJson.useInferencePlugins !== false);
|
|
175
|
-
const linter = await (0,
|
|
186
|
+
const linter = await (0, internal_2.normalizeLinterOption)(tree, options.linter);
|
|
176
187
|
if (!options.webServerCommand || !options.webServerAddress) {
|
|
177
188
|
const { webServerCommand, webServerAddress } = await promptForMissingServeData(options.project);
|
|
178
189
|
options.webServerCommand = webServerCommand;
|
|
@@ -186,7 +197,7 @@ async function normalizeOptions(tree, options) {
|
|
|
186
197
|
};
|
|
187
198
|
}
|
|
188
199
|
async function promptForMissingServeData(projectName) {
|
|
189
|
-
const { command, port } = await (0,
|
|
200
|
+
const { command, port } = await (0, internal_1.promptWhenInteractive)([
|
|
190
201
|
{
|
|
191
202
|
type: 'input',
|
|
192
203
|
name: 'command',
|
|
@@ -243,15 +254,30 @@ function setupE2ETargetDefaults(tree) {
|
|
|
243
254
|
return;
|
|
244
255
|
}
|
|
245
256
|
// E2e targets depend on all their project's sources + production sources of dependencies
|
|
246
|
-
nxJson.targetDefaults ??= {};
|
|
247
257
|
const productionFileSet = !!nxJson.namedInputs?.production;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
258
|
+
// Either a `target: 'e2e'` default or a default keyed on the executor
|
|
259
|
+
// we're about to scaffold will apply to the new target — consider both
|
|
260
|
+
// before deciding to add cache/inputs. Target-keyed wins when both are
|
|
261
|
+
// present.
|
|
262
|
+
const existingForTarget = (0, internal_1.findTargetDefault)(nxJson.targetDefaults, {
|
|
263
|
+
target: 'e2e',
|
|
264
|
+
});
|
|
265
|
+
const existingForExecutor = (0, internal_1.findTargetDefault)(nxJson.targetDefaults, {
|
|
266
|
+
executor: '@nx/playwright:playwright',
|
|
267
|
+
});
|
|
268
|
+
const existingCache = existingForTarget?.cache ?? existingForExecutor?.cache;
|
|
269
|
+
const existingInputs = existingForTarget?.inputs ?? existingForExecutor?.inputs;
|
|
270
|
+
const patch = {};
|
|
271
|
+
if (existingCache === undefined) {
|
|
272
|
+
patch.cache = true;
|
|
273
|
+
}
|
|
274
|
+
if (existingInputs === undefined) {
|
|
275
|
+
patch.inputs = ['default', productionFileSet ? '^production' : '^default'];
|
|
276
|
+
}
|
|
277
|
+
if (Object.keys(patch).length > 0) {
|
|
278
|
+
(0, internal_1.upsertTargetDefault)(tree, nxJson, { target: 'e2e', ...patch });
|
|
279
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
280
|
+
}
|
|
255
281
|
}
|
|
256
282
|
function addE2eTarget(tree, options) {
|
|
257
283
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
@@ -264,7 +290,9 @@ Rename or remove the existing e2e target.`);
|
|
|
264
290
|
executor: '@nx/playwright:playwright',
|
|
265
291
|
outputs: [`{workspaceRoot}/dist/.playwright/${projectConfig.root}`],
|
|
266
292
|
options: {
|
|
267
|
-
|
|
293
|
+
// Generator emits `playwright.config.mts` (`.mjs` for `--js`) so the
|
|
294
|
+
// legacy executor's `--config` flag must point at the same extension.
|
|
295
|
+
config: `${projectConfig.root}/playwright.config.${options.js ? 'mjs' : 'mts'}`,
|
|
268
296
|
},
|
|
269
297
|
};
|
|
270
298
|
(0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
|
|
@@ -272,7 +300,7 @@ Rename or remove the existing e2e target.`);
|
|
|
272
300
|
function ignoreTestOutput(tree, options) {
|
|
273
301
|
// Make sure playwright outputs are not linted.
|
|
274
302
|
if (options.linter === 'eslint') {
|
|
275
|
-
(0,
|
|
303
|
+
(0, internal_3.addIgnoresToLintConfig)(tree, '', ['**/test-output']);
|
|
276
304
|
}
|
|
277
305
|
// Handle gitignore
|
|
278
306
|
if (!tree.exists('.gitignore')) {
|
|
@@ -9,13 +9,20 @@ const baseURL = process.env['BASE_URL'] || '<% if(webServerAddress) {%><%= webSe
|
|
|
9
9
|
* Read environment variables from file.
|
|
10
10
|
* https://github.com/motdotla/dotenv
|
|
11
11
|
*/
|
|
12
|
-
//
|
|
12
|
+
// import 'dotenv/config';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* See https://playwright.dev/docs/test-configuration.
|
|
16
|
+
*
|
|
17
|
+
* Generated as a .mts file so Node forces ESM regardless of workspace
|
|
18
|
+
* `type`. Playwright routes `.mts` through its ESM loader (dynamic import,
|
|
19
|
+
* bypassing the pirates CJS-compile path), and Nx's native TS strip loads
|
|
20
|
+
* `.mts` directly. Playwright's configLoader auto-discovers
|
|
21
|
+
* `playwright.config.mts` via its extension list
|
|
22
|
+
* (.ts/.js/.mts/.mjs/.cts/.cjs).
|
|
16
23
|
*/
|
|
17
24
|
export default defineConfig({
|
|
18
|
-
...nxE2EPreset(
|
|
25
|
+
...nxE2EPreset(import.meta.dirname, { testDir: './<%= directory %>' }),
|
|
19
26
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
20
27
|
use: {
|
|
21
28
|
baseURL,
|
|
@@ -50,7 +57,7 @@ export default defineConfig({
|
|
|
50
57
|
name: "webkit",
|
|
51
58
|
use: { ...devices["Desktop Safari"] },
|
|
52
59
|
},
|
|
53
|
-
|
|
60
|
+
|
|
54
61
|
// Uncomment for mobile browsers support
|
|
55
62
|
/* {
|
|
56
63
|
name: 'Mobile Chrome',
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.convertToInferred = convertToInferred;
|
|
4
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
4
5
|
const devkit_1 = require("@nx/devkit");
|
|
5
6
|
const plugin_1 = require("../../plugins/plugin");
|
|
6
|
-
const
|
|
7
|
+
const assert_supported_playwright_version_1 = require("../../utils/assert-supported-playwright-version");
|
|
7
8
|
async function convertToInferred(tree, options) {
|
|
9
|
+
(0, assert_supported_playwright_version_1.assertSupportedPlaywrightVersion)(tree);
|
|
8
10
|
const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
|
|
9
|
-
const migratedProjects = await (0,
|
|
11
|
+
const migratedProjects = await (0, internal_1.migrateProjectExecutorsToPlugin)(tree, projectGraph, '@nx/playwright/plugin', plugin_1.createNodesV2, { targetName: 'e2e', ciTargetName: 'e2e-ci' }, [
|
|
10
12
|
{
|
|
11
13
|
executors: ['@nx/playwright:playwright'],
|
|
12
14
|
postTargetTransformer,
|
|
@@ -14,7 +16,7 @@ async function convertToInferred(tree, options) {
|
|
|
14
16
|
},
|
|
15
17
|
], options.project);
|
|
16
18
|
if (migratedProjects.size === 0) {
|
|
17
|
-
throw new
|
|
19
|
+
throw new internal_1.NoTargetsToMigrateError();
|
|
18
20
|
}
|
|
19
21
|
if (!options.skipFormat) {
|
|
20
22
|
await (0, devkit_1.formatFiles)(tree);
|
|
@@ -3,4 +3,3 @@ import { InitGeneratorSchema } from './schema';
|
|
|
3
3
|
export declare function initGenerator(tree: Tree, options: InitGeneratorSchema): Promise<GeneratorCallback>;
|
|
4
4
|
export declare function initGeneratorInternal(tree: Tree, options: InitGeneratorSchema): Promise<GeneratorCallback>;
|
|
5
5
|
export default initGenerator;
|
|
6
|
-
//# sourceMappingURL=init.d.ts.map
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.initGenerator = initGenerator;
|
|
4
4
|
exports.initGeneratorInternal = initGeneratorInternal;
|
|
5
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
5
6
|
const devkit_1 = require("@nx/devkit");
|
|
6
|
-
const add_plugin_1 = require("@nx/devkit/src/utils/add-plugin");
|
|
7
7
|
const plugin_1 = require("../../plugins/plugin");
|
|
8
|
+
const assert_supported_playwright_version_1 = require("../../utils/assert-supported-playwright-version");
|
|
8
9
|
const versions_1 = require("../../utils/versions");
|
|
9
10
|
function initGenerator(tree, options) {
|
|
10
11
|
return initGeneratorInternal(tree, { addPlugin: false, ...options });
|
|
11
12
|
}
|
|
12
13
|
async function initGeneratorInternal(tree, options) {
|
|
14
|
+
(0, assert_supported_playwright_version_1.assertSupportedPlaywrightVersion)(tree);
|
|
13
15
|
const tasks = [];
|
|
14
16
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
15
17
|
const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
@@ -19,10 +21,10 @@ async function initGeneratorInternal(tree, options) {
|
|
|
19
21
|
tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
20
22
|
'@nx/playwright': versions_1.nxVersion,
|
|
21
23
|
'@playwright/test': versions_1.playwrightVersion,
|
|
22
|
-
}, undefined, options.keepExistingVersions));
|
|
24
|
+
}, undefined, options.keepExistingVersions ?? true));
|
|
23
25
|
}
|
|
24
26
|
if (options.addPlugin) {
|
|
25
|
-
await (0,
|
|
27
|
+
await (0, internal_1.addPlugin)(tree, await (0, devkit_1.createProjectGraphAsync)(), '@nx/playwright/plugin', plugin_1.createNodesV2, { targetName: ['e2e', 'playwright:e2e', 'playwright-e2e'] }, options.updatePackageScripts);
|
|
26
28
|
}
|
|
27
29
|
if (!options.skipFormat) {
|
|
28
30
|
await (0, devkit_1.formatFiles)(tree);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Tree } from '@nx/devkit';
|
|
2
|
+
export default function migrateCreateNodesV2ToCreateNodes(tree: Tree): Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* Rewrites named imports and re-exports of `createNodesV2` to `createNodes`
|
|
5
|
+
* when they come from one of the given module specifiers. Only the named
|
|
6
|
+
* bindings are touched — the module specifier, the `import`/`export` keyword,
|
|
7
|
+
* any `type` modifier, and any default import are left untouched.
|
|
8
|
+
*/
|
|
9
|
+
export declare function rewriteCreateNodesV2Imports(source: string, specifiers: ReadonlySet<string>): string;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = migrateCreateNodesV2ToCreateNodes;
|
|
4
|
+
exports.rewriteCreateNodesV2Imports = rewriteCreateNodesV2Imports;
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const TS_EXTENSIONS = ['.ts', '.tsx', '.cts', '.mts'];
|
|
7
|
+
const DEPRECATED_NAME = 'createNodesV2';
|
|
8
|
+
const CANONICAL_NAME = 'createNodes';
|
|
9
|
+
// Module specifiers from which `@nx/playwright` publicly exposes `createNodesV2`.
|
|
10
|
+
// A named import or re-export of `createNodesV2` from one of these is rewritten
|
|
11
|
+
// to the canonical `createNodes` export.
|
|
12
|
+
const TARGET_SPECIFIERS = new Set([
|
|
13
|
+
'@nx/playwright/plugin',
|
|
14
|
+
]);
|
|
15
|
+
let ts;
|
|
16
|
+
async function migrateCreateNodesV2ToCreateNodes(tree) {
|
|
17
|
+
let touchedCount = 0;
|
|
18
|
+
(0, devkit_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
|
|
19
|
+
if (!TS_EXTENSIONS.some((ext) => filePath.endsWith(ext))) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const original = tree.read(filePath, 'utf-8');
|
|
23
|
+
if (!original || !original.includes(DEPRECATED_NAME)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const updated = rewriteCreateNodesV2Imports(original, TARGET_SPECIFIERS);
|
|
27
|
+
if (updated !== original) {
|
|
28
|
+
tree.write(filePath, updated);
|
|
29
|
+
touchedCount += 1;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
if (touchedCount > 0) {
|
|
33
|
+
devkit_1.logger.info(`Renamed \`${DEPRECATED_NAME}\` imports to \`${CANONICAL_NAME}\` in ${touchedCount} file(s).`);
|
|
34
|
+
}
|
|
35
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Rewrites named imports and re-exports of `createNodesV2` to `createNodes`
|
|
39
|
+
* when they come from one of the given module specifiers. Only the named
|
|
40
|
+
* bindings are touched — the module specifier, the `import`/`export` keyword,
|
|
41
|
+
* any `type` modifier, and any default import are left untouched.
|
|
42
|
+
*/
|
|
43
|
+
function rewriteCreateNodesV2Imports(source, specifiers) {
|
|
44
|
+
ts ??= (0, devkit_1.ensurePackage)('typescript', '*');
|
|
45
|
+
const sourceFile = ts.createSourceFile('tmp.ts', source, ts.ScriptTarget.Latest,
|
|
46
|
+
/* setParentNodes */ true, ts.ScriptKind.TSX);
|
|
47
|
+
const changes = [];
|
|
48
|
+
let renameLocalUsages = false;
|
|
49
|
+
for (const stmt of sourceFile.statements) {
|
|
50
|
+
if (ts.isImportDeclaration(stmt)) {
|
|
51
|
+
renameLocalUsages =
|
|
52
|
+
collectImportRewrite(sourceFile, stmt, specifiers, changes) ||
|
|
53
|
+
renameLocalUsages;
|
|
54
|
+
}
|
|
55
|
+
else if (ts.isExportDeclaration(stmt)) {
|
|
56
|
+
collectExportRewrite(sourceFile, stmt, specifiers, changes);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Renaming a local `createNodesV2` import binding to `createNodes` (a lone
|
|
60
|
+
// `{ createNodesV2 }`, or one deduped against an existing `createNodes`)
|
|
61
|
+
// changes the name in scope, so value references to `createNodesV2` in the
|
|
62
|
+
// file body must be renamed too — otherwise they dangle. Aliased imports and
|
|
63
|
+
// re-exports keep their local name, so they never trigger this.
|
|
64
|
+
if (renameLocalUsages) {
|
|
65
|
+
collectValueUsageRewrites(sourceFile, changes);
|
|
66
|
+
}
|
|
67
|
+
return changes.length > 0 ? (0, devkit_1.applyChangesToString)(source, changes) : source;
|
|
68
|
+
}
|
|
69
|
+
function isTargetSpecifier(node, specifiers) {
|
|
70
|
+
return ts.isStringLiteral(node) && specifiers.has(node.text);
|
|
71
|
+
}
|
|
72
|
+
function collectImportRewrite(sourceFile, stmt, specifiers, changes) {
|
|
73
|
+
if (!isTargetSpecifier(stmt.moduleSpecifier, specifiers)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
77
|
+
// Only `import { ... }` carries renameable named bindings. `import x`,
|
|
78
|
+
// `import * as ns`, and side-effect imports reference the module wholesale
|
|
79
|
+
// and keep working through the `createNodesV2` runtime alias, so we leave
|
|
80
|
+
// them be. A mixed `import def, { createNodesV2 }` still has its named
|
|
81
|
+
// bindings rewritten below — the default binding is untouched.
|
|
82
|
+
if (!namedBindings || !ts.isNamedImports(namedBindings)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
// The local `createNodesV2` binding only disappears when it is imported
|
|
86
|
+
// without an alias — a lone `{ createNodesV2 }` or one deduped against an
|
|
87
|
+
// existing `createNodes`. `{ createNodesV2 as x }` keeps the local `x`, so
|
|
88
|
+
// its in-file usages are unaffected and must not be rewritten.
|
|
89
|
+
const localBindingRenamed = namedBindings.elements.some((el) => el.name.text === DEPRECATED_NAME &&
|
|
90
|
+
(el.propertyName ?? el.name).text === DEPRECATED_NAME);
|
|
91
|
+
rewriteNamedBindings(sourceFile, namedBindings, changes);
|
|
92
|
+
return localBindingRenamed;
|
|
93
|
+
}
|
|
94
|
+
function collectExportRewrite(sourceFile, stmt, specifiers, changes) {
|
|
95
|
+
if (!stmt.moduleSpecifier ||
|
|
96
|
+
!isTargetSpecifier(stmt.moduleSpecifier, specifiers)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// `export { ... } from '...'` can be rewritten; `export * from '...'` has no
|
|
100
|
+
// named bindings to rename.
|
|
101
|
+
if (!stmt.exportClause || !ts.isNamedExports(stmt.exportClause)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
rewriteNamedBindings(sourceFile, stmt.exportClause, changes);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Re-renders the `{ ... }` of a named import/export, renaming any
|
|
108
|
+
* `createNodesV2` specifier to `createNodes`. If renaming would collide with a
|
|
109
|
+
* `createNodes` that is already present (e.g. `{ createNodes, createNodesV2 }`),
|
|
110
|
+
* the duplicate is dropped. Returns without recording a change when the binding
|
|
111
|
+
* list contains no `createNodesV2`.
|
|
112
|
+
*/
|
|
113
|
+
function rewriteNamedBindings(sourceFile, namedBindings, changes) {
|
|
114
|
+
const elements = namedBindings.elements;
|
|
115
|
+
const hasDeprecated = elements.some((el) => (el.propertyName ?? el.name).text === DEPRECATED_NAME);
|
|
116
|
+
if (!hasDeprecated) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const seen = new Set();
|
|
120
|
+
const rendered = [];
|
|
121
|
+
for (const el of elements) {
|
|
122
|
+
const text = renderSpecifier(el);
|
|
123
|
+
if (!seen.has(text)) {
|
|
124
|
+
seen.add(text);
|
|
125
|
+
rendered.push(text);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const start = namedBindings.getStart(sourceFile);
|
|
129
|
+
changes.push({
|
|
130
|
+
type: devkit_1.ChangeType.Delete,
|
|
131
|
+
start,
|
|
132
|
+
length: namedBindings.getEnd() - start,
|
|
133
|
+
}, {
|
|
134
|
+
type: devkit_1.ChangeType.Insert,
|
|
135
|
+
index: start,
|
|
136
|
+
text: `{ ${rendered.join(', ')} }`,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function renderSpecifier(el) {
|
|
140
|
+
const typePrefix = el.isTypeOnly ? 'type ' : '';
|
|
141
|
+
const rename = (name) => name === DEPRECATED_NAME ? CANONICAL_NAME : name;
|
|
142
|
+
// `{ name }` — no alias, so the local binding follows the rename.
|
|
143
|
+
if (!el.propertyName) {
|
|
144
|
+
return `${typePrefix}${rename(el.name.text)}`;
|
|
145
|
+
}
|
|
146
|
+
// `{ propertyName as name }` — only the imported (left) side is renamed; the
|
|
147
|
+
// local alias is preserved. A now-redundant alias such as
|
|
148
|
+
// `createNodesV2 as createNodes` collapses to `createNodes`.
|
|
149
|
+
const canonicalImported = rename(el.propertyName.text);
|
|
150
|
+
const localName = el.name.text;
|
|
151
|
+
return canonicalImported === localName
|
|
152
|
+
? `${typePrefix}${localName}`
|
|
153
|
+
: `${typePrefix}${canonicalImported} as ${localName}`;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Renames value references of `createNodesV2` to `createNodes` in the file
|
|
157
|
+
* body. Only called once a local `createNodesV2` import binding has actually
|
|
158
|
+
* been renamed, so these references would otherwise dangle. Occurrences that
|
|
159
|
+
* are not references to that binding are skipped: the import/export
|
|
160
|
+
* declarations themselves, property accesses (`x.createNodesV2`), qualified
|
|
161
|
+
* type names, object-literal keys, and declaration names that shadow the
|
|
162
|
+
* import. A shorthand property (`{ createNodesV2 }`) is expanded to
|
|
163
|
+
* `{ createNodesV2: createNodes }` so the property key is preserved. Strings
|
|
164
|
+
* and comments are never `Identifier` nodes, so they are left alone.
|
|
165
|
+
*/
|
|
166
|
+
function collectValueUsageRewrites(sourceFile, changes) {
|
|
167
|
+
const visit = (node) => {
|
|
168
|
+
if (ts.isIdentifier(node) &&
|
|
169
|
+
node.text === DEPRECATED_NAME &&
|
|
170
|
+
isRenamableValueUsage(node)) {
|
|
171
|
+
const start = node.getStart(sourceFile);
|
|
172
|
+
changes.push({
|
|
173
|
+
type: devkit_1.ChangeType.Delete,
|
|
174
|
+
start,
|
|
175
|
+
length: node.getEnd() - start,
|
|
176
|
+
}, {
|
|
177
|
+
type: devkit_1.ChangeType.Insert,
|
|
178
|
+
index: start,
|
|
179
|
+
text: ts.isShorthandPropertyAssignment(node.parent)
|
|
180
|
+
? `${DEPRECATED_NAME}: ${CANONICAL_NAME}`
|
|
181
|
+
: CANONICAL_NAME,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
node.forEachChild(visit);
|
|
185
|
+
};
|
|
186
|
+
sourceFile.forEachChild(visit);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Whether a `createNodesV2` identifier is a value reference to the renamed
|
|
190
|
+
* import binding, as opposed to a position that must be left untouched.
|
|
191
|
+
*/
|
|
192
|
+
function isRenamableValueUsage(node) {
|
|
193
|
+
const parent = node.parent;
|
|
194
|
+
if (!parent) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
// Import/export bindings — already handled by the declaration rewrite.
|
|
198
|
+
if (ts.isImportSpecifier(parent) ||
|
|
199
|
+
ts.isExportSpecifier(parent) ||
|
|
200
|
+
ts.isImportClause(parent) ||
|
|
201
|
+
ts.isNamespaceImport(parent)) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
// `x.createNodesV2` / `X.createNodesV2` — a member name, not the binding.
|
|
205
|
+
if (ts.isPropertyAccessExpression(parent) && parent.name === node) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
if (ts.isQualifiedName(parent) && parent.right === node) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
// `{ createNodesV2: ... }` — an object-literal key, not the binding.
|
|
212
|
+
if (ts.isPropertyAssignment(parent) && parent.name === node) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
// A declaration whose name shadows the import (variable, param, etc.).
|
|
216
|
+
if ((ts.isVariableDeclaration(parent) ||
|
|
217
|
+
ts.isParameter(parent) ||
|
|
218
|
+
ts.isBindingElement(parent) ||
|
|
219
|
+
ts.isFunctionDeclaration(parent) ||
|
|
220
|
+
ts.isClassDeclaration(parent)) &&
|
|
221
|
+
parent.name === node) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type CreateNodes } from '@nx/devkit';
|
|
2
|
+
export interface PlaywrightPluginOptions {
|
|
3
|
+
targetName?: string;
|
|
4
|
+
ciTargetName?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const createNodes: CreateNodes<PlaywrightPluginOptions>;
|
|
7
|
+
export declare const createNodesV2: CreateNodes<PlaywrightPluginOptions>;
|