plum-e2e 2.4.12 → 2.5.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/backend/_scaffold/utils/browser.ts +47 -2
- package/backend/_scaffold/utils/hooks.ts +25 -2
- package/backend/config/scripts/run-tests.js +35 -13
- package/backend/logs/runner-cmr8o2x3n0000mg01410tpuck.log +20 -0
- package/backend/logs/runner-cmr90hvcx0000n2016edtmrtv.log +43 -0
- package/backend/logs/runner-cmr90i7h20001n201g2wg6v3n.log +43 -0
- package/backend/logs/runner-cmr90iilm0002n201mmisva95.log +43 -0
- package/backend/logs/runner-cmr90j70r0003n201xz8525dz.log +20 -0
- package/backend/logs/runner-cmr90yup70000qp017ianc2gp.log +43 -0
- package/backend/logs/runner-cmr90zbtm0001qp01u9tfdkh1.log +20 -0
- package/backend/logs/runner-cmr91a3mw0000tb01414rd1df.log +20 -0
- package/backend/logs/runner-cmr91dhla0001tb01jp7thjnl.log +20 -0
- package/backend/prisma/migrations/20260706000000_add_report_logs/migration.sql +2 -0
- package/backend/prisma/schema.prisma +1 -0
- package/backend/routes/node.routes.js +42 -4
- package/backend/services/reportService.js +24 -4
- package/backend/services/runnerService.js +11 -1
- package/backend/websockets/socketHandler.js +162 -16
- package/bin/plum.js +2 -2
- package/frontend/package.json +1 -1
- package/frontend/src/lib/components/layout/RunnerPanel.svelte +53 -55
- package/frontend/src/lib/components/ui/AutomatedBadge.svelte +56 -0
- package/frontend/src/lib/components/ui/BackLink.svelte +77 -0
- package/frontend/src/lib/components/ui/Badge.svelte +1 -1
- package/frontend/src/lib/components/ui/Button.svelte +1 -1
- package/frontend/src/lib/components/ui/CaseIdChip.svelte +59 -0
- package/frontend/src/lib/components/ui/ConfirmModal.svelte +1 -1
- package/frontend/src/lib/components/ui/Pagination.svelte +1 -1
- package/frontend/src/lib/components/ui/PriorityBadge.svelte +83 -0
- package/frontend/src/lib/components/ui/ResultChip.svelte +92 -0
- package/frontend/src/lib/components/ui/StatusDot.svelte +64 -0
- package/frontend/src/lib/components/ui/StepKeyword.svelte +79 -0
- package/frontend/src/lib/components/ui/StepStatusIcon.svelte +66 -0
- package/frontend/src/lib/components/ui/TagChip.svelte +51 -0
- package/frontend/src/lib/constants.js +14 -0
- package/frontend/src/lib/stores/runner.js +5 -3
- package/frontend/src/lib/styles/tokens.css +26 -0
- package/frontend/src/lib/utils/format.js +74 -0
- package/frontend/src/routes/+page.svelte +3 -3
- package/frontend/src/routes/login/+page.svelte +1 -1
- package/frontend/src/routes/reports/+page.svelte +3 -3
- package/frontend/src/routes/reports/[id]/+page.svelte +703 -215
- package/frontend/src/routes/reports/live/+page.svelte +281 -283
- package/frontend/src/routes/scheduled-tests/+page.svelte +3 -3
- package/frontend/src/routes/settings/+page.svelte +6 -6
- package/frontend/src/routes/setup/+page.svelte +1 -1
- package/frontend/src/routes/test-repository/+page.svelte +5 -5
- package/frontend/src/routes/test-repository/runs/[id]/+page.svelte +27 -151
- package/frontend/src/routes/test-repository/suites/[id]/+page.svelte +4 -4
- package/package.json +1 -1
|
@@ -64,3 +64,77 @@ export function featureFile(uri) {
|
|
|
64
64
|
if (idx !== -1) return normalized.slice(idx + 1);
|
|
65
65
|
return normalized.split('/').pop();
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
export function keywordClass(kw) {
|
|
69
|
+
const k = (kw ?? '').toLowerCase().replace(/:$/, '');
|
|
70
|
+
if (k === 'given') return 'kw-given';
|
|
71
|
+
if (k === 'when') return 'kw-when';
|
|
72
|
+
if (k === 'then') return 'kw-then';
|
|
73
|
+
return 'kw-and';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function scenarioTestTag(scenario) {
|
|
77
|
+
return scenario.tags?.find((tag) => /^@test[\w-]*/i.test(tag)) ?? null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function featureSuiteTag(feature) {
|
|
81
|
+
for (const scenario of feature.scenarios ?? []) {
|
|
82
|
+
const suiteTag = scenario.tags?.find((tag) => /suite/i.test(tag));
|
|
83
|
+
if (suiteTag) return suiteTag;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function visibleTags(scenario) {
|
|
89
|
+
const testTag = scenarioTestTag(scenario);
|
|
90
|
+
if (testTag) return [testTag];
|
|
91
|
+
return (scenario.tags ?? []).filter((tag) => !/suite/i.test(tag));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const STATUS_RANK = { failed: 3, pending: 2, skipped: 1, passed: 0 };
|
|
95
|
+
|
|
96
|
+
export function worstStatus(scenarios) {
|
|
97
|
+
return scenarios.reduce(
|
|
98
|
+
(s, scenario) =>
|
|
99
|
+
(STATUS_RANK[scenario.status] ?? 0) > (STATUS_RANK[s] ?? 0) ? scenario.status : s,
|
|
100
|
+
'passed'
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function groupedScenarios(scenarios) {
|
|
105
|
+
const groups = new Map();
|
|
106
|
+
for (const scenario of scenarios) {
|
|
107
|
+
const testTag = scenarioTestTag(scenario);
|
|
108
|
+
const key = testTag ?? `${scenario.keyword}:${scenario.name}`;
|
|
109
|
+
if (!groups.has(key)) {
|
|
110
|
+
groups.set(key, {
|
|
111
|
+
key,
|
|
112
|
+
name: scenario.name,
|
|
113
|
+
tags: visibleTags(scenario),
|
|
114
|
+
scenarios: [],
|
|
115
|
+
duration: 0,
|
|
116
|
+
status: scenario.status
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
const group = groups.get(key);
|
|
120
|
+
group.scenarios.push(scenario);
|
|
121
|
+
group.duration += scenario.duration ?? 0;
|
|
122
|
+
group.status = worstStatus(group.scenarios);
|
|
123
|
+
}
|
|
124
|
+
return Array.from(groups.values());
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function parseRunnerLogs(logs) {
|
|
128
|
+
if (!logs) return [];
|
|
129
|
+
if (!/^=== .+ ===/m.test(logs)) return [{ name: 'Logs', content: logs }];
|
|
130
|
+
const sections = [];
|
|
131
|
+
for (const chunk of logs.split(/\n\n(?==== )/)) {
|
|
132
|
+
const m = chunk.match(/^=== (.+?) ===\n?([\s\S]*)/);
|
|
133
|
+
if (m) sections.push({ name: m[1].trim(), content: m[2].trim() });
|
|
134
|
+
}
|
|
135
|
+
return sections;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function scenarioHasScreenshots(scenario) {
|
|
139
|
+
return scenario.steps?.some((step) => step.screenshot) ?? false;
|
|
140
|
+
}
|
|
@@ -516,7 +516,7 @@
|
|
|
516
516
|
|
|
517
517
|
.run-icon-btn:hover {
|
|
518
518
|
background: var(--accent);
|
|
519
|
-
color:
|
|
519
|
+
color: var(--white);
|
|
520
520
|
border-color: var(--accent);
|
|
521
521
|
}
|
|
522
522
|
|
|
@@ -534,7 +534,7 @@
|
|
|
534
534
|
color: var(--accent);
|
|
535
535
|
background: var(--accent-soft);
|
|
536
536
|
border: none;
|
|
537
|
-
border-radius:
|
|
537
|
+
border-radius: var(--radius-pill);
|
|
538
538
|
padding: 0.15rem 0.55rem;
|
|
539
539
|
cursor: pointer;
|
|
540
540
|
font-family: 'JetBrains Mono', monospace;
|
|
@@ -589,7 +589,7 @@
|
|
|
589
589
|
background: var(--warn-soft);
|
|
590
590
|
color: var(--warn);
|
|
591
591
|
padding: 0.1rem 0.4rem;
|
|
592
|
-
border-radius:
|
|
592
|
+
border-radius: var(--radius-pill);
|
|
593
593
|
margin-left: 0.4rem;
|
|
594
594
|
vertical-align: middle;
|
|
595
595
|
}
|
|
@@ -361,7 +361,7 @@
|
|
|
361
361
|
.pass-bar-track {
|
|
362
362
|
height: 3px;
|
|
363
363
|
background: var(--fail-soft);
|
|
364
|
-
border-radius:
|
|
364
|
+
border-radius: var(--radius-pill);
|
|
365
365
|
overflow: hidden;
|
|
366
366
|
margin-bottom: 0.5rem;
|
|
367
367
|
}
|
|
@@ -369,7 +369,7 @@
|
|
|
369
369
|
.pass-bar-fill {
|
|
370
370
|
height: 100%;
|
|
371
371
|
background: var(--pass);
|
|
372
|
-
border-radius:
|
|
372
|
+
border-radius: var(--radius-pill);
|
|
373
373
|
transition: width 0.9s var(--ease-out) 0.1s;
|
|
374
374
|
}
|
|
375
375
|
|
|
@@ -468,7 +468,7 @@
|
|
|
468
468
|
|
|
469
469
|
.btn-delete-selected:hover {
|
|
470
470
|
background: var(--fail);
|
|
471
|
-
color:
|
|
471
|
+
color: var(--white);
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
/* ── Report rows ── */
|