@gnuechtel/nx-cucumber 24.3.1 → 24.3.2
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
CHANGED
|
@@ -172,6 +172,11 @@ affected until a repaired Nx patch is adopted. See
|
|
|
172
172
|
|
|
173
173
|
This plugin requires [Node.js](https://nodejs.org/), [Nx](https://nx.dev/) and [Cucumber](https://github.com/cucumber/cucumber-js). Version 24.3.0 targets Nx `>=24 <25` and Node.js 24 or 26; published 2.x packages remain the Nx-22 path. Plugin 23.x remains available for Nx 23. Browser automation uses the [Playwright library](https://playwright.dev/docs/library) when selected by the generator. Consult `package.json` for all dependency requirements and `.gitlab-ci.yml` for the pinned CI versions. Minor and patch versions follow this plugin's changes independently of Nx.
|
|
174
174
|
|
|
175
|
+
For generated Cucumber/Playwright runners on Linux and macOS, reclaiming an
|
|
176
|
+
occupied server port requires `lsof` in `PATH` (for example,
|
|
177
|
+
`apt-get install lsof` on Debian-based Linux). An unused port needs no additional
|
|
178
|
+
utility. Windows uses `netstat` and `taskkill`.
|
|
179
|
+
|
|
175
180
|
## Quick start
|
|
176
181
|
|
|
177
182
|
To immediately use this plugin with a new example React application use the following commands:
|
|
@@ -277,7 +282,7 @@ The `e2e` target behavior depends on the selected test runner:
|
|
|
277
282
|
- **Core runner:** no explicit `e2e` target is generated. The `e2e` task is inferred by the plugin from `cucumber.js`.
|
|
278
283
|
- **Playwright runner:** explicit command targets are generated:
|
|
279
284
|
- `e2e-prepare` installs Playwright Chromium (Linux uses `--with-deps`) and is configured with `cache: false`.
|
|
280
|
-
- `e2e` runs a generated `run-e2e.js` lifecycle script that manages the full dev server lifecycle (clear port, start server, wait for readiness, run Cucumber, stop server) using
|
|
285
|
+
- `e2e` runs a generated `run-e2e.js` lifecycle script that manages the full dev server lifecycle (clear port, start server, wait for readiness, run Cucumber, stop server) using Node.js built-ins and the Unix `lsof` utility for reclaiming occupied ports.
|
|
281
286
|
- `e2e-ci` runs `e2e-prepare` and then `e2e`.
|
|
282
287
|
|
|
283
288
|
### Additional project generator options
|
package/package.json
CHANGED
|
@@ -55,15 +55,20 @@ async function run() {
|
|
|
55
55
|
stdio: 'pipe',
|
|
56
56
|
});
|
|
57
57
|
} else {
|
|
58
|
-
//
|
|
58
|
+
// The shell can close before its descendants. Give the whole process
|
|
59
|
+
// group a grace period, then stop any remaining server processes.
|
|
59
60
|
process.kill(-server.pid, 'SIGTERM');
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
const deadline = Date.now() + 5_000;
|
|
62
|
+
while (Date.now() < deadline) {
|
|
63
|
+
try {
|
|
64
|
+
process.kill(-server.pid, 0);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (error.code === 'ESRCH') return;
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
await sleep(50);
|
|
65
70
|
}
|
|
66
|
-
|
|
71
|
+
process.kill(-server.pid, 'SIGKILL');
|
|
67
72
|
}
|
|
68
73
|
} catch {
|
|
69
74
|
/* process already exited */
|
|
@@ -74,16 +79,12 @@ async function run() {
|
|
|
74
79
|
const deadline = Date.now() + SERVER_START_TIMEOUT_MS;
|
|
75
80
|
while (!(await portOpen(PORT))) {
|
|
76
81
|
if (processClosed) {
|
|
77
|
-
console.error(
|
|
78
|
-
'[nx-cucumber] Server process exited before becoming ready',
|
|
79
|
-
);
|
|
82
|
+
console.error('[nx-cucumber] Server process exited before becoming ready');
|
|
80
83
|
process.exit(1);
|
|
81
84
|
}
|
|
82
85
|
if (Date.now() > deadline) {
|
|
83
86
|
await teardown();
|
|
84
|
-
console.error(
|
|
85
|
-
`[nx-cucumber] Server did not respond on port ${PORT} within ${SERVER_START_TIMEOUT_MS / 1000}s`,
|
|
86
|
-
);
|
|
87
|
+
console.error(`[nx-cucumber] Server did not respond on port ${PORT} within ${SERVER_START_TIMEOUT_MS / 1000}s`);
|
|
87
88
|
process.exit(1);
|
|
88
89
|
}
|
|
89
90
|
await sleep(500);
|
|
@@ -130,13 +131,29 @@ async function clearPort() {
|
|
|
130
131
|
/* port already free */
|
|
131
132
|
}
|
|
132
133
|
} else {
|
|
134
|
+
let listenerPids = '';
|
|
133
135
|
try {
|
|
134
|
-
cp.
|
|
135
|
-
|
|
136
|
-
stdio: 'pipe',
|
|
136
|
+
listenerPids = cp.execFileSync('lsof', ['-nP', '-t', `-iTCP:${PORT}`, '-sTCP:LISTEN'], {
|
|
137
|
+
encoding: 'utf8',
|
|
138
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
137
139
|
});
|
|
138
|
-
} catch {
|
|
139
|
-
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (error.code === 'ENOENT') {
|
|
142
|
+
throw new Error(
|
|
143
|
+
`[nx-cucumber] lsof is required to reclaim port ${PORT}. Install lsof or free the port manually.`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
// Exit 1 with no output means the listener disappeared after the probe.
|
|
147
|
+
if (error.status !== 1 || error.stdout?.length || error.stderr?.length) {
|
|
148
|
+
throw new Error(`[nx-cucumber] Failed to inspect port ${PORT} with lsof (${error.code || error.status}).`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
for (const pid of new Set(listenerPids.trim().split(/\s+/).filter(Boolean))) {
|
|
152
|
+
try {
|
|
153
|
+
process.kill(Number(pid), 'SIGKILL');
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (error.code !== 'ESRCH') throw error;
|
|
156
|
+
}
|
|
140
157
|
}
|
|
141
158
|
}
|
|
142
159
|
|