plum-e2e 2.1.0 → 2.3.0

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.
Files changed (31) hide show
  1. package/README.md +61 -470
  2. package/backend/lib/runnerProcess.js +50 -4
  3. package/backend/logs/runner-cmqneqerz0000qq01i5ap2rvl.log +22 -0
  4. package/backend/logs/runner-cmqnfv7kr0000r101aeocm8eu.log +20 -0
  5. package/backend/logs/runner-cmqnfvb560001r101qoi0phau.log +43 -0
  6. package/backend/logs/runner-cmqnfvlm20002r101gsyqb837.log +20 -0
  7. package/backend/logs/runner-cmqnfvqfy0003r101fh41pzx3.log +20 -0
  8. package/backend/logs/runner-cmqnfvvwo0004r101q4dtqxd2.log +20 -0
  9. package/backend/package.json +1 -0
  10. package/backend/prisma/migrations/20260621000000_add_notifications/migration.sql +8 -0
  11. package/backend/prisma/migrations/20260621000001_add_backup_config/migration.sql +11 -0
  12. package/backend/prisma/schema.prisma +22 -7
  13. package/backend/routes/backup.routes.js +70 -5
  14. package/backend/routes/node.routes.js +9 -0
  15. package/backend/routes/runners.routes.js +10 -0
  16. package/backend/routes/settings.routes.js +27 -0
  17. package/backend/scripts/manage-runners.mjs +49 -8
  18. package/backend/server.js +25 -1
  19. package/backend/services/backupCronService.js +82 -0
  20. package/backend/services/backupService.js +254 -27
  21. package/backend/services/cronService.js +91 -7
  22. package/backend/services/notificationService.js +163 -0
  23. package/backend/services/settingsService.js +74 -1
  24. package/backend/websockets/socketHandler.js +82 -6
  25. package/frontend/src/lib/api/schedules.js +5 -1
  26. package/frontend/src/lib/api/settings.js +56 -0
  27. package/frontend/src/lib/components/layout/RunnerPanel.svelte +79 -3
  28. package/frontend/src/lib/stores/runner.js +4 -2
  29. package/frontend/src/routes/scheduled-tests/+page.svelte +65 -7
  30. package/frontend/src/routes/settings/+page.svelte +472 -9
  31. package/package.json +1 -1
package/README.md CHANGED
@@ -3,12 +3,12 @@
3
3
  <p align="center">
4
4
  <a href="https://www.npmjs.com/package/plum-e2e"><img src="https://img.shields.io/npm/v/plum-e2e?color=7c3aed&label=plum-e2e" alt="npm version" /></a>
5
5
  <a href="https://github.com/silverlunah/plum/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-GPL--3.0-blue" alt="license" /></a>
6
- <a href="https://github.com/silverlunah/plum/wiki"><img src="https://img.shields.io/badge/docs-wiki-informational" alt="docs" /></a>
6
+ <a href="https://outline.silverlunah.com/collection/plum-XRoE2MURWj"><img src="https://img.shields.io/badge/docs-outline-7c3aed" alt="docs" /></a>
7
7
  </p>
8
8
 
9
9
  <p align="center">
10
10
  A ready-to-use E2E test automation environment built on <a href="https://playwright.dev">Playwright</a> + <a href="https://cucumber.io">Cucumber</a>.<br/>
11
- Write tests in Gherkin, run them from the CLI or UI, view reports, and manage your entire test case repository — all in one place.
11
+ Write tests in Gherkin, run them from the CLI or UI, view reports, schedule jobs, manage your entire test case repository, and get notified on Discord or Slack — all in one place.
12
12
  </p>
13
13
 
14
14
  ---
@@ -20,461 +20,85 @@
20
20
 
21
21
  ---
22
22
 
23
- ## 1. Installation
23
+ ## Quick Start
24
24
 
25
- ### Install Plum globally
25
+ ### For users
26
26
 
