@gnuechtel/nx-cucumber 2.0.0-beta.3 → 2.0.0-beta.4
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/README.md +74 -2
- package/migrations.json +10 -0
- package/package.json +6 -3
- package/src/index.d.ts +1 -0
- package/src/index.js +3 -1
- package/src/index.js.map +1 -1
- package/src/migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks.d.ts +20 -0
- package/src/migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks.js +206 -0
- package/src/migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks.js.map +1 -0
package/README.md
CHANGED
|
@@ -426,12 +426,15 @@ PWDEBUG=1 npx nx e2e my-project-e2e
|
|
|
426
426
|
|
|
427
427
|
### Watching
|
|
428
428
|
|
|
429
|
-
|
|
429
|
+
There is no dedicated watch mode in `@gnuechtel/nx-cucumber`.
|
|
430
|
+
If you want automatic re-runs on file changes, you can use Nx [workspace watching](https://nx.dev/recipes/running-tasks/workspace-watching) as an optional outer loop:
|
|
430
431
|
|
|
431
432
|
```bash
|
|
432
433
|
npx nx watch --projects=my-project-e2e -- npx nx e2e my-project-e2e
|
|
433
434
|
```
|
|
434
435
|
|
|
436
|
+
This command belongs to Nx workspace tooling, not to a plugin-specific watch implementation.
|
|
437
|
+
|
|
435
438
|
## Filter Cucumber scenarios
|
|
436
439
|
|
|
437
440
|
While development of Cucumber scenarios, we often want to execute only selected scenarios. We can achieve this by using the filter capabilities of Cucumber in the `cucumber.js` config or via CLI arguments.
|
|
@@ -579,6 +582,63 @@ npm run e2e:port-regression:react-example
|
|
|
579
582
|
- Upgrade to Nx `>=22`
|
|
580
583
|
- Install `@gnuechtel/nx-cucumber@2`
|
|
581
584
|
|
|
585
|
+
### Version compatibility and upgrade order
|
|
586
|
+
|
|
587
|
+
`@gnuechtel/nx-cucumber` 1.x does not have one single Nx compatibility range (taken from published npm `peerDependencies`):
|
|
588
|
+
|
|
589
|
+
| nx-cucumber 1.x | Nx peer compatibility |
|
|
590
|
+
| --------------- | ------------------------- |
|
|
591
|
+
| `1.0.0` | `^16 \|\| ^17` |
|
|
592
|
+
| `1.0.1` | `^16 \|\| ^17 \|\| ^18` |
|
|
593
|
+
| `1.0.2` | `16 - 19` |
|
|
594
|
+
| `1.1.0` | `>=19 <23` |
|
|
595
|
+
| `1.2.0 - 1.4.1` | `>=20 <23 \|\| ^22.0.0-0` |
|
|
596
|
+
|
|
597
|
+
Recommended upgrade order for projects moving from 1.x to 2.x:
|
|
598
|
+
|
|
599
|
+
1. If your project is on `1.0.0`, `1.0.1`, or `1.0.2`, first install and run with a compatible Nx (for example Nx 17) to avoid peer-resolution conflicts.
|
|
600
|
+
2. Remove the legacy plugin package from `package.json`:
|
|
601
|
+
`npm remove @gnuechtel/nx-cucumber`
|
|
602
|
+
3. Upgrade Nx to 22:
|
|
603
|
+
`npx nx@22.6.4 migrate 22.6.4`
|
|
604
|
+
`npm install`
|
|
605
|
+
`npx nx migrate --run-migrations`
|
|
606
|
+
4. Install `@gnuechtel/nx-cucumber@2`.
|
|
607
|
+
5. Run the plugin migration (`nx migrate @gnuechtel/nx-cucumber@2` + `nx migrate --run-migrations`).
|
|
608
|
+
|
|
609
|
+
For `1.1.0+`, Nx 22 is already within the supported peer range. The temporary Nx-17 compatibility step is not required there.
|
|
610
|
+
|
|
611
|
+
### Automated migration via nx migrate
|
|
612
|
+
|
|
613
|
+
You can run the legacy executor migration as part of the standard Nx migration flow:
|
|
614
|
+
|
|
615
|
+
```bash
|
|
616
|
+
npx nx migrate @gnuechtel/nx-cucumber@2
|
|
617
|
+
npx nx migrate --run-migrations
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
What this migration does:
|
|
621
|
+
|
|
622
|
+
- Detects projects using `@gnuechtel/nx-cucumber:cucumber-api`.
|
|
623
|
+
- Adds `@gnuechtel/nx-cucumber` to `nx.json` plugins (if missing).
|
|
624
|
+
- Removes legacy executor targets (`e2e-cucumber`, and legacy `e2e` wrappers pointing to `e2e-cucumber`).
|
|
625
|
+
- Removes legacy `e2e-watch` targets that use the old `--watch-message` run-command flow.
|
|
626
|
+
- Creates a `cucumber.js` file when missing, based on detected legacy options.
|
|
627
|
+
- Writes a migration report to `tmp/nx-cucumber-migration-report.json`.
|
|
628
|
+
|
|
629
|
+
Dry-run mode:
|
|
630
|
+
|
|
631
|
+
- Set `NX_CUCUMBER_MIGRATION_DRY_RUN=true` before running migrations to print planned changes without modifying files.
|
|
632
|
+
|
|
633
|
+
### CI migration tests
|
|
634
|
+
|
|
635
|
+
The repository includes an automated migration matrix test (`@migration` scenarios) for all stable 1.x versions (`1.0.0` to `1.4.1`).
|
|
636
|
+
|
|
637
|
+
- For `1.0.0 - 1.0.2`, the test uses a compatible Nx 17 workspace first, removes the legacy plugin package, upgrades Nx to 22, then runs the 2.x migration.
|
|
638
|
+
- For `1.1.0+`, the test runs directly on Nx 22.
|
|
639
|
+
|
|
640
|
+
`npm install` failures from legacy generator internals are not treated as acceptable in these migration tests.
|
|
641
|
+
|
|
582
642
|
### Step 1: Register the plugin
|
|
583
643
|
|
|
584
644
|
Add the plugin to `nx.json`:
|
|
@@ -622,7 +682,7 @@ For core (non-Playwright) projects, omit the Playwright require entries.
|
|
|
622
682
|
|
|
623
683
|
### Step 3: Simplify project.json
|
|
624
684
|
|
|
625
|
-
Remove the executor-based `e2e` and `e2e-cucumber` targets from `project.json`. The plugin infers the `e2e` target automatically from the `cucumber.js` file. Keep only non-inferred targets like `lint`.
|
|
685
|
+
Remove the executor-based `e2e` and `e2e-cucumber` targets from `project.json`. Also remove old `e2e-watch` run-commands. The plugin infers the `e2e` target automatically from the `cucumber.js` file. Keep only non-inferred targets like `lint`.
|
|
626
686
|
|
|
627
687
|
### Step 4: Move executor options to cucumber.js
|
|
628
688
|
|
|
@@ -645,3 +705,15 @@ npx nx e2e my-project-e2e
|
|
|
645
705
|
```
|
|
646
706
|
|
|
647
707
|
The inferred target runs `npx cucumber-js` with the configuration from `cucumber.js`.
|
|
708
|
+
|
|
709
|
+
### Rollback strategy
|
|
710
|
+
|
|
711
|
+
- Revert the migration commit in git if validation fails.
|
|
712
|
+
- Remove `@gnuechtel/nx-cucumber` from `nx.json` plugins if rollback to 1.x is required.
|
|
713
|
+
- Restore previous `project.json` executor targets and `cucumber.js` from version control.
|
|
714
|
+
|
|
715
|
+
### Known limitations
|
|
716
|
+
|
|
717
|
+
- Existing `cucumber.js` files are not overwritten automatically.
|
|
718
|
+
- Framework-native watch mode is not generated automatically. If you still need watch, add your own adapter-native watch command after migration.
|
|
719
|
+
- Highly customized run-command wrappers may require manual cleanup after migration.
|
package/migrations.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generators": {
|
|
3
|
+
"migrate-cucumber-api-to-inferred-tasks": {
|
|
4
|
+
"version": "2.0.0-beta.4",
|
|
5
|
+
"description": "Migrate legacy cucumber-api executor projects to adapter-based inferred tasks",
|
|
6
|
+
"implementation": "./src/migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks",
|
|
7
|
+
"cli": "nx"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gnuechtel/nx-cucumber",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.4",
|
|
4
4
|
"description": "Plugin to use Cucumber within Nx workspaces",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"@nx/devkit": ">=22 <23",
|
|
13
13
|
"minimatch": "^10.0.0",
|
|
14
14
|
"tslib": "^2.3.0",
|
|
15
|
-
"@gnuechtel/shared-coverage": "2.0.0-beta.
|
|
16
|
-
"@gnuechtel/shared-util": "2.0.0-beta.
|
|
15
|
+
"@gnuechtel/shared-coverage": "2.0.0-beta.4",
|
|
16
|
+
"@gnuechtel/shared-util": "2.0.0-beta.4"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
19
|
"@cucumber/cucumber": ">=9 <13",
|
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
"type": "commonjs",
|
|
34
34
|
"main": "./src/index.js",
|
|
35
35
|
"generators": "./generators.json",
|
|
36
|
+
"nx-migrations": {
|
|
37
|
+
"migrations": "./migrations.json"
|
|
38
|
+
},
|
|
36
39
|
"executors": "./executors.json",
|
|
37
40
|
"typings": "./src/index.d.ts",
|
|
38
41
|
"types": "./src/index.d.ts"
|
package/src/index.d.ts
CHANGED
|
@@ -9,3 +9,4 @@ export * from './adapters/validation';
|
|
|
9
9
|
export * from './adapters/registry';
|
|
10
10
|
export { createNodesV2 } from './plugin/create-nodes';
|
|
11
11
|
export type { NxCucumberPluginOptions } from './plugin/create-nodes';
|
|
12
|
+
export { migrateCucumberApiToInferredTasks } from './migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks';
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createNodesV2 = exports.stopWebServer = exports.startWebServer = exports.createBeautifulHtmlReport = void 0;
|
|
3
|
+
exports.migrateCucumberApiToInferredTasks = exports.createNodesV2 = exports.stopWebServer = exports.startWebServer = exports.createBeautifulHtmlReport = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
tslib_1.__exportStar(require("./playwright/playwright-world"), exports);
|
|
6
6
|
tslib_1.__exportStar(require("./core/test-run-options"), exports);
|
|
@@ -14,4 +14,6 @@ tslib_1.__exportStar(require("./adapters/validation"), exports);
|
|
|
14
14
|
tslib_1.__exportStar(require("./adapters/registry"), exports);
|
|
15
15
|
var create_nodes_1 = require("./plugin/create-nodes");
|
|
16
16
|
Object.defineProperty(exports, "createNodesV2", { enumerable: true, get: function () { return create_nodes_1.createNodesV2; } });
|
|
17
|
+
var migrate_cucumber_api_to_inferred_tasks_1 = require("./migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks");
|
|
18
|
+
Object.defineProperty(exports, "migrateCucumberApiToInferredTasks", { enumerable: true, get: function () { return migrate_cucumber_api_to_inferred_tasks_1.migrateCucumberApiToInferredTasks; } });
|
|
17
19
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/nx-cucumber/src/index.ts"],"names":[],"mappings":";;;;AAAA,wEAA8C;AAC9C,kEAAwC;AACxC,oEAAwE;AAA/D,iIAAA,yBAAyB,OAAA;AAClC,gDAAkE;AAAzD,4GAAA,cAAc,OAAA;AAAE,2GAAA,aAAa,OAAA;AAGtC,8DAAoC;AACpC,gEAAsC;AACtC,8DAAoC;AACpC,sDAAsD;AAA7C,6GAAA,aAAa,OAAA","sourcesContent":["export * from './playwright/playwright-world';\nexport * from './core/test-run-options';\nexport { createBeautifulHtmlReport } from './core/cucumber-report-html';\nexport { startWebServer, stopWebServer } from './core/web-server';\nexport type { WebServerConfig } from './core/web-server';\nexport type { BeautifulReportOptions } from './core/cucumber-report-html';\nexport * from './adapters/contract';\nexport * from './adapters/validation';\nexport * from './adapters/registry';\nexport { createNodesV2 } from './plugin/create-nodes';\nexport type { NxCucumberPluginOptions } from './plugin/create-nodes';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/nx-cucumber/src/index.ts"],"names":[],"mappings":";;;;AAAA,wEAA8C;AAC9C,kEAAwC;AACxC,oEAAwE;AAA/D,iIAAA,yBAAyB,OAAA;AAClC,gDAAkE;AAAzD,4GAAA,cAAc,OAAA;AAAE,2GAAA,aAAa,OAAA;AAGtC,8DAAoC;AACpC,gEAAsC;AACtC,8DAAoC;AACpC,sDAAsD;AAA7C,6GAAA,aAAa,OAAA;AAEtB,2HAAqH;AAA5G,2JAAA,iCAAiC,OAAA","sourcesContent":["export * from './playwright/playwright-world';\nexport * from './core/test-run-options';\nexport { createBeautifulHtmlReport } from './core/cucumber-report-html';\nexport { startWebServer, stopWebServer } from './core/web-server';\nexport type { WebServerConfig } from './core/web-server';\nexport type { BeautifulReportOptions } from './core/cucumber-report-html';\nexport * from './adapters/contract';\nexport * from './adapters/validation';\nexport * from './adapters/registry';\nexport { createNodesV2 } from './plugin/create-nodes';\nexport type { NxCucumberPluginOptions } from './plugin/create-nodes';\nexport { migrateCucumberApiToInferredTasks } from './migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks';\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Tree } from '@nx/devkit';
|
|
2
|
+
interface MigratedProjectReport {
|
|
3
|
+
project: string;
|
|
4
|
+
projectRoot: string;
|
|
5
|
+
removedTargets: string[];
|
|
6
|
+
createdCucumberConfig: boolean;
|
|
7
|
+
manualFollowUps: string[];
|
|
8
|
+
}
|
|
9
|
+
interface MigrationReport {
|
|
10
|
+
dryRun: boolean;
|
|
11
|
+
pluginAdded: boolean;
|
|
12
|
+
removedLegacyTargetDefaults: boolean;
|
|
13
|
+
migratedProjects: MigratedProjectReport[];
|
|
14
|
+
}
|
|
15
|
+
interface MigrationOptions {
|
|
16
|
+
dryRun?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function migrateCucumberApiToInferredTasks(tree: Tree, options?: MigrationOptions): Promise<MigrationReport>;
|
|
19
|
+
export default function migrateCucumberApiToInferredTasksEntry(tree: Tree): Promise<void>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.migrateCucumberApiToInferredTasks = migrateCucumberApiToInferredTasks;
|
|
4
|
+
exports.default = migrateCucumberApiToInferredTasksEntry;
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const LEGACY_EXECUTOR = '@gnuechtel/nx-cucumber:cucumber-api';
|
|
7
|
+
const REPORT_PATH = 'tmp/nx-cucumber-migration-report.json';
|
|
8
|
+
const PLUGIN_NAME = '@gnuechtel/nx-cucumber';
|
|
9
|
+
function isDryRunRequested() {
|
|
10
|
+
const arg = process.argv.some((v) => v === '--dry-run' || v === '--dryRun');
|
|
11
|
+
const env = `${process.env['NX_CUCUMBER_MIGRATION_DRY_RUN'] || ''}`.toLowerCase();
|
|
12
|
+
return arg || env === '1' || env === 'true' || env === 'yes';
|
|
13
|
+
}
|
|
14
|
+
function normalizePath(p) {
|
|
15
|
+
return p.replace(/\\/g, '/');
|
|
16
|
+
}
|
|
17
|
+
function resolveTsNodeProject(projectRoot, tsConfig) {
|
|
18
|
+
if (!tsConfig)
|
|
19
|
+
return `${projectRoot}/tsconfig.json`;
|
|
20
|
+
if (tsConfig.includes('/'))
|
|
21
|
+
return normalizePath(tsConfig);
|
|
22
|
+
return `${projectRoot}/${tsConfig}`;
|
|
23
|
+
}
|
|
24
|
+
function hasNxCucumberPlugin(nxJson) {
|
|
25
|
+
if (!nxJson)
|
|
26
|
+
return false;
|
|
27
|
+
return (nxJson.plugins?.some((plugin) => typeof plugin === 'string' ? plugin === PLUGIN_NAME : plugin?.plugin === PLUGIN_NAME) ?? false);
|
|
28
|
+
}
|
|
29
|
+
function getLegacyTargetNames(project) {
|
|
30
|
+
return Object.entries(project.targets ?? {})
|
|
31
|
+
.filter(([, target]) => target.executor === LEGACY_EXECUTOR)
|
|
32
|
+
.map(([targetName]) => targetName);
|
|
33
|
+
}
|
|
34
|
+
function pickLegacyOptions(project) {
|
|
35
|
+
const targets = project.targets ?? {};
|
|
36
|
+
const legacyTarget = targets['e2e-cucumber']?.executor === LEGACY_EXECUTOR
|
|
37
|
+
? targets['e2e-cucumber']
|
|
38
|
+
: Object.values(targets).find((target) => target.executor === LEGACY_EXECUTOR);
|
|
39
|
+
return (legacyTarget?.options ?? {});
|
|
40
|
+
}
|
|
41
|
+
function extractWorldParameters(options) {
|
|
42
|
+
const worldParameters = {};
|
|
43
|
+
const allowedKeys = [
|
|
44
|
+
'baseUrl',
|
|
45
|
+
'browser',
|
|
46
|
+
'headed',
|
|
47
|
+
'debug',
|
|
48
|
+
'disableAnimations',
|
|
49
|
+
'disableCoverage',
|
|
50
|
+
'disableScreenshotAttachments',
|
|
51
|
+
'disableScreenshotFiles',
|
|
52
|
+
'enableSuccessfulScreenshotFiles',
|
|
53
|
+
'disableVideoAttachments',
|
|
54
|
+
'disableVideoFiles',
|
|
55
|
+
'disableJavaScript',
|
|
56
|
+
'additionalPlaywrightConfiguration',
|
|
57
|
+
'viewport',
|
|
58
|
+
'videoSize',
|
|
59
|
+
];
|
|
60
|
+
for (const key of allowedKeys) {
|
|
61
|
+
if (options[key] !== undefined) {
|
|
62
|
+
worldParameters[key] = options[key];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return worldParameters;
|
|
66
|
+
}
|
|
67
|
+
function createCucumberConfigContent(projectRoot, options) {
|
|
68
|
+
const outputDir = `dist/e2e/${projectRoot}`;
|
|
69
|
+
const featuresDirectory = normalizePath(options.featuresDirectory || `${projectRoot}/features`);
|
|
70
|
+
const testRunner = options.testRunner === 'playwright' ? 'playwright' : 'core';
|
|
71
|
+
const tsNodeProject = resolveTsNodeProject(projectRoot, typeof options.tsConfig === 'string' ? options.tsConfig : undefined);
|
|
72
|
+
const requireEntries = [`'${projectRoot}/src/**/*.ts'`];
|
|
73
|
+
if (testRunner === 'playwright') {
|
|
74
|
+
requireEntries.push(`'node_modules/@gnuechtel/nx-cucumber/src/playwright/playwright-world-default.js'`);
|
|
75
|
+
requireEntries.push(`'node_modules/@gnuechtel/nx-cucumber/src/playwright/playwright-hooks.js'`);
|
|
76
|
+
}
|
|
77
|
+
const worldParameters = {
|
|
78
|
+
outputDirectory: outputDir,
|
|
79
|
+
...extractWorldParameters(options),
|
|
80
|
+
};
|
|
81
|
+
const lines = [
|
|
82
|
+
`process.env.TS_NODE_PROJECT = '${tsNodeProject}';`,
|
|
83
|
+
'module.exports = {',
|
|
84
|
+
' default: {',
|
|
85
|
+
` paths: ['${featuresDirectory}/**/*.feature'],`,
|
|
86
|
+
` requireModule: ['ts-node/register', 'tsconfig-paths/register'],`,
|
|
87
|
+
` require: [${requireEntries.join(', ')}],`,
|
|
88
|
+
` tags: '${typeof options.tags === 'string' ? options.tags : 'not @ignore'}',`,
|
|
89
|
+
' format: [',
|
|
90
|
+
` 'summary',`,
|
|
91
|
+
` 'progress-bar',`,
|
|
92
|
+
` 'json:dist/e2e/${projectRoot}/reports/cucumber-json/cucumber-test-report.json',`,
|
|
93
|
+
` 'html:dist/e2e/${projectRoot}/reports/html/cucumber-test-report-builtin.html',`,
|
|
94
|
+
` 'junit:dist/e2e/${projectRoot}/reports/test-results/cucumber-test-report.xml',`,
|
|
95
|
+
' ],',
|
|
96
|
+
` worldParameters: ${JSON.stringify(worldParameters, null, 4).replace(/\n/g, '\n ')},`,
|
|
97
|
+
...(typeof options.cucumberTimeout === 'number' ? [` timeout: ${options.cucumberTimeout},`] : []),
|
|
98
|
+
' publishQuiet: true,',
|
|
99
|
+
' },',
|
|
100
|
+
'};',
|
|
101
|
+
'',
|
|
102
|
+
];
|
|
103
|
+
return lines.join('\n');
|
|
104
|
+
}
|
|
105
|
+
function shouldFlagWatchTarget(targets) {
|
|
106
|
+
const watchCommand = targets?.['e2e-watch']?.options?.['commands'];
|
|
107
|
+
if (!Array.isArray(watchCommand))
|
|
108
|
+
return false;
|
|
109
|
+
return watchCommand.some((cmd) => typeof cmd === 'string' && cmd.includes('watch-message'));
|
|
110
|
+
}
|
|
111
|
+
function shouldRemoveLegacyE2eRunCommand(targets) {
|
|
112
|
+
const e2e = targets?.['e2e'];
|
|
113
|
+
if (!e2e || e2e.executor !== 'nx:run-commands')
|
|
114
|
+
return false;
|
|
115
|
+
const command = e2e.options?.['command'];
|
|
116
|
+
return typeof command === 'string' && command.includes('e2e-cucumber');
|
|
117
|
+
}
|
|
118
|
+
async function migrateCucumberApiToInferredTasks(tree, options = {}) {
|
|
119
|
+
const dryRun = options.dryRun ?? isDryRunRequested();
|
|
120
|
+
const nxJson = ((0, devkit_1.readNxJson)(tree) ?? {});
|
|
121
|
+
const report = {
|
|
122
|
+
dryRun,
|
|
123
|
+
pluginAdded: false,
|
|
124
|
+
removedLegacyTargetDefaults: false,
|
|
125
|
+
migratedProjects: [],
|
|
126
|
+
};
|
|
127
|
+
const hadPlugin = hasNxCucumberPlugin(nxJson);
|
|
128
|
+
if (!hadPlugin) {
|
|
129
|
+
report.pluginAdded = true;
|
|
130
|
+
if (!dryRun) {
|
|
131
|
+
nxJson.plugins ??= [];
|
|
132
|
+
nxJson.plugins.push(PLUGIN_NAME);
|
|
133
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (nxJson.targetDefaults?.[LEGACY_EXECUTOR]) {
|
|
137
|
+
report.removedLegacyTargetDefaults = true;
|
|
138
|
+
if (!dryRun) {
|
|
139
|
+
delete nxJson.targetDefaults[LEGACY_EXECUTOR];
|
|
140
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
for (const [projectName, projectConfig] of (0, devkit_1.getProjects)(tree).entries()) {
|
|
144
|
+
const legacyTargets = getLegacyTargetNames(projectConfig);
|
|
145
|
+
const removeLegacyRunCommandTarget = shouldRemoveLegacyE2eRunCommand(projectConfig.targets);
|
|
146
|
+
const removeLegacyWatchTarget = shouldFlagWatchTarget(projectConfig.targets);
|
|
147
|
+
if (legacyTargets.length === 0 && !removeLegacyRunCommandTarget && !removeLegacyWatchTarget)
|
|
148
|
+
continue;
|
|
149
|
+
const manualFollowUps = [];
|
|
150
|
+
const removedTargets = [...legacyTargets];
|
|
151
|
+
if (removeLegacyRunCommandTarget && !removedTargets.includes('e2e')) {
|
|
152
|
+
removedTargets.push('e2e');
|
|
153
|
+
}
|
|
154
|
+
if (removeLegacyWatchTarget && !removedTargets.includes('e2e-watch')) {
|
|
155
|
+
removedTargets.push('e2e-watch');
|
|
156
|
+
}
|
|
157
|
+
const cucumberConfigPath = `${projectConfig.root}/cucumber.js`;
|
|
158
|
+
const hasCucumberConfig = tree.exists(cucumberConfigPath);
|
|
159
|
+
const legacyOptions = pickLegacyOptions(projectConfig);
|
|
160
|
+
if (hasCucumberConfig) {
|
|
161
|
+
manualFollowUps.push(`Existing ${cucumberConfigPath} was kept. Verify tags/paths/worldParameters still reflect prior executor options.`);
|
|
162
|
+
}
|
|
163
|
+
const updatedProject = {
|
|
164
|
+
...projectConfig,
|
|
165
|
+
targets: {
|
|
166
|
+
...(projectConfig.targets ?? {}),
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
for (const targetName of removedTargets) {
|
|
170
|
+
delete updatedProject.targets?.[targetName];
|
|
171
|
+
}
|
|
172
|
+
if (!dryRun) {
|
|
173
|
+
(0, devkit_1.updateProjectConfiguration)(tree, projectName, updatedProject);
|
|
174
|
+
if (!hasCucumberConfig) {
|
|
175
|
+
tree.write(cucumberConfigPath, createCucumberConfigContent(projectConfig.root, legacyOptions));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
report.migratedProjects.push({
|
|
179
|
+
project: projectName,
|
|
180
|
+
projectRoot: projectConfig.root,
|
|
181
|
+
removedTargets,
|
|
182
|
+
createdCucumberConfig: !hasCucumberConfig,
|
|
183
|
+
manualFollowUps,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
if (!dryRun) {
|
|
187
|
+
tree.write(REPORT_PATH, JSON.stringify(report, null, 2));
|
|
188
|
+
}
|
|
189
|
+
devkit_1.logger.info(`[nx-cucumber migration] migrated projects: ${report.migratedProjects.length}, pluginAdded: ${report.pluginAdded}, dryRun: ${report.dryRun}`);
|
|
190
|
+
if (report.migratedProjects.length > 0) {
|
|
191
|
+
for (const project of report.migratedProjects) {
|
|
192
|
+
devkit_1.logger.info(`[nx-cucumber migration] ${project.project}: removed targets [${project.removedTargets.join(', ')}], created cucumber.js: ${project.createdCucumberConfig}`);
|
|
193
|
+
for (const followUp of project.manualFollowUps) {
|
|
194
|
+
devkit_1.logger.warn(`[nx-cucumber migration] ${project.project}: ${followUp}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!dryRun) {
|
|
199
|
+
devkit_1.logger.info(`[nx-cucumber migration] report written to ${REPORT_PATH}`);
|
|
200
|
+
}
|
|
201
|
+
return report;
|
|
202
|
+
}
|
|
203
|
+
async function migrateCucumberApiToInferredTasksEntry(tree) {
|
|
204
|
+
await migrateCucumberApiToInferredTasks(tree);
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=migrate-cucumber-api-to-inferred-tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-cucumber-api-to-inferred-tasks.js","sourceRoot":"","sources":["../../../../../../libs/nx-cucumber/src/migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n logger,\n NxJsonConfiguration,\n ProjectConfiguration,\n readNxJson,\n Tree,\n updateNxJson,\n updateProjectConfiguration,\n getProjects,\n} from '@nx/devkit';\n\nconst LEGACY_EXECUTOR = '@gnuechtel/nx-cucumber:cucumber-api';\nconst REPORT_PATH = 'tmp/nx-cucumber-migration-report.json';\nconst PLUGIN_NAME = '@gnuechtel/nx-cucumber';\n\ninterface LegacyOptions {\n testRunner?: 'core' | 'playwright';\n featuresDirectory?: string;\n tags?: string;\n cucumberTimeout?: number;\n tsConfig?: string;\n baseUrl?: string;\n browser?: string;\n headed?: boolean;\n debug?: boolean;\n disableAnimations?: boolean;\n disableCoverage?: boolean;\n disableScreenshotAttachments?: boolean;\n disableScreenshotFiles?: boolean;\n enableSuccessfulScreenshotFiles?: boolean;\n disableVideoAttachments?: boolean;\n disableVideoFiles?: boolean;\n disableJavaScript?: boolean;\n additionalPlaywrightConfiguration?: Record<string, unknown>;\n viewport?: Record<string, unknown>;\n videoSize?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ninterface MigratedProjectReport {\n project: string;\n projectRoot: string;\n removedTargets: string[];\n createdCucumberConfig: boolean;\n manualFollowUps: string[];\n}\n\ninterface MigrationReport {\n dryRun: boolean;\n pluginAdded: boolean;\n removedLegacyTargetDefaults: boolean;\n migratedProjects: MigratedProjectReport[];\n}\n\ninterface MigrationOptions {\n dryRun?: boolean;\n}\n\nfunction isDryRunRequested(): boolean {\n const arg = process.argv.some((v) => v === '--dry-run' || v === '--dryRun');\n const env = `${process.env['NX_CUCUMBER_MIGRATION_DRY_RUN'] || ''}`.toLowerCase();\n return arg || env === '1' || env === 'true' || env === 'yes';\n}\n\nfunction normalizePath(p: string): string {\n return p.replace(/\\\\/g, '/');\n}\n\nfunction resolveTsNodeProject(projectRoot: string, tsConfig?: string): string {\n if (!tsConfig) return `${projectRoot}/tsconfig.json`;\n if (tsConfig.includes('/')) return normalizePath(tsConfig);\n return `${projectRoot}/${tsConfig}`;\n}\n\nfunction hasNxCucumberPlugin(nxJson: NxJsonConfiguration | null): boolean {\n if (!nxJson) return false;\n return (\n nxJson.plugins?.some((plugin) =>\n typeof plugin === 'string' ? plugin === PLUGIN_NAME : plugin?.plugin === PLUGIN_NAME\n ) ?? false\n );\n}\n\nfunction getLegacyTargetNames(project: ProjectConfiguration): string[] {\n return Object.entries(project.targets ?? {})\n .filter(([, target]) => target.executor === LEGACY_EXECUTOR)\n .map(([targetName]) => targetName);\n}\n\nfunction pickLegacyOptions(project: ProjectConfiguration): LegacyOptions {\n const targets = project.targets ?? {};\n const legacyTarget =\n targets['e2e-cucumber']?.executor === LEGACY_EXECUTOR\n ? targets['e2e-cucumber']\n : Object.values(targets).find((target) => target.executor === LEGACY_EXECUTOR);\n return (legacyTarget?.options ?? {}) as LegacyOptions;\n}\n\nfunction extractWorldParameters(options: LegacyOptions): Record<string, unknown> {\n const worldParameters: Record<string, unknown> = {};\n const allowedKeys = [\n 'baseUrl',\n 'browser',\n 'headed',\n 'debug',\n 'disableAnimations',\n 'disableCoverage',\n 'disableScreenshotAttachments',\n 'disableScreenshotFiles',\n 'enableSuccessfulScreenshotFiles',\n 'disableVideoAttachments',\n 'disableVideoFiles',\n 'disableJavaScript',\n 'additionalPlaywrightConfiguration',\n 'viewport',\n 'videoSize',\n ];\n\n for (const key of allowedKeys) {\n if (options[key] !== undefined) {\n worldParameters[key] = options[key];\n }\n }\n return worldParameters;\n}\n\nfunction createCucumberConfigContent(projectRoot: string, options: LegacyOptions): string {\n const outputDir = `dist/e2e/${projectRoot}`;\n const featuresDirectory = normalizePath(options.featuresDirectory || `${projectRoot}/features`);\n const testRunner = options.testRunner === 'playwright' ? 'playwright' : 'core';\n const tsNodeProject = resolveTsNodeProject(\n projectRoot,\n typeof options.tsConfig === 'string' ? options.tsConfig : undefined\n );\n\n const requireEntries: string[] = [`'${projectRoot}/src/**/*.ts'`];\n if (testRunner === 'playwright') {\n requireEntries.push(`'node_modules/@gnuechtel/nx-cucumber/src/playwright/playwright-world-default.js'`);\n requireEntries.push(`'node_modules/@gnuechtel/nx-cucumber/src/playwright/playwright-hooks.js'`);\n }\n\n const worldParameters = {\n outputDirectory: outputDir,\n ...extractWorldParameters(options),\n };\n\n const lines: string[] = [\n `process.env.TS_NODE_PROJECT = '${tsNodeProject}';`,\n 'module.exports = {',\n ' default: {',\n ` paths: ['${featuresDirectory}/**/*.feature'],`,\n ` requireModule: ['ts-node/register', 'tsconfig-paths/register'],`,\n ` require: [${requireEntries.join(', ')}],`,\n ` tags: '${typeof options.tags === 'string' ? options.tags : 'not @ignore'}',`,\n ' format: [',\n ` 'summary',`,\n ` 'progress-bar',`,\n ` 'json:dist/e2e/${projectRoot}/reports/cucumber-json/cucumber-test-report.json',`,\n ` 'html:dist/e2e/${projectRoot}/reports/html/cucumber-test-report-builtin.html',`,\n ` 'junit:dist/e2e/${projectRoot}/reports/test-results/cucumber-test-report.xml',`,\n ' ],',\n ` worldParameters: ${JSON.stringify(worldParameters, null, 4).replace(/\\n/g, '\\n ')},`,\n ...(typeof options.cucumberTimeout === 'number' ? [` timeout: ${options.cucumberTimeout},`] : []),\n ' publishQuiet: true,',\n ' },',\n '};',\n '',\n ];\n return lines.join('\\n');\n}\n\nfunction shouldFlagWatchTarget(targets: ProjectConfiguration['targets']): boolean {\n const watchCommand = targets?.['e2e-watch']?.options?.['commands'];\n if (!Array.isArray(watchCommand)) return false;\n return watchCommand.some((cmd) => typeof cmd === 'string' && cmd.includes('watch-message'));\n}\n\nfunction shouldRemoveLegacyE2eRunCommand(targets: ProjectConfiguration['targets']): boolean {\n const e2e = targets?.['e2e'];\n if (!e2e || e2e.executor !== 'nx:run-commands') return false;\n const command = e2e.options?.['command'];\n return typeof command === 'string' && command.includes('e2e-cucumber');\n}\n\nexport async function migrateCucumberApiToInferredTasks(\n tree: Tree,\n options: MigrationOptions = {}\n): Promise<MigrationReport> {\n const dryRun = options.dryRun ?? isDryRunRequested();\n const nxJson = (readNxJson(tree) ?? {}) as NxJsonConfiguration;\n const report: MigrationReport = {\n dryRun,\n pluginAdded: false,\n removedLegacyTargetDefaults: false,\n migratedProjects: [],\n };\n\n const hadPlugin = hasNxCucumberPlugin(nxJson);\n if (!hadPlugin) {\n report.pluginAdded = true;\n if (!dryRun) {\n nxJson.plugins ??= [];\n nxJson.plugins.push(PLUGIN_NAME);\n updateNxJson(tree, nxJson);\n }\n }\n\n if (nxJson.targetDefaults?.[LEGACY_EXECUTOR]) {\n report.removedLegacyTargetDefaults = true;\n if (!dryRun) {\n delete nxJson.targetDefaults[LEGACY_EXECUTOR];\n updateNxJson(tree, nxJson);\n }\n }\n\n for (const [projectName, projectConfig] of getProjects(tree).entries()) {\n const legacyTargets = getLegacyTargetNames(projectConfig);\n const removeLegacyRunCommandTarget = shouldRemoveLegacyE2eRunCommand(projectConfig.targets);\n const removeLegacyWatchTarget = shouldFlagWatchTarget(projectConfig.targets);\n if (legacyTargets.length === 0 && !removeLegacyRunCommandTarget && !removeLegacyWatchTarget) continue;\n\n const manualFollowUps: string[] = [];\n const removedTargets = [...legacyTargets];\n if (removeLegacyRunCommandTarget && !removedTargets.includes('e2e')) {\n removedTargets.push('e2e');\n }\n if (removeLegacyWatchTarget && !removedTargets.includes('e2e-watch')) {\n removedTargets.push('e2e-watch');\n }\n\n const cucumberConfigPath = `${projectConfig.root}/cucumber.js`;\n const hasCucumberConfig = tree.exists(cucumberConfigPath);\n const legacyOptions = pickLegacyOptions(projectConfig);\n\n if (hasCucumberConfig) {\n manualFollowUps.push(\n `Existing ${cucumberConfigPath} was kept. Verify tags/paths/worldParameters still reflect prior executor options.`\n );\n }\n\n const updatedProject: ProjectConfiguration = {\n ...projectConfig,\n targets: {\n ...(projectConfig.targets ?? {}),\n },\n };\n\n for (const targetName of removedTargets) {\n delete updatedProject.targets?.[targetName];\n }\n\n if (!dryRun) {\n updateProjectConfiguration(tree, projectName, updatedProject);\n if (!hasCucumberConfig) {\n tree.write(cucumberConfigPath, createCucumberConfigContent(projectConfig.root, legacyOptions));\n }\n }\n\n report.migratedProjects.push({\n project: projectName,\n projectRoot: projectConfig.root,\n removedTargets,\n createdCucumberConfig: !hasCucumberConfig,\n manualFollowUps,\n });\n }\n\n if (!dryRun) {\n tree.write(REPORT_PATH, JSON.stringify(report, null, 2));\n }\n\n logger.info(\n `[nx-cucumber migration] migrated projects: ${report.migratedProjects.length}, pluginAdded: ${report.pluginAdded}, dryRun: ${report.dryRun}`\n );\n if (report.migratedProjects.length > 0) {\n for (const project of report.migratedProjects) {\n logger.info(\n `[nx-cucumber migration] ${project.project}: removed targets [${project.removedTargets.join(\n ', '\n )}], created cucumber.js: ${project.createdCucumberConfig}`\n );\n for (const followUp of project.manualFollowUps) {\n logger.warn(`[nx-cucumber migration] ${project.project}: ${followUp}`);\n }\n }\n }\n if (!dryRun) {\n logger.info(`[nx-cucumber migration] report written to ${REPORT_PATH}`);\n }\n\n return report;\n}\n\nexport default async function migrateCucumberApiToInferredTasksEntry(tree: Tree): Promise<void> {\n await migrateCucumberApiToInferredTasks(tree);\n}\n"]}
|