plum-e2e 2.4.10 → 2.4.12
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.
|
@@ -29,13 +29,25 @@ function getTestIdsForTag(tag) {
|
|
|
29
29
|
const ids = [];
|
|
30
30
|
const normalTag = tag?.trim();
|
|
31
31
|
|
|
32
|
+
// A test run selection produces a compound OR expression like "@test-1 or @test-2".
|
|
33
|
+
// Split it so each part is matched individually instead of against the whole string.
|
|
34
|
+
const tagParts = normalTag
|
|
35
|
+
? normalTag
|
|
36
|
+
.split(/\s+or\s+/i)
|
|
37
|
+
.map((t) => t.trim())
|
|
38
|
+
.filter(Boolean)
|
|
39
|
+
: [];
|
|
40
|
+
|
|
41
|
+
const matchesAny = (candidates) =>
|
|
42
|
+
tagParts.length === 0 || tagParts.some((part) => candidates.some((id) => id === part));
|
|
43
|
+
|
|
32
44
|
for (const suite of suites) {
|
|
33
45
|
const suiteIds = Array.isArray(suite.suiteId) ? suite.suiteId : [suite.suiteId];
|
|
34
|
-
const suiteMatches = !normalTag || suiteIds
|
|
46
|
+
const suiteMatches = !normalTag || matchesAny(suiteIds);
|
|
35
47
|
|
|
36
48
|
for (const test of suite.tests) {
|
|
37
49
|
const testIds = Array.isArray(test.id) ? test.id : [test.id];
|
|
38
|
-
if (suiteMatches || testIds
|
|
50
|
+
if (suiteMatches || matchesAny(testIds)) {
|
|
39
51
|
ids.push(testIds[0]);
|
|
40
52
|
}
|
|
41
53
|
}
|
|
@@ -721,11 +721,7 @@
|
|
|
721
721
|
{/if}
|
|
722
722
|
|
|
723
723
|
{#each cronJobs as name}
|
|
724
|
-
<a
|
|
725
|
-
href="/scheduled-tests"
|
|
726
|
-
class="run-card cron-run"
|
|
727
|
-
transition:fly={{ x: -4, duration: 160 }}
|
|
728
|
-
>
|
|
724
|
+
<a href="/reports/live" class="run-card cron-run" transition:fly={{ x: -4, duration: 160 }}>
|
|
729
725
|
<span class="run-card-dot pulse-pass"></span>
|
|
730
726
|
<div class="run-card-info">
|
|
731
727
|
<span class="run-card-label">{name}</span>
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { onMount, afterUpdate, onDestroy } from 'svelte';
|
|
20
20
|
import { goto } from '$app/navigation';
|
|
21
21
|
import { fly, fade } from 'svelte/transition';
|
|
22
|
-
import { runnerState, cancelRun } from '$lib/stores/runner';
|
|
22
|
+
import { runnerState, cancelRun, activeCronJobs } from '$lib/stores/runner';
|
|
23
23
|
import { reportUrl } from '$lib/api/reports';
|
|
24
24
|
|
|
25
25
|
let terminalEl;
|
|
@@ -30,6 +30,16 @@
|
|
|
30
30
|
|
|
31
31
|
$: state = $runnerState;
|
|
32
32
|
$: isMulti = state.lanes.length > 0;
|
|
33
|
+
$: cronJobs = Object.keys($activeCronJobs);
|
|
34
|
+
$: anyCronRunning = cronJobs.length > 0;
|
|
35
|
+
|
|
36
|
+
let wasAnyCronRunning = false;
|
|
37
|
+
$: {
|
|
38
|
+
if (wasAnyCronRunning && !anyCronRunning && !state.running && !state.testCompleted) {
|
|
39
|
+
goto('/reports');
|
|
40
|
+
}
|
|
41
|
+
wasAnyCronRunning = anyCronRunning;
|
|
42
|
+
}
|
|
33
43
|
|
|
34
44
|
// Auto-scroll terminals
|
|
35
45
|
afterUpdate(() => {
|
|
@@ -95,7 +105,7 @@
|
|
|
95
105
|
</a>
|
|
96
106
|
</div>
|
|
97
107
|
|
|
98
|
-
{#if !state.running && !state.testCompleted}
|
|
108
|
+
{#if !state.running && !state.testCompleted && !anyCronRunning}
|
|
99
109
|
<!-- Nothing running and no completed test -->
|
|
100
110
|
<div class="idle-state">
|
|
101
111
|
<div class="idle-icon">
|
|
@@ -117,6 +127,20 @@
|
|
|
117
127
|
<p>Start a test from the panel below, then come back here to watch it live.</p>
|
|
118
128
|
<a href="/reports" class="idle-link">View past reports →</a>
|
|
119
129
|
</div>
|
|
130
|
+
{:else if anyCronRunning && !state.running && !state.testCompleted}
|
|
131
|
+
<!-- Scheduled run(s) in progress -->
|
|
132
|
+
<div class="cron-running-state">
|
|
133
|
+
<div class="cron-running-icon">
|
|
134
|
+
<span class="cron-pulse-dot"></span>
|
|
135
|
+
</div>
|
|
136
|
+
<h2>Scheduled {cronJobs.length === 1 ? 'run' : 'runs'} in progress</h2>
|
|
137
|
+
<div class="cron-task-list">
|
|
138
|
+
{#each cronJobs as name}
|
|
139
|
+
<span class="cron-task-chip">{name}</span>
|
|
140
|
+
{/each}
|
|
141
|
+
</div>
|
|
142
|
+
<p>The report will open automatically when the run finishes.</p>
|
|
143
|
+
</div>
|
|
120
144
|
{:else}
|
|
121
145
|
<!-- Run header -->
|
|
122
146
|
<div
|
|
@@ -374,6 +398,70 @@
|
|
|
374
398
|
text-decoration: underline;
|
|
375
399
|
}
|
|
376
400
|
|
|
401
|
+
/* ── Cron running state ── */
|
|
402
|
+
.cron-running-state {
|
|
403
|
+
display: flex;
|
|
404
|
+
flex-direction: column;
|
|
405
|
+
align-items: center;
|
|
406
|
+
justify-content: center;
|
|
407
|
+
padding: 5rem 1rem;
|
|
408
|
+
text-align: center;
|
|
409
|
+
gap: 0.75rem;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.cron-running-icon {
|
|
413
|
+
margin-bottom: 0.5rem;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.cron-pulse-dot {
|
|
417
|
+
display: inline-block;
|
|
418
|
+
width: 18px;
|
|
419
|
+
height: 18px;
|
|
420
|
+
border-radius: 50%;
|
|
421
|
+
background: var(--pass);
|
|
422
|
+
animation: pulse-pass 1.4s ease-in-out infinite;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
@keyframes pulse-pass {
|
|
426
|
+
0%,
|
|
427
|
+
100% {
|
|
428
|
+
opacity: 1;
|
|
429
|
+
transform: scale(1);
|
|
430
|
+
}
|
|
431
|
+
50% {
|
|
432
|
+
opacity: 0.5;
|
|
433
|
+
transform: scale(0.8);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.cron-running-state h2 {
|
|
438
|
+
font-size: 1.5rem;
|
|
439
|
+
font-weight: 400;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.cron-task-list {
|
|
443
|
+
display: flex;
|
|
444
|
+
flex-wrap: wrap;
|
|
445
|
+
gap: 0.5rem;
|
|
446
|
+
justify-content: center;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.cron-task-chip {
|
|
450
|
+
font-size: 0.8125rem;
|
|
451
|
+
font-weight: 500;
|
|
452
|
+
color: var(--accent);
|
|
453
|
+
background: var(--accent-soft);
|
|
454
|
+
border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent);
|
|
455
|
+
border-radius: 100px;
|
|
456
|
+
padding: 0.2rem 0.65rem;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.cron-running-state p {
|
|
460
|
+
font-size: 0.9375rem;
|
|
461
|
+
color: var(--text-muted);
|
|
462
|
+
max-width: 360px;
|
|
463
|
+
}
|
|
464
|
+
|
|
377
465
|
/* ── Run header ── */
|
|
378
466
|
.run-header {
|
|
379
467
|
display: flex;
|