plum-e2e 2.4.9 → 2.4.11
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 +18 -17
- package/backend/lib/runnerProcess.js +18 -1
- package/bin/plum.js +91 -18
- package/frontend/src/routes/reports/[id]/+page.svelte +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -78,23 +78,24 @@ Full documentation is available at:
|
|
|
78
78
|
|
|
79
79
|
## Command Reference
|
|
80
80
|
|
|
81
|
-
| Command | Description
|
|
82
|
-
| ----------------------------- |
|
|
83
|
-
| `plum init` | Initialize a new project in the current folder
|
|
84
|
-
| `plum server start` | Start the full UI stack via Docker
|
|
85
|
-
| `plum server
|
|
86
|
-
| `plum
|
|
87
|
-
| `plum
|
|
88
|
-
| `plum
|
|
89
|
-
| `plum
|
|
90
|
-
| `plum
|
|
91
|
-
| `plum
|
|
92
|
-
| `plum
|
|
93
|
-
| `plum
|
|
94
|
-
| `plum
|
|
95
|
-
| `plum
|
|
96
|
-
| `plum
|
|
97
|
-
| `plum
|
|
81
|
+
| Command | Description |
|
|
82
|
+
| ----------------------------- | ------------------------------------------------------------------ |
|
|
83
|
+
| `plum init` | Initialize a new project in the current folder |
|
|
84
|
+
| `plum server start` | Start the full UI stack via Docker |
|
|
85
|
+
| `plum server restart` | Rebuild Docker images and restart the server without prompts |
|
|
86
|
+
| `plum server stop` | Stop the server (data preserved) |
|
|
87
|
+
| `plum server reconfig` | Re-enter server settings without starting |
|
|
88
|
+
| `plum update` | Update Plum and auto-restart whatever is running (server or node) |
|
|
89
|
+
| `plum node start` | Set up connectivity, start a runner node, and open the runner menu |
|
|
90
|
+
| `plum node restart` | Stop, refresh dependencies, and restart the runner node |
|
|
91
|
+
| `plum node stop` | Stop the runner node started from this folder |
|
|
92
|
+
| `plum node reconfig` | Re-enter node settings and re-register |
|
|
93
|
+
| `plum run-test` | Run all tests locally without Docker |
|
|
94
|
+
| `plum run-test @tag` | Run tests matching a tag |
|
|
95
|
+
| `plum run-test --parallel N` | Run tests across N parallel workers |
|
|
96
|
+
| `plum run-test --browser <b>` | Run in `chromium` (default) or `firefox` |
|
|
97
|
+
| `plum create-step` | Interactively scaffold a new step definition |
|
|
98
|
+
| `plum manage-runners` | Open the interactive runner management menu |
|
|
98
99
|
|
|
99
100
|
---
|
|
100
101
|
|
|
@@ -139,9 +139,26 @@ function statusOf(id, registry = loadRegistry()) {
|
|
|
139
139
|
*/
|
|
140
140
|
function prepareEnv() {
|
|
141
141
|
const stdio = ['ignore', 'inherit', 'inherit'];
|
|
142
|
-
|
|
142
|
+
|
|
143
|
+
// Re-run npm install when node_modules is missing OR when the plum package
|
|
144
|
+
// version has changed (npm install -g wipes node_modules on upgrade).
|
|
145
|
+
const markerPath = path.join(BACKEND_DIR, 'node_modules', '.plum-version');
|
|
146
|
+
let installedVersion = null;
|
|
147
|
+
try {
|
|
148
|
+
installedVersion = fs.readFileSync(markerPath, 'utf8').trim();
|
|
149
|
+
} catch {}
|
|
150
|
+
const currentVersion = JSON.parse(
|
|
151
|
+
fs.readFileSync(path.join(BACKEND_DIR, '..', 'package.json'), 'utf8')
|
|
152
|
+
).version;
|
|
153
|
+
|
|
154
|
+
if (
|
|
155
|
+
!fs.existsSync(path.join(BACKEND_DIR, 'node_modules')) ||
|
|
156
|
+
installedVersion !== currentVersion
|
|
157
|
+
) {
|
|
143
158
|
execSync('npm install', { cwd: BACKEND_DIR, stdio, shell: true });
|
|
159
|
+
fs.writeFileSync(markerPath, currentVersion, 'utf8');
|
|
144
160
|
}
|
|
161
|
+
|
|
145
162
|
execSync('npx playwright install chromium firefox', { cwd: BACKEND_DIR, stdio, shell: true });
|
|
146
163
|
}
|
|
147
164
|
|
package/bin/plum.js
CHANGED
|
@@ -324,7 +324,7 @@ async function serverStart() {
|
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
async function serverRestart() {
|
|
327
|
-
clack.intro(pc.bgMagenta(pc.white(' 🟣 Plum — Restart ')));
|
|
327
|
+
clack.intro(pc.bgMagenta(pc.white(' 🟣 Plum — Server Restart ')));
|
|
328
328
|
const { loadServerConfig } = serverConfigLib();
|
|
329
329
|
const cfg = loadServerConfig(process.cwd());
|
|
330
330
|
applyServerConfig(cfg);
|
|
@@ -349,7 +349,7 @@ async function serverRestart() {
|
|
|
349
349
|
s.stop(ready ? pc.green('✓ Server is ready') : pc.yellow('Server may still be starting'));
|
|
350
350
|
clack.log.info(`UI: ${pc.cyan(`http://localhost:${cfg.frontendPort}`)}`);
|
|
351
351
|
clack.log.info(`API: ${pc.cyan(`http://localhost:${cfg.backendPort}`)}`);
|
|
352
|
-
clack.outro(pc.green('
|
|
352
|
+
clack.outro(pc.green('Server restarted.'));
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
async function serverUpdate() {
|
|
@@ -357,8 +357,33 @@ async function serverUpdate() {
|
|
|
357
357
|
clack.log.step('Fetching latest Plum version…');
|
|
358
358
|
execSync('npm install -g plum-e2e@latest', { stdio: 'inherit' });
|
|
359
359
|
clack.log.success('Plum CLI updated.');
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
|
|
361
|
+
const serverCfgPath = path.join(process.cwd(), '.plum-server.json');
|
|
362
|
+
const hasServerCfg = fs.existsSync(serverCfgPath);
|
|
363
|
+
|
|
364
|
+
const { loadNodeConfig } = nodeRegisterLib();
|
|
365
|
+
const { loadRegistry, isAlive } = runnerProcessLib();
|
|
366
|
+
const nodeCfg = loadNodeConfig(process.cwd());
|
|
367
|
+
const registry = loadRegistry();
|
|
368
|
+
const nodeRunning = !!(
|
|
369
|
+
nodeCfg.id &&
|
|
370
|
+
registry[String(nodeCfg.id)]?.pid &&
|
|
371
|
+
isAlive(registry[String(nodeCfg.id)].pid)
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
if (hasServerCfg) {
|
|
375
|
+
clack.log.step('Rebuilding server with new version…');
|
|
376
|
+
await serverRestart();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (nodeRunning) {
|
|
380
|
+
clack.log.step('Restarting node runner with new version…');
|
|
381
|
+
await nodeRestart();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (!hasServerCfg && !nodeRunning) {
|
|
385
|
+
clack.outro(pc.green('Plum updated. Run `plum server start` or `plum node start` to launch.'));
|
|
386
|
+
}
|
|
362
387
|
}
|
|
363
388
|
|
|
364
389
|
async function serverReconfig() {
|
|
@@ -528,6 +553,46 @@ async function nodeStart({ reconfig }) {
|
|
|
528
553
|
clack.outro(`Manage runners anytime: ${pc.cyan('plum manage-runners')}`);
|
|
529
554
|
}
|
|
530
555
|
|
|
556
|
+
async function nodeRestart() {
|
|
557
|
+
clack.intro(pc.bgMagenta(pc.white(' 🟣 Plum — Node Restart ')));
|
|
558
|
+
const { loadNodeConfig } = nodeRegisterLib();
|
|
559
|
+
const { prepareEnv, stopNode, startNode } = runnerProcessLib();
|
|
560
|
+
const cfg = loadNodeConfig(process.cwd());
|
|
561
|
+
|
|
562
|
+
if (!cfg.id) {
|
|
563
|
+
clack.log.warn('No node configured in this folder — run `plum node start` first.');
|
|
564
|
+
clack.outro(pc.dim('Done.'));
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const stopped = stopNode(String(cfg.id));
|
|
569
|
+
if (stopped) {
|
|
570
|
+
clack.log.success(`Stopped runner "${cfg.name ?? cfg.id}".`);
|
|
571
|
+
} else {
|
|
572
|
+
clack.log.info('Node was not running — starting fresh.');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
clack.log.step('Refreshing dependencies…');
|
|
576
|
+
try {
|
|
577
|
+
prepareEnv();
|
|
578
|
+
} catch (e) {
|
|
579
|
+
clack.log.warn(`Dependency refresh failed: ${e.message}`);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
try {
|
|
583
|
+
const entry = startNode({ id: String(cfg.id), port: cfg.port, token: cfg.token });
|
|
584
|
+
clack.log.success(
|
|
585
|
+
pc.green(
|
|
586
|
+
`Node "${cfg.name}" restarted (pid ${entry.pid}) — logs at backend/logs/runner-${cfg.id}.log`
|
|
587
|
+
)
|
|
588
|
+
);
|
|
589
|
+
} catch (e) {
|
|
590
|
+
clack.log.warn(`Could not restart node: ${e.message}`);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
clack.outro(pc.green('Node restarted.'));
|
|
594
|
+
}
|
|
595
|
+
|
|
531
596
|
async function nodeReconfig() {
|
|
532
597
|
clack.intro(pc.bgMagenta(pc.white(' 🟣 Plum — Reconfigure Node ')));
|
|
533
598
|
const cfg = await configureNode({ force: true });
|
|
@@ -809,11 +874,17 @@ switch (command) {
|
|
|
809
874
|
// intentional fall-through
|
|
810
875
|
|
|
811
876
|
case 'start':
|
|
812
|
-
|
|
877
|
+
console.log(
|
|
878
|
+
`\nSpecify what to start:\n ${pc.cyan('plum server start')} — start the web UI stack (Docker)\n ${pc.cyan('plum node start')} — start a runner node\n`
|
|
879
|
+
);
|
|
880
|
+
process.exit(1);
|
|
813
881
|
break;
|
|
814
882
|
|
|
815
883
|
case 'restart':
|
|
816
|
-
|
|
884
|
+
console.log(
|
|
885
|
+
`\nSpecify what to restart:\n ${pc.cyan('plum server restart')} — rebuild and restart the server\n ${pc.cyan('plum node restart')} — restart the runner node\n`
|
|
886
|
+
);
|
|
887
|
+
process.exit(1);
|
|
817
888
|
break;
|
|
818
889
|
|
|
819
890
|
case 'update':
|
|
@@ -894,14 +965,10 @@ switch (command) {
|
|
|
894
965
|
}
|
|
895
966
|
|
|
896
967
|
case 'stop':
|
|
897
|
-
console.log(
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
stdio: 'inherit'
|
|
902
|
-
});
|
|
903
|
-
console.log('✅ Plum stopped. Your data is preserved in the database volume.\n');
|
|
904
|
-
console.log('--------------------------------------\n');
|
|
968
|
+
console.log(
|
|
969
|
+
`\nSpecify what to stop:\n ${pc.cyan('plum server stop')} — stop the web UI stack\n ${pc.cyan('plum node stop')} — stop the runner node\n`
|
|
970
|
+
);
|
|
971
|
+
process.exit(1);
|
|
905
972
|
break;
|
|
906
973
|
|
|
907
974
|
case 'node': {
|
|
@@ -942,6 +1009,11 @@ switch (command) {
|
|
|
942
1009
|
break;
|
|
943
1010
|
}
|
|
944
1011
|
|
|
1012
|
+
if (subcommand === 'restart') {
|
|
1013
|
+
await nodeRestart();
|
|
1014
|
+
break;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
945
1017
|
if (subcommand === 'reconfig') {
|
|
946
1018
|
await nodeReconfig();
|
|
947
1019
|
break;
|
|
@@ -1006,16 +1078,16 @@ switch (command) {
|
|
|
1006
1078
|
console.log('--------------------------------------\n');
|
|
1007
1079
|
console.log('Usage: plum <command>\n');
|
|
1008
1080
|
console.log(' init Set up a new Plum project');
|
|
1009
|
-
console.log(' server start Start the full UI stack (interactive
|
|
1081
|
+
console.log(' server start Start the full UI stack (interactive)');
|
|
1010
1082
|
console.log(' --headless <bool> Run browsers headless (true/false)');
|
|
1011
1083
|
console.log(' --backend-port <n> Host port for the backend/API (default: 3001)');
|
|
1012
1084
|
console.log(' --frontend-port <n> Host port for the UI (default: 5173)');
|
|
1085
|
+
console.log(' server restart Rebuild Docker images and restart the server (no prompts)');
|
|
1086
|
+
console.log(' server stop Stop the server (data preserved)');
|
|
1013
1087
|
console.log(' server reconfig Re-enter server settings without starting');
|
|
1014
1088
|
console.log(
|
|
1015
|
-
'
|
|
1089
|
+
' update Update Plum and restart whichever is running (server/node)'
|
|
1016
1090
|
);
|
|
1017
|
-
console.log(' server stop Stop the server (alias: plum stop)');
|
|
1018
|
-
console.log(' update Update Plum to the latest version and restart the server');
|
|
1019
1091
|
console.log(' node start Start a runner node (interactive), then open runner menu');
|
|
1020
1092
|
console.log(' --primary <url> Primary Plum server to auto-register with');
|
|
1021
1093
|
console.log(' --url <url> Address the primary calls back (default: <lan-ip>:<port>;');
|
|
@@ -1026,6 +1098,7 @@ switch (command) {
|
|
|
1026
1098
|
console.log(' --token <secret> Auth token (auto-generated + saved if omitted)');
|
|
1027
1099
|
console.log(' --name <name> Runner name shown on the primary (default: node-<rand>)');
|
|
1028
1100
|
console.log(' --browser <name> chromium | firefox (default: chromium)');
|
|
1101
|
+
console.log(' node restart Stop, refresh deps, and restart the node runner');
|
|
1029
1102
|
console.log(' node reconfig Re-enter node settings + re-register, without starting');
|
|
1030
1103
|
console.log(' node stop Stop the runner node started from this folder');
|
|
1031
1104
|
console.log(' manage-runners Open the runner management menu');
|