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 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 dev` to run tests directly on your machine without Docker:
250
+ Use `plum run-test` to run tests directly on your machine without Docker:
251
251
 
252
252
  ```bash
253
- plum dev # run all tests
254
- plum dev @test-login-1 # run a single scenario
255
- plum dev @suite-login # run an entire suite
256
- plum dev --parallel 4 # run all tests across 4 workers
257
- plum dev --parallel 4 @suite-login # run a suite in parallel
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
- > `plum dev` syncs your tests, installs dependencies, and runs Cucumber. No Docker needed.
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 dev` | Run all tests locally without Docker |
308
- | `plum dev @tag` | Run tests matching a tag |
309
- | `plum dev --parallel N` | Run tests across N parallel workers |
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);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plum-backend",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "init": "node services/envService.js",
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 dev',
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 dev` | Run all tests locally |',
273
- '| `plum dev @tag` | Run tests matching a tag |',
274
- '| `plum dev --parallel N` | Run tests across N parallel workers |',
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 dev @test-login-1 # run a single scenario',
315
- 'plum dev @suite-login # run the whole suite',
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 dev` or `plum dev @tag`\n\n - Start the full UI (requires Docker):\n `plum start`\n\n - Generate a step:\n `plum create-step`'
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 'dev': {
416
+ case 'run-test': {
416
417
  console.log('--------------------------------------\n');
417
- console.log('🚀 Running Plum in Development Mode...');
418
+ console.log('🚀 Running tests locally...');
418
419
 
419
420
  // Copy .env file from root to backend
420
421
  copyEnvFile();
421
422
 
422
- const devArgs = process.argv.slice(3);
423
- const parallelIdx = devArgs.indexOf('--parallel');
424
- const parallelArg = parallelIdx !== -1 ? devArgs[parallelIdx + 1] : null;
425
- const tagArg = devArgs.find((a) => a.startsWith('@')) ?? null;
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(' dev Run tests locally without Docker');
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
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "plum-frontend",
3
3
  "private": true,
4
- "version": "1.3.0",
4
+ "version": "1.3.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite dev",
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plum-e2e",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/silverlunah/plum.git"