plum-e2e 1.3.0 → 1.3.1
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 +19 -11
- package/backend/config/scripts/run-tests.js +6 -0
- package/backend/package.json +1 -1
- package/bin/plum.js +32 -16
- package/frontend/package.json +1 -1
- package/frontend/src/routes/reports/[id]/+page.svelte +21 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ my-tests/
|
|
|
50
50
|
│ ├── pages/ — Page Object Models
|
|
51
51
|
│ └── utils/ — Browser setup, hooks, shared helpers
|
|
52
52
|
├── .env — Base URL and browser settings
|
|
53
|
-
├── .gitignore — Pre-configured to exclude reports/
|
|
53
|
+
├── .gitignore — Pre-configured to exclude .env and reports/
|
|
54
54
|
├── plum.plugins.json — Add extra npm packages for your tests
|
|
55
55
|
└── tsconfig.json — IDE type resolution (no local install needed)
|
|
56
56
|
```
|
|
@@ -247,17 +247,24 @@ Follow the prompts — Plum writes the boilerplate, you fill in the implementati
|
|
|
247
247
|
|
|
248
248
|
### Run Tests Locally
|
|
249
249
|
|
|
250
|
-
Use `plum
|
|
250
|
+
Use `plum run-test` to run tests directly on your machine without Docker:
|
|
251
251
|
|
|
252
252
|
```bash
|
|
253
|
-
plum
|
|
254
|
-
plum
|
|
255
|
-
plum
|
|
256
|
-
plum
|
|
257
|
-
plum
|
|
253
|
+
plum run-test # run all tests
|
|
254
|
+
plum run-test @test-login-1 # run a single scenario
|
|
255
|
+
plum run-test @suite-login # run an entire suite
|
|
256
|
+
plum run-test --parallel 4 # run all tests across 4 workers
|
|
257
|
+
plum run-test --parallel 4 @suite-login # run a suite in parallel
|
|
258
|
+
plum run-test --browser firefox # run in a specific browser
|
|
258
259
|
```
|
|
259
260
|
|
|
260
|
-
|
|
261
|
+
| Flag | Description |
|
|
262
|
+
| ------------------ | -------------------------------------------- |
|
|
263
|
+
| `@tag` | Run only tests matching the tag |
|
|
264
|
+
| `--parallel <n>` | Run across `n` parallel workers |
|
|
265
|
+
| `--browser <name>` | `chromium` (default), `firefox`, or `webkit` |
|
|
266
|
+
|
|
267
|
+
> `plum run-test` syncs your tests, installs dependencies, and runs Cucumber. No Docker needed.
|
|
261
268
|
|
|
262
269
|
---
|
|
263
270
|
|
|
@@ -304,9 +311,10 @@ plum node stop
|
|
|
304
311
|
| `plum init` | Initialize a new project in the current folder |
|
|
305
312
|
| `plum server start` | Start the full UI stack via Docker (alias: `plum start`) |
|
|
306
313
|
| `plum server stop` | Stop the server and preserve data (alias: `plum stop`) |
|
|
307
|
-
| `plum
|
|
308
|
-
| `plum
|
|
309
|
-
| `plum
|
|
314
|
+
| `plum run-test` | Run all tests locally without Docker |
|
|
315
|
+
| `plum run-test @tag` | Run tests matching a tag |
|
|
316
|
+
| `plum run-test --parallel N` | Run tests across N parallel workers |
|
|
317
|
+
| `plum run-test --browser <b>` | Run in a specific browser (chromium/firefox/webkit) |
|
|
310
318
|
| `plum create-step` | Interactively scaffold a new step definition |
|
|
311
319
|
| `plum node start --token <t>` | Start a runner node on this machine |
|
|
312
320
|
| `plum node stop` | Stop the runner node |
|
|
@@ -25,6 +25,8 @@ const runners = parallel || process.env.REPORT_RUNNERS || '1';
|
|
|
25
25
|
const tag = process.env.TAG || process.argv.slice(2).find((a) => a.startsWith('@'));
|
|
26
26
|
const browser = process.env.BROWSER || 'chromium';
|
|
27
27
|
|
|
28
|
+
let testExitCode = 0;
|
|
29
|
+
|
|
28
30
|
try {
|
|
29
31
|
const testsRoot = (process.env.TESTS_ROOT || 'tests').replace(/\\/g, '/');
|
|
30
32
|
|
|
@@ -56,6 +58,8 @@ try {
|
|
|
56
58
|
const cucumberCommand = baseCommand.join(' ');
|
|
57
59
|
execSync(cucumberCommand, { stdio: 'inherit' });
|
|
58
60
|
} catch (error) {
|
|
61
|
+
// Cucumber exits non-zero when scenarios fail — preserve it so callers see the real result.
|
|
62
|
+
testExitCode = error.status ?? 1;
|
|
59
63
|
console.error(pc.red('✗') + ' Tests failed: ' + error.message);
|
|
60
64
|
} finally {
|
|
61
65
|
try {
|
|
@@ -67,3 +71,5 @@ try {
|
|
|
67
71
|
console.error(pc.red('✗') + ' Report generation failed: ' + error.message);
|
|
68
72
|
}
|
|
69
73
|
}
|
|
74
|
+
|
|
75
|
+
process.exit(testExitCode);
|
package/backend/package.json
CHANGED
package/bin/plum.js
CHANGED
|
@@ -100,7 +100,7 @@ function installPlugins() {
|
|
|
100
100
|
// Ensure user's .gitignore contains Plum-generated entries
|
|
101
101
|
function ensureGitignore() {
|
|
102
102
|
const gitignorePath = path.join(process.cwd(), '.gitignore');
|
|
103
|
-
const plumEntries = ['reports/'];
|
|
103
|
+
const plumEntries = ['.env', 'reports/'];
|
|
104
104
|
const plumBlock = `\n# Plum (auto-generated)\n${plumEntries.join('\n')}\n`;
|
|
105
105
|
|
|
106
106
|
if (!fs.existsSync(gitignorePath)) {
|
|
@@ -251,7 +251,7 @@ switch (command) {
|
|
|
251
251
|
"1. **Open `.env`** and set `BASE_URL` to your application's URL.",
|
|
252
252
|
'2. **Run the example tests** to confirm everything works:',
|
|
253
253
|
' ```bash',
|
|
254
|
-
' plum
|
|
254
|
+
' plum run-test',
|
|
255
255
|
' ```',
|
|
256
256
|
'3. **Write your first test** — edit a file in `tests/features/` or generate a step:',
|
|
257
257
|
' ```bash',
|
|
@@ -269,9 +269,10 @@ switch (command) {
|
|
|
269
269
|
'',
|
|
270
270
|
'| Command | Description |',
|
|
271
271
|
'| --- | --- |',
|
|
272
|
-
'| `plum
|
|
273
|
-
'| `plum
|
|
274
|
-
'| `plum
|
|
272
|
+
'| `plum run-test` | Run all tests locally |',
|
|
273
|
+
'| `plum run-test @tag` | Run tests matching a tag |',
|
|
274
|
+
'| `plum run-test --parallel N` | Run tests across N parallel workers |',
|
|
275
|
+
'| `plum run-test --browser firefox` | Run in a specific browser (chromium/firefox/webkit) |',
|
|
275
276
|
'| `plum start` | Start the full UI via Docker |',
|
|
276
277
|
'| `plum stop` | Stop the server |',
|
|
277
278
|
'| `plum create-step` | Interactively generate a new step definition |',
|
|
@@ -311,8 +312,8 @@ switch (command) {
|
|
|
311
312
|
'```',
|
|
312
313
|
'',
|
|
313
314
|
'```bash',
|
|
314
|
-
'plum
|
|
315
|
-
'plum
|
|
315
|
+
'plum run-test @test-login-1 # run a single scenario',
|
|
316
|
+
'plum run-test @suite-login # run the whole suite',
|
|
316
317
|
'```',
|
|
317
318
|
'',
|
|
318
319
|
'---',
|
|
@@ -342,7 +343,7 @@ switch (command) {
|
|
|
342
343
|
});
|
|
343
344
|
|
|
344
345
|
console.log(
|
|
345
|
-
'🟣 Plum is now ready!\n\n Scaffold test cases are in `tests/`.\n Add extra npm packages to `plum.plugins.json`.\n\n - Run tests locally:\n `plum
|
|
346
|
+
'🟣 Plum is now ready!\n\n Scaffold test cases are in `tests/`.\n Add extra npm packages to `plum.plugins.json`.\n\n - Run tests locally:\n `plum run-test` or `plum run-test @tag`\n\n - Start the full UI (requires Docker):\n `plum start`\n\n - Generate a step:\n `plum create-step`'
|
|
346
347
|
);
|
|
347
348
|
console.log('--------------------------------------\n');
|
|
348
349
|
break;
|
|
@@ -412,20 +413,30 @@ switch (command) {
|
|
|
412
413
|
console.log('--------------------------------------\n');
|
|
413
414
|
break;
|
|
414
415
|
|
|
415
|
-
case '
|
|
416
|
+
case 'run-test': {
|
|
416
417
|
console.log('--------------------------------------\n');
|
|
417
|
-
console.log('🚀 Running
|
|
418
|
+
console.log('🚀 Running tests locally...');
|
|
418
419
|
|
|
419
420
|
// Copy .env file from root to backend
|
|
420
421
|
copyEnvFile();
|
|
421
422
|
|
|
422
|
-
const
|
|
423
|
-
const parallelIdx =
|
|
424
|
-
const parallelArg = parallelIdx !== -1 ?
|
|
425
|
-
const
|
|
423
|
+
const runArgs = process.argv.slice(3);
|
|
424
|
+
const parallelIdx = runArgs.indexOf('--parallel');
|
|
425
|
+
const parallelArg = parallelIdx !== -1 ? runArgs[parallelIdx + 1] : null;
|
|
426
|
+
const browserIdx = runArgs.indexOf('--browser');
|
|
427
|
+
const browserArg = browserIdx !== -1 ? runArgs[browserIdx + 1] : null;
|
|
428
|
+
const tagArg = runArgs.find((a) => a.startsWith('@')) ?? null;
|
|
426
429
|
const userTestsPath = path.resolve(process.cwd(), 'tests');
|
|
427
430
|
const backendTestsPath = path.join(plumRoot, 'backend', 'tests');
|
|
428
431
|
|
|
432
|
+
const validBrowsers = ['chromium', 'firefox', 'webkit'];
|
|
433
|
+
if (browserArg && !validBrowsers.includes(browserArg)) {
|
|
434
|
+
console.error(
|
|
435
|
+
`✗ Invalid browser "${browserArg}". Choose one of: ${validBrowsers.join(', ')}`
|
|
436
|
+
);
|
|
437
|
+
process.exit(1);
|
|
438
|
+
}
|
|
439
|
+
|
|
429
440
|
// Copy user tests into backend
|
|
430
441
|
if (fs.existsSync(userTestsPath)) {
|
|
431
442
|
console.log('📦 Syncing your tests...\n');
|
|
@@ -458,6 +469,7 @@ switch (command) {
|
|
|
458
469
|
console.log('Running `npm run test` with:');
|
|
459
470
|
console.log('TAG =', tagArg ?? '');
|
|
460
471
|
console.log('PARALLEL =', parallelArg ?? 'off');
|
|
472
|
+
console.log('BROWSER =', browserArg ?? 'chromium');
|
|
461
473
|
console.log('TRIGGER =', 'command-line-trigger');
|
|
462
474
|
|
|
463
475
|
execSync('npm run test', {
|
|
@@ -467,7 +479,8 @@ switch (command) {
|
|
|
467
479
|
...process.env,
|
|
468
480
|
TAG: tagArg ?? '',
|
|
469
481
|
TRIGGER: 'command-line-trigger',
|
|
470
|
-
...(parallelArg ? { PARALLEL: parallelArg } : {})
|
|
482
|
+
...(parallelArg ? { PARALLEL: parallelArg } : {}),
|
|
483
|
+
...(browserArg ? { BROWSER: browserArg } : {})
|
|
471
484
|
}
|
|
472
485
|
});
|
|
473
486
|
console.log('--------------------------------------\n');
|
|
@@ -566,7 +579,10 @@ switch (command) {
|
|
|
566
579
|
console.log(' --token <secret> Auth token the primary must send');
|
|
567
580
|
console.log(' --primary <url> URL of the primary Plum server');
|
|
568
581
|
console.log(' node stop Stop the runner node');
|
|
569
|
-
console.log('
|
|
582
|
+
console.log(' run-test Run tests locally without Docker');
|
|
583
|
+
console.log(' @tag Run only tests matching a tag');
|
|
584
|
+
console.log(' --parallel <n> Run across n parallel workers');
|
|
585
|
+
console.log(' --browser <name> chromium | firefox | webkit (default: chromium)');
|
|
570
586
|
console.log(' create-step Interactively scaffold a new step definition');
|
|
571
587
|
console.log('\n--------------------------------------\n');
|
|
572
588
|
}
|
package/frontend/package.json
CHANGED
|
@@ -56,6 +56,14 @@
|
|
|
56
56
|
return scenario.tags.find((tag) => /^@test[\w-]*/i.test(tag));
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
function featureSuiteTag(feature) {
|
|
60
|
+
for (const scenario of feature.scenarios) {
|
|
61
|
+
const suiteTag = scenario.tags.find((tag) => /suite/i.test(tag));
|
|
62
|
+
if (suiteTag) return suiteTag;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
59
67
|
function visibleTags(scenario) {
|
|
60
68
|
const testTag = scenarioTestTag(scenario);
|
|
61
69
|
if (testTag) return [testTag];
|
|
@@ -349,6 +357,9 @@
|
|
|
349
357
|
<polyline points="14 2 14 8 20 8" />
|
|
350
358
|
</svg>
|
|
351
359
|
{feature.name}
|
|
360
|
+
{#if featureSuiteTag(feature)}
|
|
361
|
+
<span class="suite-tag">{featureSuiteTag(feature)}</span>
|
|
362
|
+
{/if}
|
|
352
363
|
</h2>
|
|
353
364
|
<div class="feature-right">
|
|
354
365
|
<span class="feature-file">{feature.uri}</span>
|
|
@@ -687,6 +698,16 @@
|
|
|
687
698
|
color: var(--text-muted);
|
|
688
699
|
}
|
|
689
700
|
|
|
701
|
+
.suite-tag {
|
|
702
|
+
font-size: 0.65rem;
|
|
703
|
+
font-family: 'JetBrains Mono', monospace;
|
|
704
|
+
background: var(--accent-soft);
|
|
705
|
+
color: var(--accent);
|
|
706
|
+
padding: 0.1rem 0.4rem;
|
|
707
|
+
border-radius: 100px;
|
|
708
|
+
font-weight: 500;
|
|
709
|
+
}
|
|
710
|
+
|
|
690
711
|
.scenarios {
|
|
691
712
|
display: flex;
|
|
692
713
|
flex-direction: column;
|