27
27
  ```bash
28
+ # 1. Install Plum globally
28
29
  npm install -g plum-e2e
29
- ```
30
-
31
- > The `-g` flag is required. Plum is a CLI tool — it must be installed globally to use `plum` commands anywhere on your machine.
32
-
33
- ### Initialize a new project
34
-
35
- Create a folder for your tests and run `plum init` inside it:
36
30
 
37
- ```bash
38
- mkdir my-tests
39
- cd my-tests
31
+ # 2. Create a project folder and initialize it
32
+ mkdir my-tests && cd my-tests
40
33
  plum init
41
- ```
42
-
43
- This sets up your project with a working test scaffold:
44
-
45
- ```
46
- my-tests/
47
- ├── tests/
48
- │ ├── features/ — Gherkin .feature files (your test cases)
49
- │ ├── step_definitions/ — TypeScript step implementations
50
- │ ├── pages/ — Page Object Models
51
- │ └── utils/ — Browser setup, hooks, shared helpers
52
- ├── .env — Base URL and browser settings
53
- ├── .gitignore — Pre-configured to exclude .env and reports/
54
- ├── plum.plugins.json — Add extra npm packages for your tests
55
- └── tsconfig.json — IDE type resolution (no local install needed)
56
- ```
57
-
58
- The `tests/` folder includes working example tests against [SauceDemo](https://www.saucedemo.com/v1/) so you can run something immediately.
59
-
60
- ### Configure your target URL
61
-
62
- Open `.env` and set your application's URL:
63
34
 
64
- ```env
65
- BASE_URL=https://your-app.com
66
- IS_HEADLESS=false
67
- ```
68
-
69
- | Variable | Description |
70
- | ------------- | ---------------------------------------------------- |
71
- | `BASE_URL` | The URL Playwright opens at the start of tests |
72
- | `IS_HEADLESS` | `true` to run headlessly, `false` to see the browser |
35
+ # 3. Set your app URL
36
+ # Edit .env → BASE_URL=https://your-app.com
73
37
 
74
- ### Add extra packages (optional)
38
+ # 4. Run the example tests locally (no server needed)
39
+ plum run-test
75
40
 
76
- If your tests need additional npm packages, add them to `plum.plugins.json`:
77
-
78
- ```json
79
- {
80
- "dependencies": {
81
- "@faker-js/faker": "^9.0.0"
82
- }
83
- }
84
- ```
85
-
86
- Plum installs these automatically before each run. Commit this file so your whole team uses the same packages.
87
-
88
- ---
89
-
90
- ## 2. Starting the Server
91
-
92
- Plum includes a full web UI for triggering tests, viewing reports, and scheduling runs.
93
-
94
- ### Start
95
-
96
- ```bash
41
+ # 5. Start the web UI (requires Docker)
97
42
  plum server start
98
43
  ```
99
44
 
100
- or the shorthand:
101
-
102
- ```bash
103
- plum start
104
- ```
105
-
106
- The first time you run it, Plum asks a few questions (press Enter to accept the default shown in parentheses):
107
-
108
- | Prompt | Default | What it sets |
109
- | ---------------------- | ------------------------- | ----------------------------------------------------------------------- |
110
- | **App URL (BASE_URL)** | from your `.env` | The URL Playwright opens at the start of every test |
111
- | **Headless?** | `No` | Whether browsers run hidden |
112
- | **Backend port** | `3001` | Host port for the API |
113
- | **Frontend (UI) port** | `5173` | Host port for the web UI |
114
- | **Primary public URL** | `http://<your-ip>:<port>` | The address you give runner nodes (see [Runner Setup](#4-runner-setup)) |
115
-
116
- Your answers are saved to `.plum-server.json`, so the next `plum server start` reuses them without asking.
117
-
118
- ### First-user setup
119
-
120
- On the very first start, Plum detects that no user accounts exist and prompts you to create one:
121
-
122
- ```
123
- No users found — create your first account to get started.
124
- ✔ Your name … Jane Smith
125
- ✔ Email address … jane@example.com
126
- ✔ Password …
127
- ✓ Account created for jane@example.com. You can now log in.
128
- ```
129
-
130
- After that, open the UI at the frontend port it prints (default **http://localhost:5173**) and sign in. Additional users can be invited from **Settings → Account** or the **Settings → Users** page.
131
-
132
- > If you skip the CLI prompt, visit `http://localhost:5173/setup` in your browser to create the first account.
133
-
134
- > Docker must be running before you use this command. Plum builds and starts the backend, database, and UI automatically.
135
-
136
- **Skip the prompts** by passing flags (handy for CI):
137
-
138
- ```bash
139
- plum server start --base-url https://your-app.com --headless true --backend-port 3001 --frontend-port 5173
140
- ```
141
-
142
- ### Change settings later
143
-
144
- ```bash
145
- plum server reconfig
146
- ```
147
-
148
- Re-asks every question and saves your answers **without** starting the stack. Run `plum server start` afterwards to apply them.
149
-
150
- ### Stop
151
-
152
- ```bash
153
- plum server stop
154
- ```
155
-
156
- or the shorthand:
157
-
158
- ```bash
159
- plum stop
160
- ```
161
-
162
- > Your data (reports, schedules, settings) is preserved in the database volume. Only the running containers are stopped.
163
-
164
- ---
165
-
166
- ## 3. Writing Tests
167
-
168
- Plum uses [Cucumber](https://cucumber.io) and [Gherkin](https://cucumber.io/docs/gherkin/) to write human-readable test cases.
169
-
170
- ### Cucumber Basics
171
-
172
- Gherkin is a plain-English language for writing test scenarios. Each test lives in a `.feature` file and follows this structure:
173
-
174
- ```gherkin
175
- @suite-login
176
- Feature: Login
177
-
178
- @test-login-1
179
- Scenario: User can log in with valid credentials
180
- Given I am on the login page
181
- When I enter valid credentials
182
- Then I should see the dashboard
183
- ```
184
-
185
- **Key concepts:**
186
-
187
- | Term | What it is |
188
- | ------------------ | ---------------------------------------------------------------------- |
189
- | `Feature` | A group of related scenarios (one per file) |
190
- | `Scenario` | A single test case |
191
- | `Given` | Sets up the initial state |
192
- | `When` | Performs an action |
193
- | `Then` | Asserts the expected outcome |
194
- | `Background` | Steps that run before every scenario in a file |
195
- | `Scenario Outline` | A parameterized scenario that runs once per row in an `Examples` table |
196
- | `@tag` | A label used to run specific tests or suites |
197
-
198
- **Useful links:**
199
-
200
- - [Gherkin syntax reference](https://cucumber.io/docs/gherkin/reference/)
201
- - [Cucumber step definitions](https://cucumber.io/docs/cucumber/step-definitions/)
202
- - [Playwright documentation](https://playwright.dev/docs/intro)
203
-
204
- ---
205
-
206
- ### Project Structure
207
-
208
- Tests follow a three-layer structure: **Feature → Step Definition → Page Object**.
209
-
210
- #### Feature File — what to test
211
-
212
- ```gherkin
213
- # tests/features/Login.feature
214
-
215
- @suite-login
216
- Feature: Login
217
-
218
- @test-login-1
219
- Scenario: User can log in with valid credentials
220
- Given I am on the login page
221
- When I enter valid credentials
222
- Then I should see the dashboard
223
- ```
224
-
225
- Tags (`@suite-login`, `@test-login-1`) let you run specific tests or entire suites. Every suite and scenario should have its own tag.
226
-
227
- #### Page Object — how to interact with the page
228
-
229
- ```typescript
230
- // tests/pages/LoginPage.ts
231
-
232
- import { page } from '../utils/browser';
233
-
234
- export class LoginPage {
235
- static async goToLoginPage() {
236
- await page().goto(process.env.BASE_URL as string);
237
- }
238
-
239
- static async enterCredentials(username: string, password: string) {
240
- await page().fill('#username', username);
241
- await page().fill('#password', password);
242
- await page().click('button[type="submit"]');
243
- }
244
-
245
- static async verifyDashboardVisible() {
246
- await page().waitForSelector('#dashboard');
247
- }
248
- }
249
- ```
250
-
251
- Methods are `static` and use the `page()` helper from `utils/browser.ts` — you never pass a page instance around.
252
-
253
- #### Step Definition — connects Gherkin to code
254
-
255
- ```typescript
256
- // tests/step_definitions/LoginSteps.ts
257
-
258
- import { Given, When, Then } from '@cucumber/cucumber';
259
- import { LoginPage } from '../pages/LoginPage';
260
-
261
- Given('I am on the login page', async () => {
262
- await LoginPage.goToLoginPage();
263
- });
264
-
265
- When('I enter valid credentials', async () => {
266
- await LoginPage.enterCredentials('user@example.com', 'password123');
267
- });
268
-
269
- Then('I should see the dashboard', async () => {
270
- await LoginPage.verifyDashboardVisible();
271
- });
272
- ```
273
-
274
- ---
275
-
276
- ### Generate a Step
277
-
278
- Use `plum create-step` to interactively scaffold a new step definition and page object method:
279
-
280
- ```bash
281
- plum create-step
282
- ```
283
-
284
- Follow the prompts — Plum writes the boilerplate, you fill in the implementation.
285
-
286
- ---
287
-
288
- ### Run Tests Locally
45
+ Open **http://localhost:5173** and sign in with the account you create on first start.
289
46
 
290
- Use `plum run-test` to run tests directly on your machine without Docker:
47
+ ### For contributors
291
48
 
292
49
  ```bash
293
- plum run-test # run all tests
294
- plum run-test @test-login-1 # run a single scenario
295
- plum run-test @suite-login # run an entire suite
296
- plum run-test --parallel 4 # run all tests across 4 workers
297
- plum run-test --parallel 4 @suite-login # run a suite in parallel
298
- plum run-test --browser firefox # run in a specific browser
299
- ```
300
-
301
- | Flag | Description |
302
- | ------------------ | --------------------------------- |
303
- | `@tag` | Run only tests matching the tag |
304
- | `--parallel <n>` | Run across `n` parallel workers |
305
- | `--browser <name>` | `chromium` (default) or `firefox` |
306
-
307
- > `plum run-test` syncs your tests, installs dependencies, and runs Cucumber. No Docker needed.
308
-
309
- ---
310
-
311
- ## 4. Test Repository
312
-
313
- Plum includes a built-in test case management system accessible from the **Test Repository** tab in the UI.
314
-
315
- ### Test Suites and Cases
316
-
317
- Organise test cases into **suites**. Each suite and case gets an auto-assigned ID (e.g. `TS-001`, `TC-001`). The prefix is configurable in **Settings → Repository**.
318
-
319
- Each test case has:
320
-
321
- - **Title** and **Description**
322
- - **Priority** — Critical, High, Medium, or Low
323
- - **Test Steps** — an ordered table with columns: Action, Test Data, Expected Output
324
- - **Automated tag** — a Cucumber `@tag` name that links this case to an automated scenario (e.g. `test-login-1`)
325
- - **History** — a timeline of every result, from manual test runs and automated builds
326
-
327
- ### Linking automated tests
328
-
329
- Set the **Automated tag** on a test case to match a Cucumber `@tag` in your feature files. After every automated run, Plum scans the results and:
330
-
331
- 1. Marks matching cases as **automated**
332
- 2. Records a pass/fail entry in the case's history
333
-
334
- ```gherkin
335
- @test-login-1
336
- Scenario: User can log in with valid credentials
50
+ git clone https://github.com/silverlunah/plum.git
51
+ cd plum
52
+ npm run init # installs all monorepo dependencies
53
+ npm run docker:up # builds and starts the full stack
337
54
  ```
338
55
 
339
- If `TC-042` has `automatedTag = test-login-1`, it will be marked automated and updated after each buildno manual linking required.
340
-
341
- ### Test Runs
342
-
343
- Create a **Test Run** (e.g. "Sprint 12 regression") and drag test cases from the suite browser into the run. Then switch to **Execute** mode to step through each case and mark it pass / fail / blocked / skip.
344
-
345
- Results are recorded in the case's history and the run's progress bar updates in real time.
346
-
347
- ### Migrating IDs
348
-
349
- If you change the test ID prefix (e.g. from `TC` to `CASE`), use **Settings → Repository → Run Migration** to rename all existing IDs at once. Cucumber tags in your code are intentionally left unchanged — update those separately.
56
+ The UI is available at **http://localhost:5173**. The frontend dev server runs outside Docker for fast HMRsee the **Development** section below.
350
57
 
351
58
  ---
352
59
 
353
- ## 5. Runner Setup
354
-
355
- Runners are additional machines that execute tests in parallel alongside the primary server, letting you distribute a large suite across many nodes. A node runs as a plain Node process — **no Docker required**.
356
-
357
- Each node automatically installs **Chromium and Firefox** — no browser selection needed. When triggering a test run from the UI, you choose which browser to use at run time.
358
-
359
- ### Start a runner node
360
-
361
- On the machine that will act as a runner, navigate to your Plum project and run:
362
-
363
- ```bash
364
- plum node start
365
- ```
366
-
367
- Plum asks a few questions, **registers the node with your server automatically**, starts it in the background, then opens the runner management menu:
368
-
369
- | Prompt | Default | What it sets |
370
- | ------------------ | ------------------------- | -------------------------------------------------------------------- |
371
- | **Primary URL** | last used | The server this node registers with (e.g. `http://192.168.1.5:3001`) |
372
- | **Local port** | `3001` | The port this node process listens on |
373
- | **Advertised URL** | `http://<your-ip>:<port>` | The address the **server** uses to reach this node |
374
- | **Runner name** | `node-<random>` | The name shown in the UI |
375
- | **Auth token** | auto-generated | Shared secret; press Enter to keep the generated one |
376
-
377
- The node starts as a **background daemon** — your terminal is free immediately. Logs go to `backend/logs/runner-<id>.log`. Settings are saved to `.plum-node.json`, so re-running reuses them and never creates a duplicate.
378
-
379
- After setup, the **runner management menu** opens automatically. From there you can start, stop, restart, and ping any runner registered on the primary. Exit the menu any time — the node keeps running.
380
-
381
- **Skip the prompts** with flags (handy for CI or scripted nodes):
382
-
383
- ```bash
384
- plum node start --primary http://192.168.1.5:3001 --port 3001 --name ci-node-1
385
- ```
386
-
387
- | Flag | Description |
388
- | ------------------ | ---------------------------------------------------------------------------------------- |
389
- | `--primary <url>` | Server to auto-register with. Omit to only print the details for manual entry. |
390
- | `--url <url>` | Address the server calls back. Defaults to `<lan-ip>:<port>`; pass a domain to override. |
391
- | `--port <n>` | Local HTTP port the node listens on (default `3001`). |
392
- | `--token <secret>` | Auth token. Auto-generated and saved if omitted. |
393
- | `--name <name>` | Runner name shown in the UI. |
394
-
395
- #### Nodes behind a domain or reverse proxy
396
-
397
- `--url` is the address the **server** calls back and is used exactly as given, while `--port` is the local port the node listens on. So a node behind an HTTPS reverse proxy is:
398
-
399
- ```bash
400
- plum node start --primary https://plum.example.com --url https://node1.example.com --port 3001
401
- ```
402
-
403
- The server reaches the node at `https://node1.example.com`; the proxy forwards to the node on port `3001`. The advertised `--url` must be reachable from the server.
404
-
405
- ### Manage runners
406
-
407
- ```bash
408
- plum manage-runners
409
- ```
410
-
411
- Opens the interactive runner management menu at any time (reads the primary URL from your saved node config). You can also pass a different server:
412
-
413
- ```bash
414
- plum manage-runners --primary http://192.168.1.5:3001
415
- ```
416
-
417
- > In development, the equivalent command is `npm run manage-runners` from the `backend/` directory.
418
-
419
- ### Change settings later
420
-
421
- ```bash
422
- plum node reconfig
423
- ```
424
-
425
- Re-asks every question, re-registers with the primary, and prints the updated card — **without** starting the node. Run `plum node start` afterwards to launch it.
426
-
427
- ### Register manually (fallback)
428
-
429
- If you run `plum node start` without a reachable `--primary`, Plum prints the node's **name, url, and token** instead. Add it by hand:
60
+ ## Documentation
430
61
 
431
- 1. Open the Plum UI at **http://localhost:5173**
432
- 2. Go to **Settings → Runners**
433
- 3. Click **Add Runner** and paste the node's URL, token, and name
62
+ Full documentation is available at:
434
63
 
435
- ### Stop a runner node
64
+ **[https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd)**
436
65
 
437
- ```bash
438
- plum node stop
439
- ```
440
-
441
- Stops the node started from the current folder. You can also stop individual runners from the `plum manage-runners` menu.
66
+ | Guide | What it covers |
67
+ | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------- |
68
+ | [Installation](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd/doc/installation-JftwFX9csC) | Requirements, global install, first-user setup, plugins |
69
+ | [Initializing the Project](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd/doc/initializing-the-project-ilfc8LUyO7) | What `plum init` generates, config files explained |
70
+ | [Writing Tests](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd/doc/writing-tests-XeHJQdtH49) | Feature files, page objects, step definitions, best practices |
71
+ | [Running Tests Locally](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd/doc/running-tests-locally-GGhFcqaAQ8) | `plum run-test` flags, parallel runs, debugging tips |
72
+ | [Setting Up the Server](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd/doc/setting-up-the-server-vj0Ab1kJVs) | Production server setup, reverse proxy (Nginx/Caddy), Docker |
73
+ | [Setting Up Nodes](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd/doc/setting-up-nodes-dtmekJGJia) | Runner nodes, systemd service, managing nodes |
74
+ | [Integrations](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd/doc/integrations-qfiqfmdP0j) | Discord & Slack webhook notifications |
75
+ | [Backup](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd/doc/backup-RNNObJfct9) | Backup strategy |
442
76
 
443
77
  ---
444
78
 
445
79
  ## Command Reference
446
80
 
447
- | Command | Description |
448
- | ----------------------------- | ------------------------------------------------------------------------------ |
449
- | `plum init` | Initialize a new project in the current folder |
450
- | `plum server start` | Start the full UI stack via Docker, interactively (alias: `plum start`) |
451
- | `plum server reconfig` | Re-enter server settings (URL, ports) without starting |
452
- | `plum server stop` | Stop the server and preserve data (alias: `plum stop`) |
453
- | `plum run-test` | Run all tests locally without Docker |
454
- | `plum run-test @tag` | Run tests matching a tag |
455
- | `plum run-test --parallel N` | Run tests across N parallel workers |
456
- | `plum run-test --browser <b>` | Run in a specific browser (`chromium` or `firefox`) |
457
- | `plum create-step` | Interactively scaffold a new step definition |
458
- | `plum node start` | Configure, register, and start a runner node; opens the runner management menu |
459
- | `plum node reconfig` | Re-enter node settings + re-register, without starting |
460
- | `plum node stop` | Stop the runner node started from this folder |
461
- | `plum manage-runners` | Open the interactive runner management menu |
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 (alias: `plum start`) |
85
+ | `plum server stop` | Stop the server and preserve data (alias: `plum stop`) |
86
+ | `plum server reconfig` | Re-enter server settings without starting |
87
+ | `plum run-test` | Run all tests locally without Docker |
88
+ | `plum run-test @tag` | Run tests matching a tag |
89
+ | `plum run-test --parallel N` | Run tests across N parallel workers |
90
+ | `plum run-test --browser <b>` | Run in `chromium` (default) or `firefox` |
91
+ | `plum create-step` | Interactively scaffold a new step definition |
92
+ | `plum node start` | Configure, register, and start a runner node |
93
+ | `plum node stop` | Stop the runner node started from this folder |
94
+ | `plum node reconfig` | Re-enter node settings and re-register |
95
+ | `plum manage-runners` | Open the interactive runner management menu |
462
96
 
463
97
  ---
464
98
 
465
99
  ## Development
466
100
 
467
- > This section is for contributors developing Plum itself. If you're a user, the sections above are all you need.
468
-
469
- ### Clone and install
470
-
471
- ```bash
472
- git clone https://github.com/silverlunah/plum.git
473
- cd plum
474
- npm run init
475
- ```
476
-
477
- `npm run init` installs all dependencies across the monorepo (root, backend, and frontend) in one command.
101
+ > This section is for contributors developing Plum itself.
478
102
 
479
103
  ### Start the stack
480
104
 
@@ -483,51 +107,27 @@ npm run docker:up # build and start all services (detached)
483
107
  npm run docker:down # stop all services
484
108
  ```
485
109
 
486
- The UI will be available at **http://localhost:5173** after `docker:up` completes.
487
-
488
- > After any backend dependency or schema change, re-run `npm run docker:up` to rebuild the containers.
489
-
490
- ### Backend — writing and running tests
110
+ ### Frontend (hot reload)
491
111
 
492
- All test development happens inside the `backend/` directory, where the Playwright + Cucumber runner lives:
112
+ The frontend dev server runs outside Docker for fast HMR:
493
113
 
494
114
  ```bash
495
- cd backend
115
+ cd frontend
116
+ npm run dev # available at http://localhost:5173
496
117
  ```
497
118
 
498
- **Run tests:**
119
+ ### Backend — writing and running tests
499
120
 
500
121
  ```bash
122
+ cd backend
501
123
  npm test # run all tests
502
- npm test -- @test-1 # run a specific scenario by tag
503
- npm test -- @suite-login # run an entire suite
504
- npm test -- --parallel 4 # run all tests in parallel
505
- ```
506
-
507
- **Generate a step definition:**
508
-
509
- ```bash
510
- npm run create-step
511
- ```
512
-
513
- Interactive prompt that creates a new step and its page object method.
514
-
515
- **Scaffold a new test:**
516
-
517
- ```bash
518
- npm run create-test
124
+ npm test -- @test-1 # run a specific scenario
125
+ npm test -- --parallel 4 # run in parallel
126
+ npm run create-step # scaffold a step definition
127
+ npm run create-test # scaffold a full test from template
128
+ npm run manage-runners # open the runner management menu
519
129
  ```
520
130
 
521
- Interactive prompt that creates a new `.feature` file, page object, and step definition file from a template — ready for you to implement.
522
-
523
- **Manage runner nodes:**
524
-
525
- ```bash
526
- npm run manage-runners
527
- ```
528
-
529
- One interactive menu to **add** a new runner (registers it with the primary and optionally starts it), and to **start / stop / restart / ping** the local node processes it manages. In dev the primary runs in Docker and nodes run as bare host processes, reached via `host.docker.internal`. PIDs are tracked in `.runners.local.json` and logs go to `backend/logs/` so you can manage nodes across terminal sessions.
530
-
531
131
  ### Test file locations
532
132
 
533
133
  ```
@@ -538,20 +138,11 @@ backend/tests/
538
138
  utils/ — Browser setup, hooks, helpers
539
139
  ```
540
140
 
541
- ### Frontend
542
-
543
- The frontend dev server runs outside Docker for fast hot module replacement:
544
-
545
- ```bash
546
- cd frontend
547
- npm run dev
548
- ```
549
-
550
- Available at **http://localhost:5173**. The backend (via Docker) serves API requests at **http://localhost:3001**.
141
+ > After any backend dependency or schema change, rebuild: `npm run docker:up`
551
142
 
552
143
  ---
553
144
 
554
145
  <p align="center">
555
- Plum is free to use. If you'd like to show some love:<br/>
146
+ Plum is free and open source. If you'd like to show some love:<br/>
556
147
  <a href="https://www.paypal.me/silverlunah">PayPal</a> · <a href="https://wise.com/pay/me/janneserjosee">Wise</a>
557
148
  </p>