plum-e2e 2.4.13 → 2.5.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.
Files changed (55) hide show
  1. package/CLAUDE.md +1 -1
  2. package/backend/_scaffold/utils/browser.ts +47 -2
  3. package/backend/_scaffold/utils/hooks.ts +25 -2
  4. package/backend/config/scripts/run-tests.js +35 -13
  5. package/backend/logs/runner-cmr8o2x3n0000mg01410tpuck.log +20 -0
  6. package/backend/logs/runner-cmr90hvcx0000n2016edtmrtv.log +43 -0
  7. package/backend/logs/runner-cmr90i7h20001n201g2wg6v3n.log +43 -0
  8. package/backend/logs/runner-cmr90iilm0002n201mmisva95.log +43 -0
  9. package/backend/logs/runner-cmr90j70r0003n201xz8525dz.log +20 -0
  10. package/backend/logs/runner-cmr90yup70000qp017ianc2gp.log +43 -0
  11. package/backend/logs/runner-cmr90zbtm0001qp01u9tfdkh1.log +20 -0
  12. package/backend/logs/runner-cmr91a3mw0000tb01414rd1df.log +20 -0
  13. package/backend/logs/runner-cmr91dhla0001tb01jp7thjnl.log +20 -0
  14. package/backend/prisma/migrations/20260706000000_add_report_logs/migration.sql +2 -0
  15. package/backend/prisma/migrations/20260707032554_add_perf_indexes/migration.sql +44 -0
  16. package/backend/prisma/schema.prisma +20 -0
  17. package/backend/routes/node.routes.js +42 -4
  18. package/backend/routes/reports.routes.js +4 -2
  19. package/backend/services/reportService.js +58 -20
  20. package/backend/services/runnerService.js +11 -1
  21. package/backend/websockets/socketHandler.js +162 -16
  22. package/bin/plum.js +96 -68
  23. package/frontend/package.json +1 -1
  24. package/frontend/src/lib/api/reports.js +16 -5
  25. package/frontend/src/lib/components/layout/RunnerPanel.svelte +53 -55
  26. package/frontend/src/lib/components/ui/AutomatedBadge.svelte +56 -0
  27. package/frontend/src/lib/components/ui/BackLink.svelte +77 -0
  28. package/frontend/src/lib/components/ui/Badge.svelte +1 -1
  29. package/frontend/src/lib/components/ui/Button.svelte +1 -1
  30. package/frontend/src/lib/components/ui/CaseIdChip.svelte +59 -0
  31. package/frontend/src/lib/components/ui/ConfirmModal.svelte +1 -1
  32. package/frontend/src/lib/components/ui/Pagination.svelte +1 -1
  33. package/frontend/src/lib/components/ui/PriorityBadge.svelte +83 -0
  34. package/frontend/src/lib/components/ui/ResultChip.svelte +92 -0
  35. package/frontend/src/lib/components/ui/StatusDot.svelte +64 -0
  36. package/frontend/src/lib/components/ui/StepKeyword.svelte +79 -0
  37. package/frontend/src/lib/components/ui/StepStatusIcon.svelte +66 -0
  38. package/frontend/src/lib/components/ui/TagChip.svelte +51 -0
  39. package/frontend/src/lib/constants.js +14 -0
  40. package/frontend/src/lib/stores/runner.js +5 -3
  41. package/frontend/src/lib/styles/tokens.css +26 -0
  42. package/frontend/src/lib/utils/format.js +74 -0
  43. package/frontend/src/routes/+page.svelte +3 -3
  44. package/frontend/src/routes/login/+page.svelte +55 -40
  45. package/frontend/src/routes/reports/+page.svelte +35 -27
  46. package/frontend/src/routes/reports/[id]/+page.svelte +703 -215
  47. package/frontend/src/routes/reports/live/+page.svelte +281 -283
  48. package/frontend/src/routes/scheduled-tests/+page.svelte +3 -3
  49. package/frontend/src/routes/settings/+page.svelte +6 -6
  50. package/frontend/src/routes/setup/+page.svelte +2 -1
  51. package/frontend/src/routes/test-repository/+page.svelte +5 -5
  52. package/frontend/src/routes/test-repository/runs/[id]/+page.svelte +33 -152
  53. package/frontend/src/routes/test-repository/suites/[id]/+page.svelte +4 -4
  54. package/frontend/vite.config.js +7 -1
  55. package/package.json +1 -1
