plum-e2e 2.2.0 → 2.4.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.
- package/README.md +61 -520
- package/backend/app.js +1 -0
- package/backend/constants/triggers.js +3 -1
- package/backend/lib/serverConfig.js +23 -14
- package/backend/mcp/server.js +385 -0
- package/backend/middleware/jwtAuth.js +18 -0
- package/backend/package-lock.json +1432 -28
- package/backend/package.json +4 -1
- package/backend/prisma/migrations/20260621000001_add_backup_config/migration.sql +11 -0
- package/backend/prisma/migrations/20260621000002_add_mcp_key/migration.sql +2 -0
- package/backend/prisma/schema.prisma +21 -10
- package/backend/routes/backup.routes.js +70 -5
- package/backend/routes/settings.routes.js +18 -0
- package/backend/routes/trigger.routes.js +94 -0
- package/backend/scripts/manage-runners.mjs +25 -4
- package/backend/server.js +11 -0
- package/backend/services/backupCronService.js +82 -0
- package/backend/services/backupService.js +254 -27
- package/backend/services/settingsService.js +65 -1
- package/bin/plum.js +18 -51
- package/frontend/src/lib/api/settings.js +61 -0
- package/frontend/src/lib/components/layout/Nav.svelte +0 -1
- package/frontend/src/routes/+layout.js +20 -0
- package/frontend/src/routes/+layout.svelte +24 -16
- package/frontend/src/routes/settings/+page.svelte +622 -9
- package/package.json +2 -2
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://
|
|
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,
|
|
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,511 +20,85 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Quick Start
|
|
24
24
|
|
|
25
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
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 |
|
|
73
|
-
|
|
74
|
-
### Add extra packages (optional)
|
|
75
|
-
|
|
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
34
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
## 2. Starting the Server
|
|
35
|
+
# 3. Set your app URL
|
|
36
|
+
# Edit .env → BASE_URL=https://your-app.com
|
|
91
37
|
|
|
92
|
-
|
|
38
|
+
# 4. Run the example tests locally (no server needed)
|
|
39
|
+
plum run-test
|
|
93
40
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
```bash
|
|
41
|
+
# 5. Start the web UI (requires Docker)
|
|
97
42
|
plum server start
|
|
98
43
|
```
|
|
99
44
|
|
|
100
|
-
|
|
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
|
-
|
|
47
|
+
### For contributors
|
|
291
48
|
|
|
292
49
|
```bash
|
|
293
|
-
|
|
294
|
-
plum
|
|
295
|
-
|
|
296
|
-
|
|
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
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
If `TC-042` has `automatedTag = test-login-1`, it will be marked automated and updated after each build — no 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.
|
|
350
|
-
|
|
351
|
-
---
|
|
352
|
-
|
|
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:
|
|
430
|
-
|
|
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
|
|
434
|
-
|
|
435
|
-
### Stop a runner node
|
|
436
|
-
|
|
437
|
-
```bash
|
|
438
|
-
plum node stop
|
|
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
|
|
439
54
|
```
|
|
440
55
|
|
|
441
|
-
|
|
56
|
+
The UI is available at **http://localhost:5173**. The frontend dev server runs outside Docker for fast HMR — see the **Development** section below.
|
|
442
57
|
|
|
443
58
|
---
|
|
444
59
|
|
|
445
|
-
##
|
|
446
|
-
|
|
447
|
-
Plum can post a pass/fail summary to a Discord channel or Slack workspace after every automated or manual test run. The notification includes the job name, overall result, scenario counts, browser, tags, and a link to the full report.
|
|
448
|
-
|
|
449
|
-
### Step 1 — Get a webhook URL
|
|
450
|
-
|
|
451
|
-
**Discord:**
|
|
452
|
-
|
|
453
|
-
1. Open your Discord server, right-click the target channel → **Edit Channel**
|
|
454
|
-
2. Go to **Integrations → Webhooks → New Webhook**
|
|
455
|
-
3. Copy the webhook URL
|
|
456
|
-
|
|
457
|
-
**Slack:**
|
|
458
|
-
|
|
459
|
-
1. Go to your workspace's [Slack App directory](https://api.slack.com/apps) → **Create New App → From scratch**
|
|
460
|
-
2. Under **Features**, choose **Incoming Webhooks** and activate them
|
|
461
|
-
3. Click **Add New Webhook to Workspace**, choose the channel, and copy the webhook URL
|
|
462
|
-
|
|
463
|
-
### Step 2 — Configure in Plum
|
|
60
|
+
## Documentation
|
|
464
61
|
|
|
465
|
-
|
|
466
|
-
2. Paste your webhook URL(s) into the **Discord Webhook URL** and/or **Slack Webhook URL** fields
|
|
467
|
-
3. Set **Public URL** to the base address of your Plum instance (e.g. `http://192.168.1.5:5173`). This is used to generate the "View Report" link in the notification. Leave it blank if you don't want report links included.
|
|
468
|
-
4. Click **Save Integrations**
|
|
62
|
+
Full documentation is available at:
|
|
469
63
|
|
|
470
|
-
|
|
64
|
+
**[https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd](https://outline.silverlunah.com/s/12bf21d1-02ba-49e9-b0df-908976407afd)**
|
|
471
65
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
### What the notification contains
|
|
483
|
-
|
|
484
|
-
| Field | Example |
|
|
485
|
-
| ----------- | ------------------------------------------------------------ |
|
|
486
|
-
| Job / Run | `nightly-login-suite` or `Manual Run` |
|
|
487
|
-
| Status | ✅ PASS or ❌ FAIL |
|
|
488
|
-
| Results | `42 / 45 passed` |
|
|
489
|
-
| Browser | `chromium` |
|
|
490
|
-
| Tags | `@suite-login` |
|
|
491
|
-
| Report link | Button / link to the full HTML report (if Public URL is set) |
|
|
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 |
|
|
492
76
|
|
|
493
77
|
---
|
|
494
78
|
|
|
495
79
|
## Command Reference
|
|
496
80
|
|
|
497
|
-
| Command | Description
|
|
498
|
-
| ----------------------------- |
|
|
499
|
-
| `plum init` | Initialize a new project in the current folder
|
|
500
|
-
| `plum server start` | Start the full UI stack via Docker
|
|
501
|
-
| `plum server
|
|
502
|
-
| `plum server
|
|
503
|
-
| `plum run-test` | Run all tests locally without Docker
|
|
504
|
-
| `plum run-test @tag` | Run tests matching a tag
|
|
505
|
-
| `plum run-test --parallel N` | Run tests across N parallel workers
|
|
506
|
-
| `plum run-test --browser <b>` | Run in
|
|
507
|
-
| `plum create-step` | Interactively scaffold a new step definition
|
|
508
|
-
| `plum node start` |
|
|
509
|
-
| `plum node
|
|
510
|
-
| `plum node
|
|
511
|
-
| `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` | Set up connectivity, start a runner node, and open the runner menu |
|
|
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 |
|
|
512
96
|
|
|
513
97
|
---
|
|
514
98
|
|
|
515
99
|
## Development
|
|
516
100
|
|
|
517
|
-
> This section is for contributors developing Plum itself.
|
|
518
|
-
|
|
519
|
-
### Clone and install
|
|
520
|
-
|
|
521
|
-
```bash
|
|
522
|
-
git clone https://github.com/silverlunah/plum.git
|
|
523
|
-
cd plum
|
|
524
|
-
npm run init
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
`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.
|
|
528
102
|
|
|
529
103
|
### Start the stack
|
|
530
104
|
|
|
@@ -533,51 +107,27 @@ npm run docker:up # build and start all services (detached)
|
|
|
533
107
|
npm run docker:down # stop all services
|
|
534
108
|
```
|
|
535
109
|
|
|
536
|
-
|
|
110
|
+
### Frontend (hot reload)
|
|
537
111
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
### Backend — writing and running tests
|
|
541
|
-
|
|
542
|
-
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:
|
|
543
113
|
|
|
544
114
|
```bash
|
|
545
|
-
cd
|
|
115
|
+
cd frontend
|
|
116
|
+
npm run dev # available at http://localhost:5173
|
|
546
117
|
```
|
|
547
118
|
|
|
548
|
-
|
|
119
|
+
### Backend — writing and running tests
|
|
549
120
|
|
|
550
121
|
```bash
|
|
122
|
+
cd backend
|
|
551
123
|
npm test # run all tests
|
|
552
|
-
npm test -- @test-1 # run a specific scenario
|
|
553
|
-
npm test --
|
|
554
|
-
npm
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
**Generate a step definition:**
|
|
558
|
-
|
|
559
|
-
```bash
|
|
560
|
-
npm run create-step
|
|
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
|
|
561
129
|
```
|
|
562
130
|
|
|
563
|
-
Interactive prompt that creates a new step and its page object method.
|
|
564
|
-
|
|
565
|
-
**Scaffold a new test:**
|
|
566
|
-
|
|
567
|
-
```bash
|
|
568
|
-
npm run create-test
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
Interactive prompt that creates a new `.feature` file, page object, and step definition file from a template — ready for you to implement.
|
|
572
|
-
|
|
573
|
-
**Manage runner nodes:**
|
|
574
|
-
|
|
575
|
-
```bash
|
|
576
|
-
npm run manage-runners
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
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.
|
|
580
|
-
|
|
581
131
|
### Test file locations
|
|
582
132
|
|
|
583
133
|
```
|
|
@@ -588,20 +138,11 @@ backend/tests/
|
|
|
588
138
|
utils/ — Browser setup, hooks, helpers
|
|
589
139
|
```
|
|
590
140
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
The frontend dev server runs outside Docker for fast hot module replacement:
|
|
594
|
-
|
|
595
|
-
```bash
|
|
596
|
-
cd frontend
|
|
597
|
-
npm run dev
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
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`
|
|
601
142
|
|
|
602
143
|
---
|
|
603
144
|
|
|
604
145
|
<p align="center">
|
|
605
|
-
Plum is free
|
|
146
|
+
Plum is free and open source. If you'd like to show some love:<br/>
|
|
606
147
|
<a href="https://www.paypal.me/silverlunah">PayPal</a> · <a href="https://wise.com/pay/me/janneserjosee">Wise</a>
|
|
607
148
|
</p>
|
package/backend/app.js
CHANGED
|
@@ -44,6 +44,7 @@ if (process.env.PLUM_MODE !== 'node') {
|
|
|
44
44
|
app.use('/test-suites', require('./routes/test-suites.routes'));
|
|
45
45
|
app.use('/test-cases', require('./routes/test-cases.routes'));
|
|
46
46
|
app.use('/test-runs', require('./routes/test-runs.routes'));
|
|
47
|
+
app.use('/trigger', require('./routes/trigger.routes'));
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
module.exports = app;
|