package/CLAUDE.md CHANGED
@@ -145,7 +145,7 @@ The GPL license header at the top of every file is a legal requirement — do no
145
145
  - All schema changes require a Prisma migration file in `backend/prisma/migrations/`.
146
146
  - Run `npx prisma migrate deploy` (or rebuild Docker) to apply.
147
147
  - Report content is stored as JSONB in the `Report.content` column — never reconstruct report metadata from filenames.
148
- - The `getAllReports()` service function deliberately excludes `content` for list performance — only `getReportDetail(id)` fetches it.
148
+ - The `getReports()` service function is paginated (`page`/`limit`) and deliberately excludes `content` for list performance — only `getReportDetail(id)` fetches it.
149
149
 
150
150
  ---
151
151
 
@@ -1,8 +1,28 @@
1
+ /*
2
+ * This file is part of Plum.
3
+ *
4
+ * Plum is free software: you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation, either version 3 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * Plum is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+
1
18
  import { chromium, firefox, webkit, Browser, BrowserContext, Page } from 'playwright';
19
+ import * as fs from 'fs';
20
+ import * as path from 'path';
2
21
 
3
22
  let _browser: Browser;
4
23
  let _context: BrowserContext;
5
24
  let _page: Page;
25
+ let _ssCounter = 0;
6
26
 
7
27
  export const page = (): Page => _page;
8
28
 
@@ -16,14 +36,39 @@ export async function setup(): Promise<void> {
16
36
  _page = await _context.newPage();
17
37
  }
18
38
 
39
+ export async function screenshotStep(
40
+ attach: (data: Buffer, mime: string) => Promise<void>
41
+ ): Promise<void> {
42
+ if (!_page) return;
43
+ try {
44
+ const screenshot = await _page.screenshot({ type: 'png' });
45
+ await attach(screenshot, 'image/png');
46
+ } catch {
47
+ // page may be navigating or already closed
48
+ }
49
+ }
50
+
51
+ export async function streamLiveScreenshot(stepName: string): Promise<void> {
52
+ const ssDir = process.env.PLUM_SS_DIR;
53
+ if (!ssDir || !_page) return;
54
+ try {
55
+ const seq = `${String(Date.now()).padStart(16, '0')}-${String(++_ssCounter).padStart(4, '0')}`;
56
+ const screenshot = await _page.screenshot({ type: 'jpeg', quality: 70 });
57
+ fs.writeFileSync(
58
+ path.join(ssDir, `${seq}.ss.json`),
59
+ JSON.stringify({ stepName, data: screenshot.toString('base64') })
60
+ );
61
+ } catch {
62
+ // ignore — live streaming is best-effort
63
+ }
64
+ }
65
+
19
66
  export async function teardown(
20
67
  attach: (data: Buffer, mime: string) => Promise<void>,
21
68
  failed: boolean
22
69
  ): Promise<void> {
23
70
  if (failed && _page) {
24
71
  const screenshotDir = 'reports/screenshots';
25
- const fs = await import('fs');
26
- const path = await import('path');
27
72
  if (!fs.existsSync(screenshotDir)) {
28
73
  fs.mkdirSync(screenshotDir, { recursive: true });
29
74
  }
@@ -1,5 +1,22 @@
1
- import { Before, After, ITestCaseHookParameter } from '@cucumber/cucumber';
2
- import { setup, teardown } from './browser';
1
+ /*
2
+ * This file is part of Plum.
3
+ *
4
+ * Plum is free software: you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation, either version 3 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * Plum is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+
18
+ import { Before, After, AfterStep, ITestCaseHookParameter } from '@cucumber/cucumber';
19
+ import { setup, teardown, screenshotStep, streamLiveScreenshot } from './browser';
3
20
  import dotenv from 'dotenv';
4
21
 
5
22
  dotenv.config();
@@ -10,6 +27,12 @@ Before(async ({ pickle }: ITestCaseHookParameter) => {
10
27
  await setup();
11
28
  });
12
29
 
30
+ AfterStep(async function ({ pickleStep, result }: { pickleStep: any; result: any }) {
31
+ if (result?.status === 'SKIPPED') return;
32
+ await screenshotStep(this.attach.bind(this));
33
+ await streamLiveScreenshot(pickleStep?.text ?? '');
34
+ });
35
+
13
36
  After(async function (scenario: ITestCaseHookParameter) {
14
37
  await teardown(this.attach.bind(this), scenario.result?.status === 'FAILED');
15
38
  });
@@ -52,21 +52,39 @@ try {
52
52
  `BROWSER=${browser}`,
53
53
  'TS_NODE_TRANSPILE_ONLY=true',
54
54
  'cucumber-js',
55
- `${testsRoot}/features/**/*.feature`
55
+ // Pass the directory, not a glob — avoids shell globstar expansion differences
56
+ // across platforms and lets cucumber-js discover .feature files recursively.
57
+ `${testsRoot}/features`
56
58
  ];
57
59
 
58
- // A dispatched run executes test files in a temp dir on a runner node. The node's
59
- // own working directory ships a cucumber.json whose `require` globs point at the
60
- // node's *local* tests/ and cucumber merges config-file `require` additively with
61
- // the CLI ones, so every step would match two definitions (local + dispatched) and
62
- // run as "ambiguous": never executing, reporting zero duration. Point cucumber at a
63
- // self-contained config inside the dispatched dir so the node's own cucumber.json is
64
- // skipped entirely (an explicit --config disables auto-discovery of the cwd file).
60
+ // A dispatched run executes test files in a temp dir on a runner node. Running
61
+ // cucumber from that temp dir (cwd = testsRootAbs) makes it auto-discover the
62
+ // cucumber.json written there, so the node's own backend cucumber.json is never
63
+ // loaded preventing step-definition conflicts without relying on --config path
64
+ // resolution (which is fragile when the temp path is outside the project).
65
+ let execCwd;
65
66
  if (process.env.TESTS_ROOT) {
66
- const testsRootAbs = path.resolve(testsRoot);
67
- const configPath = path.join(testsRootAbs, 'cucumber.json');
67
+ const testsRootAbs = path.isAbsolute(testsRoot) ? testsRoot : path.resolve(testsRoot);
68
+ execCwd = testsRootAbs;
69
+
70
+ // hooks.ts calls dotenv.config() with no path, which defaults to process.cwd().
71
+ // When running from a temp dir there is no .env there, so vars like BASE_URL
72
+ // would be undefined. Pre-load BACKEND_DIR's .env so they are already in
73
+ // process.env before dotenv.config() runs (dotenv never overwrites existing vars).
74
+ const backendEnvPath = path.resolve(__dirname, '..', '..', '.env');
75
+ if (fs.existsSync(backendEnvPath)) {
76
+ for (const line of fs.readFileSync(backendEnvPath, 'utf8').split(/\r?\n/)) {
77
+ const m = line.match(/^([A-Za-z_]\w*)\s*=\s*(.*?)(\s*#.*)?$/);
78
+ if (m) {
79
+ const key = m[1];
80
+ const val = m[2].trim().replace(/^(['"])(.*)\1$/, '$2');
81
+ if (!(key in process.env)) process.env[key] = val;
82
+ }
83
+ }
84
+ }
85
+
68
86
  fs.writeFileSync(
69
- configPath,
87
+ path.join(testsRootAbs, 'cucumber.json'),
70
88
  JSON.stringify({
71
89
  default: {
72
90
  requireModule: ['ts-node/register'],
@@ -77,7 +95,6 @@ try {
77
95
  }
78
96
  })
79
97
  );
80
- baseCommand.push('--config', path.relative(process.cwd(), configPath).replace(/\\/g, '/'));
81
98
  } else {
82
99
  baseCommand.push(
83
100
  '--require-module',
@@ -102,11 +119,16 @@ try {
102
119
  const cucumberCommand = baseCommand.join(' ');
103
120
  execSync(cucumberCommand, {
104
121
  stdio: 'inherit',
122
+ ...(execCwd && { cwd: execCwd }),
105
123
  env: {
106
124
  ...process.env,
107
125
  NODE_PATH: process.env.NODE_PATH
108
126
  ? `${nodeModulesPath}${path.delimiter}${process.env.NODE_PATH}`
109
- : nodeModulesPath
127
+ : nodeModulesPath,
128
+ // When running from a temp dir there is no tsconfig.json above it, so
129
+ // ts-node falls back to defaults that may conflict with the Node version.
130
+ // Point it at the backend tsconfig explicitly.
131
+ ...(execCwd && { TS_NODE_PROJECT: path.resolve(__dirname, '..', '..', 'tsconfig.json') })
110
132
  }
111
133
  });
112
134
  } catch (error) {
@@ -0,0 +1,20 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ Backend running on port 3002 (node/runner mode)
19
+ (node:89713) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
20
+ (Use `node --trace-deprecation ...` to show where the warning was created)
@@ -0,0 +1,43 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ node:events:487
19
+ throw er; // Unhandled 'error' event
20
+ ^
21
+
22
+ Error: listen EADDRINUSE: address already in use :::3002
23
+ at Server.setupListenHandle [as _listen2] (node:net:2008:16)
24
+ at listenInCluster (node:net:2065:12)
25
+ at Server.listen (node:net:2170:7)
26
+ at start (/Users/silverlunah/Projects/plum/backend/server.js:65:9)
27
+ at Object.<anonymous> (/Users/silverlunah/Projects/plum/backend/server.js:139:1)
28
+ at Module._compile (node:internal/modules/cjs/loader:1829:14)
29
+ at Module._extensions..js (node:internal/modules/cjs/loader:1969:10)
30
+ at Module.load (node:internal/modules/cjs/loader:1552:32)
31
+ at Module._load (node:internal/modules/cjs/loader:1354:12)
32
+ at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
33
+ Emitted 'error' event on Server instance at:
34
+ at emitErrorNT (node:net:2044:8)
35
+ at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
36
+ code: 'EADDRINUSE',
37
+ errno: -48,
38
+ syscall: 'listen',
39
+ address: '::',
40
+ port: 3002
41
+ }
42
+
43
+ Node.js v25.9.0
@@ -0,0 +1,43 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ node:events:487
19
+ throw er; // Unhandled 'error' event
20
+ ^
21
+
22
+ Error: listen EADDRINUSE: address already in use :::3003
23
+ at Server.setupListenHandle [as _listen2] (node:net:2008:16)
24
+ at listenInCluster (node:net:2065:12)
25
+ at Server.listen (node:net:2170:7)
26
+ at start (/Users/silverlunah/Projects/plum/backend/server.js:65:9)
27
+ at Object.<anonymous> (/Users/silverlunah/Projects/plum/backend/server.js:139:1)
28
+ at Module._compile (node:internal/modules/cjs/loader:1829:14)
29
+ at Module._extensions..js (node:internal/modules/cjs/loader:1969:10)
30
+ at Module.load (node:internal/modules/cjs/loader:1552:32)
31
+ at Module._load (node:internal/modules/cjs/loader:1354:12)
32
+ at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
33
+ Emitted 'error' event on Server instance at:
34
+ at emitErrorNT (node:net:2044:8)
35
+ at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
36
+ code: 'EADDRINUSE',
37
+ errno: -48,
38
+ syscall: 'listen',
39
+ address: '::',
40
+ port: 3003
41
+ }
42
+
43
+ Node.js v25.9.0
@@ -0,0 +1,43 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ node:events:487
19
+ throw er; // Unhandled 'error' event
20
+ ^
21
+
22
+ Error: listen EADDRINUSE: address already in use :::3009
23
+ at Server.setupListenHandle [as _listen2] (node:net:2008:16)
24
+ at listenInCluster (node:net:2065:12)
25
+ at Server.listen (node:net:2170:7)
26
+ at start (/Users/silverlunah/Projects/plum/backend/server.js:65:9)
27
+ at Object.<anonymous> (/Users/silverlunah/Projects/plum/backend/server.js:139:1)
28
+ at Module._compile (node:internal/modules/cjs/loader:1829:14)
29
+ at Module._extensions..js (node:internal/modules/cjs/loader:1969:10)
30
+ at Module.load (node:internal/modules/cjs/loader:1552:32)
31
+ at Module._load (node:internal/modules/cjs/loader:1354:12)
32
+ at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
33
+ Emitted 'error' event on Server instance at:
34
+ at emitErrorNT (node:net:2044:8)
35
+ at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
36
+ code: 'EADDRINUSE',
37
+ errno: -48,
38
+ syscall: 'listen',
39
+ address: '::',
40
+ port: 3009
41
+ }
42
+
43
+ Node.js v25.9.0
@@ -0,0 +1,20 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ Backend running on port 5177 (node/runner mode)
19
+ (node:98310) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
20
+ (Use `node --trace-deprecation ...` to show where the warning was created)
@@ -0,0 +1,43 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ node:events:487
19
+ throw er; // Unhandled 'error' event
20
+ ^
21
+
22
+ Error: listen EADDRINUSE: address already in use :::3002
23
+ at Server.setupListenHandle [as _listen2] (node:net:2008:16)
24
+ at listenInCluster (node:net:2065:12)
25
+ at Server.listen (node:net:2170:7)
26
+ at start (/Users/silverlunah/Projects/plum/backend/server.js:65:9)
27
+ at Object.<anonymous> (/Users/silverlunah/Projects/plum/backend/server.js:139:1)
28
+ at Module._compile (node:internal/modules/cjs/loader:1829:14)
29
+ at Module._extensions..js (node:internal/modules/cjs/loader:1969:10)
30
+ at Module.load (node:internal/modules/cjs/loader:1552:32)
31
+ at Module._load (node:internal/modules/cjs/loader:1354:12)
32
+ at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
33
+ Emitted 'error' event on Server instance at:
34
+ at emitErrorNT (node:net:2044:8)
35
+ at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
36
+ code: 'EADDRINUSE',
37
+ errno: -48,
38
+ syscall: 'listen',
39
+ address: '::',
40
+ port: 3002
41
+ }
42
+
43
+ Node.js v25.9.0
@@ -0,0 +1,20 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ Backend running on port 5178 (node/runner mode)
19
+ (node:825) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
20
+ (Use `node --trace-deprecation ...` to show where the warning was created)
@@ -0,0 +1,20 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ Backend running on port 5178 (node/runner mode)
19
+ (node:2599) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
20
+ (Use `node --trace-deprecation ...` to show where the warning was created)
@@ -0,0 +1,20 @@
1
+ /*
2
+ This file is part of Plum.
3
+
4
+ Plum is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ Plum is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Plum. If not, see https://www.gnu.org/licenses/.
16
+ */
17
+ 📂 Loading tests from: /Users/silverlunah/Projects/plum/backend/tests
18
+ Backend running on port 5180 (node/runner mode)
19
+ (node:3077) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
20
+ (Use `node --trace-deprecation ...` to show where the warning was created)
@@ -0,0 +1,2 @@
1
+ -- AlterTable
2
+ ALTER TABLE "Report" ADD COLUMN "logs" TEXT;
@@ -0,0 +1,44 @@
1
+ -- AlterTable
2
+ ALTER TABLE "Report" ALTER COLUMN "content" DROP DEFAULT;
3
+
4
+ -- AlterTable
5
+ ALTER TABLE "TestRun" ALTER COLUMN "status" SET DEFAULT 'backlog';
6
+
7
+ -- CreateIndex
8
+ CREATE INDEX "Report_createdAt_idx" ON "Report"("createdAt");
9
+
10
+ -- CreateIndex
11
+ CREATE INDEX "Report_status_idx" ON "Report"("status");
12
+
13
+ -- CreateIndex
14
+ CREATE INDEX "Report_testRunId_idx" ON "Report"("testRunId");
15
+
16
+ -- CreateIndex
17
+ CREATE INDEX "Report_runnerId_idx" ON "Report"("runnerId");
18
+
19
+ -- CreateIndex
20
+ CREATE INDEX "Report_cronJobId_idx" ON "Report"("cronJobId");
21
+
22
+ -- CreateIndex
23
+ CREATE INDEX "TestCase_suiteId_idx" ON "TestCase"("suiteId");
24
+
25
+ -- CreateIndex
26
+ CREATE INDEX "TestCaseHistory_caseId_idx" ON "TestCaseHistory"("caseId");
27
+
28
+ -- CreateIndex
29
+ CREATE INDEX "TestCaseHistory_runId_idx" ON "TestCaseHistory"("runId");
30
+
31
+ -- CreateIndex
32
+ CREATE INDEX "TestCaseHistory_reportId_idx" ON "TestCaseHistory"("reportId");
33
+
34
+ -- CreateIndex
35
+ CREATE INDEX "TestRun_createdAt_idx" ON "TestRun"("createdAt");
36
+
37
+ -- CreateIndex
38
+ CREATE INDEX "TestRunEntry_runId_idx" ON "TestRunEntry"("runId");
39
+
40
+ -- CreateIndex
41
+ CREATE INDEX "TestRunEntry_caseId_idx" ON "TestRunEntry"("caseId");
42
+
43
+ -- CreateIndex
44
+ CREATE INDEX "TestSuite_createdAt_idx" ON "TestSuite"("createdAt");
@@ -67,8 +67,15 @@ model Report {
67
67
  testRunId String?
68
68
  testRun TestRun? @relation(fields: [testRunId], references: [id], onDelete: SetNull)
69
69
  content Json
70
+ logs String?
70
71
  createdAt DateTime @default(now())
71
72
  testHistory TestCaseHistory[]
73
+
74
+ @@index([createdAt])
75
+ @@index([status])
76
+ @@index([testRunId])
77
+ @@index([runnerId])
78
+ @@index([cronJobId])
72
79
  }
73
80
 
74
81
  model Project {
@@ -123,6 +130,8 @@ model TestSuite {
123
130
  createdAt DateTime @default(now())
124
131
  updatedAt DateTime @updatedAt
125
132
  cases TestCase[]
133
+
134
+ @@index([createdAt])
126
135
  }
127
136
 
128
137
  model TestCase {
@@ -141,6 +150,8 @@ model TestCase {
141
150
  steps TestStep[]
142
151
  runEntries TestRunEntry[]
143
152
  history TestCaseHistory[]
153
+
154
+ @@index([suiteId])
144
155
  }
145
156
 
146
157
  model TestStep {
@@ -165,6 +176,8 @@ model TestRun {
165
176
  entries TestRunEntry[]
166
177
  history TestCaseHistory[]
167
178
  reports Report[]
179
+
180
+ @@index([createdAt])
168
181
  }
169
182
 
170
183
  model TestRunEntry {
@@ -181,6 +194,9 @@ model TestRunEntry {
181
194
  executedAt DateTime?
182
195
  assignedToId String?
183
196
  assignedTo User? @relation("entryAssignee", fields: [assignedToId], references: [id])
197
+
198
+ @@index([runId])
199
+ @@index([caseId])
184
200
  }
185
201
 
186
202
  model TestCaseHistory {
@@ -197,4 +213,8 @@ model TestCaseHistory {
197
213
  executedById String?
198
214
  executedBy User? @relation(fields: [executedById], references: [id])
199
215
  executedAt DateTime @default(now())
216
+
217
+ @@index([caseId])
218
+ @@index([runId])
219
+ @@index([reportId])
200
220
  }