@alejandrojca/elmulo-reporter 2.0.0-beta.7 → 2.0.0-beta.9
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/VERSION.json +1 -1
- package/assets/app.css +209 -69
- package/assets/app.js +158 -89
- package/assets/menu-icons/analysis.png +0 -0
- package/assets/menu-icons/executions.png +0 -0
- package/assets/menu-icons/preferences.png +0 -0
- package/assets/menu-icons/quality.png +0 -0
- package/assets/menu-icons/summary.png +0 -0
- package/assets/menu-icons/tests.png +0 -0
- package/finalize.cjs +2 -2
- package/jira.cjs +2 -2
- package/package.json +1 -1
- package/plugin.cjs +1 -1
- package/server.cjs +1 -1
package/VERSION.json
CHANGED
package/assets/app.css
CHANGED
|
@@ -27,9 +27,12 @@
|
|
|
27
27
|
box-sizing: border-box;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
html,
|
|
31
|
+
body {
|
|
32
|
+
height: 100%;
|
|
33
|
+
margin: 0;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
}
|
|
33
36
|
|
|
34
37
|
html[data-theme="dark"],
|
|
35
38
|
html[data-theme="dark"] * {
|
|
@@ -258,10 +261,54 @@ button {
|
|
|
258
261
|
.metricCard.passed { --metric-color: var(--pw-success); }
|
|
259
262
|
.metricCard.failed { --metric-color: var(--pw-danger); }
|
|
260
263
|
.metricCard.skipped { --metric-color: var(--pw-gray-300); }
|
|
261
|
-
.metricCard.flaky { --metric-color: var(--pw-warning); }
|
|
262
|
-
.metricCard.otherErrors { --metric-color: #d18a00; }
|
|
263
|
-
|
|
264
|
-
.metricCard.
|
|
264
|
+
.metricCard.flaky { --metric-color: var(--pw-warning); }
|
|
265
|
+
.metricCard.otherErrors { --metric-color: #d18a00; }
|
|
266
|
+
|
|
267
|
+
.metricCard.failedBreakdown {
|
|
268
|
+
display: grid;
|
|
269
|
+
gap: 0.9rem;
|
|
270
|
+
grid-column: span 2;
|
|
271
|
+
grid-template-columns: minmax(90px, 0.7fr) minmax(210px, 1.3fr);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.failureMetricTotal {
|
|
275
|
+
align-self: center;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.failureMetricBreakdown {
|
|
279
|
+
align-content: center;
|
|
280
|
+
display: grid;
|
|
281
|
+
gap: 0.35rem;
|
|
282
|
+
margin: 0;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.failureMetricBreakdown > div {
|
|
286
|
+
--breakdown-color: var(--pw-danger);
|
|
287
|
+
align-items: center;
|
|
288
|
+
border: 1px solid color-mix(in srgb, var(--breakdown-color) 62%, var(--pw-gray-200));
|
|
289
|
+
border-radius: 999px;
|
|
290
|
+
display: flex;
|
|
291
|
+
justify-content: space-between;
|
|
292
|
+
padding: 0.25rem 0.55rem;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.failureMetricBreakdown .reported { --breakdown-color: var(--pw-blue-600); }
|
|
296
|
+
.failureMetricBreakdown .otherErrors { --breakdown-color: var(--pw-warning); }
|
|
297
|
+
|
|
298
|
+
.failureMetricBreakdown dt,
|
|
299
|
+
.failureMetricBreakdown dd {
|
|
300
|
+
color: var(--pw-gray-700);
|
|
301
|
+
font-size: 0.68rem;
|
|
302
|
+
font-weight: 800;
|
|
303
|
+
margin: 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.failureMetricBreakdown dd {
|
|
307
|
+
color: var(--breakdown-color);
|
|
308
|
+
font-size: 0.82rem;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.metricCard.activeFilter {
|
|
265
312
|
border-color: var(--metric-color, var(--pw-blue-700));
|
|
266
313
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--metric-color, var(--pw-blue-700)) 18%, transparent);
|
|
267
314
|
}
|
|
@@ -363,10 +410,15 @@ button {
|
|
|
363
410
|
padding: 0.55rem 0.65rem;
|
|
364
411
|
}
|
|
365
412
|
|
|
366
|
-
.statusLegendItem.empty {
|
|
367
|
-
opacity: 0.56;
|
|
368
|
-
}
|
|
369
|
-
|
|
413
|
+
.statusLegendItem.empty {
|
|
414
|
+
opacity: 0.56;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.statusLegendItem:not(.empty) {
|
|
418
|
+
border-color: var(--status-color);
|
|
419
|
+
box-shadow: 0 0 0 1px color-mix(in srgb, var(--status-color) 24%, transparent);
|
|
420
|
+
}
|
|
421
|
+
|
|
370
422
|
.statusLegendDot {
|
|
371
423
|
background: var(--status-color);
|
|
372
424
|
border-radius: 50%;
|
|
@@ -798,19 +850,59 @@ button {
|
|
|
798
850
|
margin: 1rem 0;
|
|
799
851
|
}
|
|
800
852
|
|
|
801
|
-
.
|
|
802
|
-
background: var(--pw-blue-050);
|
|
803
|
-
border-radius: 999px;
|
|
804
|
-
color: var(--pw-gray-700);
|
|
805
|
-
font-size: 0.78rem;
|
|
806
|
-
padding: 0.45rem 0.65rem;
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
.
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
.
|
|
853
|
+
.historicalExecutionCount {
|
|
854
|
+
background: var(--pw-blue-050);
|
|
855
|
+
border-radius: 999px;
|
|
856
|
+
color: var(--pw-gray-700);
|
|
857
|
+
font-size: 0.78rem;
|
|
858
|
+
padding: 0.45rem 0.65rem;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
.historicalStatusFilters {
|
|
862
|
+
display: flex;
|
|
863
|
+
flex: 1 1 420px;
|
|
864
|
+
flex-wrap: wrap;
|
|
865
|
+
gap: 0.45rem;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
.historicalStatusFilter {
|
|
869
|
+
--historical-status-color: var(--pw-gray-700);
|
|
870
|
+
background: color-mix(in srgb, var(--historical-status-color) 7%, var(--pw-white));
|
|
871
|
+
border: 1px solid color-mix(in srgb, var(--historical-status-color) 55%, var(--pw-gray-200));
|
|
872
|
+
border-radius: 999px;
|
|
873
|
+
color: var(--historical-status-color);
|
|
874
|
+
font-size: 0.75rem;
|
|
875
|
+
font-weight: 700;
|
|
876
|
+
padding: 0.42rem 0.65rem;
|
|
877
|
+
transition:
|
|
878
|
+
background 140ms ease,
|
|
879
|
+
box-shadow 140ms ease,
|
|
880
|
+
transform 140ms ease;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.historicalStatusFilter.passed { --historical-status-color: var(--pw-success); }
|
|
884
|
+
.historicalStatusFilter.failed { --historical-status-color: var(--pw-danger); }
|
|
885
|
+
.historicalStatusFilter.environment_error { --historical-status-color: var(--pw-warning); }
|
|
886
|
+
.historicalStatusFilter.precondition_error { --historical-status-color: #e87922; }
|
|
887
|
+
.historicalStatusFilter.outdated_test { --historical-status-color: #7c5ce5; }
|
|
888
|
+
.historicalStatusFilter.reported { --historical-status-color: var(--pw-blue-600); }
|
|
889
|
+
.historicalStatusFilter.skipped,
|
|
890
|
+
.historicalStatusFilter.pending { --historical-status-color: #71859a; }
|
|
891
|
+
|
|
892
|
+
.historicalStatusFilter:hover,
|
|
893
|
+
.historicalStatusFilter:focus-visible {
|
|
894
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--historical-status-color) 18%, transparent);
|
|
895
|
+
transform: translateY(-1px);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
.historicalStatusFilter.active {
|
|
899
|
+
background: var(--historical-status-color);
|
|
900
|
+
border-color: var(--historical-status-color);
|
|
901
|
+
color: #fff;
|
|
902
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--historical-status-color) 22%, transparent);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
.historicalTestList {
|
|
814
906
|
display: grid;
|
|
815
907
|
gap: 0.55rem;
|
|
816
908
|
max-height: 480px;
|
|
@@ -2228,18 +2320,35 @@ html[data-theme="dark"] .exportPdfButton {
|
|
|
2228
2320
|
grid-template-columns: repeat(5, 1fr);
|
|
2229
2321
|
}
|
|
2230
2322
|
|
|
2231
|
-
.attentionCard {
|
|
2232
|
-
background: var(--pw-blue-050);
|
|
2233
|
-
border: 1px solid var(--pw-gray-200);
|
|
2234
|
-
border-left: 4px solid var(--attention-color, var(--pw-blue-700));
|
|
2323
|
+
.attentionCard {
|
|
2324
|
+
background: var(--pw-blue-050);
|
|
2325
|
+
border: 1px solid var(--pw-gray-200);
|
|
2326
|
+
border-left: 4px solid var(--attention-color, var(--pw-blue-700));
|
|
2235
2327
|
border-radius: 14px;
|
|
2236
2328
|
color: var(--pw-gray-900);
|
|
2237
2329
|
display: grid;
|
|
2238
|
-
gap: 0.25rem;
|
|
2239
|
-
padding: 0.8rem;
|
|
2240
|
-
text-align: left;
|
|
2241
|
-
|
|
2242
|
-
|
|
2330
|
+
gap: 0.25rem;
|
|
2331
|
+
padding: 0.8rem;
|
|
2332
|
+
text-align: left;
|
|
2333
|
+
transition:
|
|
2334
|
+
border-color 160ms ease,
|
|
2335
|
+
box-shadow 160ms ease,
|
|
2336
|
+
transform 160ms ease;
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
.attentionCard:not(:disabled):hover,
|
|
2340
|
+
.attentionCard:not(:disabled):focus-visible {
|
|
2341
|
+
border-color: var(--attention-color, var(--pw-blue-700));
|
|
2342
|
+
box-shadow:
|
|
2343
|
+
0 0 0 2px color-mix(in srgb, var(--attention-color, var(--pw-blue-700)) 24%, transparent),
|
|
2344
|
+
0 12px 24px color-mix(in srgb, var(--attention-color, var(--pw-blue-700)) 14%, transparent);
|
|
2345
|
+
transform: translateY(-2px);
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
.attentionCard:not(:disabled):focus-visible {
|
|
2349
|
+
outline: none;
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2243
2352
|
.attentionCard.failed,
|
|
2244
2353
|
.attentionCard.no_comment,
|
|
2245
2354
|
.attentionCard.no_ticket {
|
|
@@ -3938,15 +4047,23 @@ pre {
|
|
|
3938
4047
|
|
|
3939
4048
|
/* Elmulo V2 application navigation */
|
|
3940
4049
|
|
|
3941
|
-
.appFrame {
|
|
3942
|
-
display: grid;
|
|
3943
|
-
grid-template-columns: auto minmax(0, 1fr);
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
4050
|
+
.appFrame {
|
|
4051
|
+
display: grid;
|
|
4052
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
4053
|
+
height: 100vh;
|
|
4054
|
+
height: 100dvh;
|
|
4055
|
+
min-height: 0;
|
|
4056
|
+
overflow: hidden;
|
|
4057
|
+
}
|
|
4058
|
+
|
|
4059
|
+
.workspaceShell {
|
|
4060
|
+
display: grid;
|
|
4061
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
4062
|
+
height: 100vh;
|
|
4063
|
+
height: 100dvh;
|
|
4064
|
+
min-width: 0;
|
|
4065
|
+
overflow: hidden;
|
|
4066
|
+
}
|
|
3950
4067
|
|
|
3951
4068
|
.sidebar {
|
|
3952
4069
|
background:
|
|
@@ -4074,23 +4191,40 @@ pre {
|
|
|
4074
4191
|
position: relative;
|
|
4075
4192
|
}
|
|
4076
4193
|
|
|
4077
|
-
.sidebarIcon {
|
|
4078
|
-
align-items: center;
|
|
4079
|
-
background: rgb(255 255 255 / 7%);
|
|
4080
|
-
border-radius: 9px;
|
|
4081
|
-
display: inline-flex;
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4194
|
+
.sidebarIcon {
|
|
4195
|
+
align-items: center;
|
|
4196
|
+
background: rgb(255 255 255 / 7%);
|
|
4197
|
+
border-radius: 9px;
|
|
4198
|
+
display: inline-flex;
|
|
4199
|
+
height: 34px;
|
|
4200
|
+
justify-content: center;
|
|
4201
|
+
width: 34px;
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4204
|
+
.sidebarIconImage {
|
|
4205
|
+
filter: brightness(0) invert(1);
|
|
4206
|
+
height: 21px;
|
|
4207
|
+
object-fit: contain;
|
|
4208
|
+
opacity: 0.82;
|
|
4209
|
+
transition: filter 140ms ease, opacity 140ms ease, transform 140ms ease;
|
|
4210
|
+
width: 21px;
|
|
4211
|
+
}
|
|
4212
|
+
|
|
4213
|
+
.sidebarLink:hover .sidebarIconImage {
|
|
4214
|
+
opacity: 1;
|
|
4215
|
+
transform: scale(1.06);
|
|
4216
|
+
}
|
|
4217
|
+
|
|
4218
|
+
.sidebarLink.active .sidebarIcon {
|
|
4219
|
+
background: #dff8f8;
|
|
4220
|
+
color: #075f76;
|
|
4221
|
+
}
|
|
4222
|
+
|
|
4223
|
+
.sidebarLink.active .sidebarIconImage {
|
|
4224
|
+
filter: brightness(0) saturate(100%) invert(29%) sepia(43%) saturate(1271%) hue-rotate(147deg) brightness(91%) contrast(96%);
|
|
4225
|
+
opacity: 1;
|
|
4226
|
+
}
|
|
4227
|
+
|
|
4094
4228
|
.sidebarLabel {
|
|
4095
4229
|
font-size: 0.85rem;
|
|
4096
4230
|
font-weight: 700;
|
|
@@ -4196,11 +4330,16 @@ pre {
|
|
|
4196
4330
|
width: 38px;
|
|
4197
4331
|
}
|
|
4198
4332
|
|
|
4199
|
-
.appShell {
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4333
|
+
.appShell {
|
|
4334
|
+
height: 100%;
|
|
4335
|
+
margin: 0 auto;
|
|
4336
|
+
max-width: 1600px;
|
|
4337
|
+
min-height: 0;
|
|
4338
|
+
overflow-y: auto;
|
|
4339
|
+
overscroll-behavior-y: contain;
|
|
4340
|
+
padding: 1.5rem 2rem 4rem;
|
|
4341
|
+
width: 100%;
|
|
4342
|
+
}
|
|
4204
4343
|
|
|
4205
4344
|
.workspaceView[hidden] {
|
|
4206
4345
|
display: none !important;
|
|
@@ -4311,11 +4450,12 @@ pre {
|
|
|
4311
4450
|
transform: translateY(-1px);
|
|
4312
4451
|
}
|
|
4313
4452
|
|
|
4314
|
-
.
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4453
|
+
.overviewLaunchIcon {
|
|
4454
|
+
filter: brightness(0) saturate(100%) invert(61%) sepia(78%) saturate(623%) hue-rotate(132deg) brightness(87%) contrast(82%);
|
|
4455
|
+
height: 24px;
|
|
4456
|
+
object-fit: contain;
|
|
4457
|
+
width: 24px;
|
|
4458
|
+
}
|
|
4319
4459
|
|
|
4320
4460
|
.overviewLaunchGrid small {
|
|
4321
4461
|
color: var(--pw-gray-700);
|
package/assets/app.js
CHANGED
|
@@ -42,13 +42,13 @@
|
|
|
42
42
|
const pdfSections = [
|
|
43
43
|
["summary", "Resumen ejecutivo", "Indicadores principales y evaluación general.", true],
|
|
44
44
|
["statusDistribution", "Distribución por estado", "Resultados automáticos y clasificaciones manuales.", true],
|
|
45
|
-
["runContext", "Contexto de la corrida", "Ambiente, fecha, navegador, tags, rama y pipeline.",
|
|
45
|
+
["runContext", "Contexto de la corrida", "Ambiente, fecha, navegador, tags, rama y pipeline.", false],
|
|
46
46
|
["features", "Resultados por Feature", "Totales y estados agrupados por Feature.", true],
|
|
47
47
|
["issues", "Problemas que requieren seguimiento", "Fallos, Jira, comentarios y tickets asociados.", true],
|
|
48
|
-
["previousComparison", "Comparación con la corrida anterior", "Variaciones de resultados y duración.",
|
|
49
|
-
["recentHistory", "Historial reciente", "Últimas ejecuciones del mismo ambiente.",
|
|
50
|
-
["flaky", "Pruebas inestables", "Casos que pasaron después de uno o más reintentos.",
|
|
51
|
-
["recurrentFailures", "Fallos recurrentes", "Pruebas con fallos repetidos en el historial.",
|
|
48
|
+
["previousComparison", "Comparación con la corrida anterior", "Variaciones de resultados y duración.", false],
|
|
49
|
+
["recentHistory", "Historial reciente", "Últimas ejecuciones del mismo ambiente.", false],
|
|
50
|
+
["flaky", "Pruebas inestables", "Casos que pasaron después de uno o más reintentos.", false],
|
|
51
|
+
["recurrentFailures", "Fallos recurrentes", "Pruebas con fallos repetidos en el historial.", false],
|
|
52
52
|
["slowTests", "Pruebas más lentas", "Ranking histórico de pruebas por duración.", false],
|
|
53
53
|
["recommendation", "Recomendación y pendientes", "Evaluación final, fallos sin comentario y sin ticket.", true],
|
|
54
54
|
];
|
|
@@ -201,9 +201,10 @@
|
|
|
201
201
|
tag: initialUrlState.get("tag") || "all",
|
|
202
202
|
trendStatus: "total",
|
|
203
203
|
trendEnvironment: initialTrendEnvironment,
|
|
204
|
-
selectedTrendRunId: null,
|
|
205
|
-
historicalRun: null,
|
|
206
|
-
historicalRerun: null,
|
|
204
|
+
selectedTrendRunId: null,
|
|
205
|
+
historicalRun: null,
|
|
206
|
+
historicalRerun: null,
|
|
207
|
+
historicalStatusFilter: "",
|
|
207
208
|
historyJiraId: null,
|
|
208
209
|
historyTestTitle: "",
|
|
209
210
|
historyCurrentTestId: null,
|
|
@@ -705,19 +706,32 @@
|
|
|
705
706
|
dialog.showModal();
|
|
706
707
|
}
|
|
707
708
|
|
|
708
|
-
function metric(label, value, className = "") {
|
|
709
|
-
return `<article class="metricCard ${className}">
|
|
710
|
-
<span>${escapeHtml(label)}</span>
|
|
711
|
-
<strong>${value}</strong>
|
|
712
|
-
</article>`;
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
function
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
709
|
+
function metric(label, value, className = "") {
|
|
710
|
+
return `<article class="metricCard ${className}">
|
|
711
|
+
<span>${escapeHtml(label)}</span>
|
|
712
|
+
<strong>${value}</strong>
|
|
713
|
+
</article>`;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function failureMetric(total, deltaMarkup, breakdown, className = "") {
|
|
717
|
+
return `<article class="metricCard failed failedBreakdown ${className}">
|
|
718
|
+
<div class="failureMetricTotal">
|
|
719
|
+
<span>Fallidas</span>
|
|
720
|
+
<strong>${escapeHtml(total)}${deltaMarkup}</strong>
|
|
721
|
+
</div>
|
|
722
|
+
<dl class="failureMetricBreakdown" aria-label="Desglose de pruebas fallidas">
|
|
723
|
+
${breakdown.map(([label, value, status]) => `<div class="${escapeHtml(status)}">
|
|
724
|
+
<dt>${escapeHtml(label)}</dt>
|
|
725
|
+
<dd>${escapeHtml(value)}</dd>
|
|
726
|
+
</div>`).join("")}
|
|
727
|
+
</dl>
|
|
728
|
+
</article>`;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function summaryMarkup() {
|
|
732
|
+
const effectiveStatuses = run.tests.map(effectiveTestStatus);
|
|
733
|
+
const statusCount = (status) =>
|
|
734
|
+
effectiveStatuses.filter((value) => value === status).length;
|
|
721
735
|
const activeClass = (status, baseClass = status) =>
|
|
722
736
|
`${baseClass} ${state.status === status ? "activeFilter" : ""}`.trim();
|
|
723
737
|
const previousRun = [...(run.trends?.runs || [])]
|
|
@@ -728,26 +742,33 @@
|
|
|
728
742
|
const difference = Number(current) - Number(previous || 0);
|
|
729
743
|
if (!difference) return '<small class="metricDelta neutral">Sin cambios</small>';
|
|
730
744
|
return `<small class="metricDelta ${difference > 0 ? "up" : "down"}">${difference > 0 ? "+" : ""}${difference} vs. anterior</small>`;
|
|
731
|
-
};
|
|
732
|
-
const passedCount = statusCount("passed");
|
|
733
|
-
const
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
745
|
+
};
|
|
746
|
+
const passedCount = statusCount("passed");
|
|
747
|
+
const automaticFailures = run.tests.filter((test) => test.status === "failed");
|
|
748
|
+
const failedCount = automaticFailures.length;
|
|
749
|
+
const pendingFailures = automaticFailures.filter((test) =>
|
|
750
|
+
effectiveTestStatus(test) === "failed").length;
|
|
751
|
+
const reportedFailures = automaticFailures.filter((test) =>
|
|
752
|
+
effectiveTestStatus(test) === "reported").length;
|
|
753
|
+
const otherFailures = automaticFailures.filter((test) => {
|
|
754
|
+
const status = effectiveTestStatus(test);
|
|
755
|
+
return otherErrorStatuses.has(status) && status !== "reported";
|
|
756
|
+
}).length;
|
|
740
757
|
|
|
741
758
|
return `
|
|
742
759
|
${metric("Casos", groupTestsByCase(run.tests).length)}
|
|
743
760
|
${metric("Ejecuciones", run.tests.length)}
|
|
744
761
|
${metric("Exitosas", `${passedCount}${delta(passedCount, previousRun?.passed)}`, activeClass("passed"))}
|
|
745
|
-
${
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
762
|
+
${failureMetric(
|
|
763
|
+
failedCount,
|
|
764
|
+
delta(failedCount, previousRun?.failed),
|
|
765
|
+
[
|
|
766
|
+
["Pendientes", pendingFailures, "pending"],
|
|
767
|
+
["Reportadas", reportedFailures, "reported"],
|
|
768
|
+
["Otros errores", otherFailures, "otherErrors"],
|
|
769
|
+
],
|
|
770
|
+
activeClass("failed"),
|
|
771
|
+
)}
|
|
751
772
|
${metric("Inestables", run.tests.filter((test) => test.flaky).length, "flaky")}
|
|
752
773
|
`;
|
|
753
774
|
}
|
|
@@ -1099,7 +1120,7 @@
|
|
|
1099
1120
|
</div>`;
|
|
1100
1121
|
}
|
|
1101
1122
|
|
|
1102
|
-
function renderHistoricalRun() {
|
|
1123
|
+
function renderHistoricalRun() {
|
|
1103
1124
|
const historicalRun = state.historicalRun;
|
|
1104
1125
|
if (!state.selectedTrendRunId) {
|
|
1105
1126
|
return `<div class="trendHistoryPlaceholder">
|
|
@@ -1110,11 +1131,39 @@
|
|
|
1110
1131
|
return `<div class="trendHistoryPlaceholder">Cargando resultados históricos…</div>`;
|
|
1111
1132
|
}
|
|
1112
1133
|
|
|
1113
|
-
const tests = historicalRun.tests || [];
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1134
|
+
const tests = historicalRun.tests || [];
|
|
1135
|
+
const historicalStatusOrder = [
|
|
1136
|
+
"passed",
|
|
1137
|
+
"failed",
|
|
1138
|
+
"environment_error",
|
|
1139
|
+
"precondition_error",
|
|
1140
|
+
"outdated_test",
|
|
1141
|
+
"reported",
|
|
1142
|
+
"skipped",
|
|
1143
|
+
"pending",
|
|
1144
|
+
"unknown",
|
|
1145
|
+
];
|
|
1146
|
+
const statusCounts = tests.reduce((counts, test) => {
|
|
1147
|
+
const status = String(test.status || "unknown");
|
|
1148
|
+
counts.set(status, (counts.get(status) || 0) + 1);
|
|
1149
|
+
return counts;
|
|
1150
|
+
}, new Map());
|
|
1151
|
+
const visibleStatuses = [...statusCounts.entries()]
|
|
1152
|
+
.sort(([left], [right]) => {
|
|
1153
|
+
const leftIndex = historicalStatusOrder.indexOf(left);
|
|
1154
|
+
const rightIndex = historicalStatusOrder.indexOf(right);
|
|
1155
|
+
return (leftIndex < 0 ? historicalStatusOrder.length : leftIndex) -
|
|
1156
|
+
(rightIndex < 0 ? historicalStatusOrder.length : rightIndex);
|
|
1157
|
+
});
|
|
1158
|
+
if (
|
|
1159
|
+
state.historicalStatusFilter &&
|
|
1160
|
+
!statusCounts.has(state.historicalStatusFilter)
|
|
1161
|
+
) {
|
|
1162
|
+
state.historicalStatusFilter = "";
|
|
1163
|
+
}
|
|
1164
|
+
const filteredTests = state.historicalStatusFilter
|
|
1165
|
+
? tests.filter((test) => test.status === state.historicalStatusFilter)
|
|
1166
|
+
: tests;
|
|
1118
1167
|
const rerun = state.historicalRerun || historicalRun.rerun || {};
|
|
1119
1168
|
const rerunBusy = ["starting", "running"].includes(rerun.status);
|
|
1120
1169
|
const rerunLabel = rerun.status === "starting"
|
|
@@ -1152,18 +1201,23 @@
|
|
|
1152
1201
|
>×</button>
|
|
1153
1202
|
</div>
|
|
1154
1203
|
</header>
|
|
1155
|
-
${rerunFeedback
|
|
1156
|
-
? `<div class="trendRerunFeedback ${rerun.status === "failed" || rerun.status === "unavailable" ? "error" : "success"}" role="status">${escapeHtml(rerunFeedback)}</div>`
|
|
1157
|
-
: ""}
|
|
1158
|
-
<div class="trendHistoryStats">
|
|
1159
|
-
<span><strong>${tests.length}</strong> ejecuciones</span>
|
|
1160
|
-
<
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1204
|
+
${rerunFeedback
|
|
1205
|
+
? `<div class="trendRerunFeedback ${rerun.status === "failed" || rerun.status === "unavailable" ? "error" : "success"}" role="status">${escapeHtml(rerunFeedback)}</div>`
|
|
1206
|
+
: ""}
|
|
1207
|
+
<div class="trendHistoryStats">
|
|
1208
|
+
<span class="historicalExecutionCount"><strong>${tests.length}</strong> ejecuciones</span>
|
|
1209
|
+
<div class="historicalStatusFilters" aria-label="Filtrar pruebas históricas por estado">
|
|
1210
|
+
${visibleStatuses.map(([status, count]) => `<button
|
|
1211
|
+
class="historicalStatusFilter ${escapeHtml(status)} ${state.historicalStatusFilter === status ? "active" : ""}"
|
|
1212
|
+
type="button"
|
|
1213
|
+
data-historical-status-filter="${escapeHtml(status)}"
|
|
1214
|
+
aria-pressed="${state.historicalStatusFilter === status}"
|
|
1215
|
+
><strong>${escapeHtml(count)}</strong> ${escapeHtml(statusLabel[status] || status)}</button>`).join("")}
|
|
1216
|
+
</div>
|
|
1217
|
+
</div>
|
|
1218
|
+
<div class="historicalTestList">
|
|
1219
|
+
${filteredTests.length
|
|
1220
|
+
? filteredTests.map((test) => `<article class="historicalTestRow">
|
|
1167
1221
|
<span class="statusDot ${escapeHtml(test.status)}" aria-hidden="true"></span>
|
|
1168
1222
|
<span>
|
|
1169
1223
|
<strong>${escapeHtml(test.title)}</strong>
|
|
@@ -1176,7 +1230,7 @@
|
|
|
1176
1230
|
<small>${escapeHtml(formatDuration(test.duration_ms))}</small>
|
|
1177
1231
|
</span>
|
|
1178
1232
|
</article>`).join("")
|
|
1179
|
-
: `<div class="emptyState"><strong>Sin resultados</strong><span>Esta corrida no tiene pruebas registradas.</span></div>`}
|
|
1233
|
+
: `<div class="emptyState"><strong>Sin resultados</strong><span>Esta corrida no tiene pruebas registradas.</span></div>`}
|
|
1180
1234
|
</div>
|
|
1181
1235
|
</section>`;
|
|
1182
1236
|
}
|
|
@@ -1205,11 +1259,20 @@
|
|
|
1205
1259
|
const closeButton = document.querySelector("[data-close-trend-history]");
|
|
1206
1260
|
if (!closeButton) return;
|
|
1207
1261
|
closeButton.addEventListener("click", () => {
|
|
1208
|
-
state.selectedTrendRunId = null;
|
|
1209
|
-
state.historicalRun = null;
|
|
1210
|
-
state.historicalRerun = null;
|
|
1211
|
-
|
|
1212
|
-
|
|
1262
|
+
state.selectedTrendRunId = null;
|
|
1263
|
+
state.historicalRun = null;
|
|
1264
|
+
state.historicalRerun = null;
|
|
1265
|
+
state.historicalStatusFilter = "";
|
|
1266
|
+
renderTrendArea();
|
|
1267
|
+
});
|
|
1268
|
+
document.querySelectorAll("[data-historical-status-filter]").forEach((button) => {
|
|
1269
|
+
button.addEventListener("click", () => {
|
|
1270
|
+
const status = button.dataset.historicalStatusFilter;
|
|
1271
|
+
state.historicalStatusFilter =
|
|
1272
|
+
state.historicalStatusFilter === status ? "" : status;
|
|
1273
|
+
renderTrendHistoryPanel();
|
|
1274
|
+
});
|
|
1275
|
+
});
|
|
1213
1276
|
document.querySelector("[data-rerun-trend-report]")?.addEventListener(
|
|
1214
1277
|
"click",
|
|
1215
1278
|
startHistoricalRerun,
|
|
@@ -1282,10 +1345,11 @@
|
|
|
1282
1345
|
function bindTrendEvents() {
|
|
1283
1346
|
document.querySelectorAll("[data-trend-run-id]").forEach((button) => {
|
|
1284
1347
|
button.addEventListener("click", async () => {
|
|
1285
|
-
const requestedRunId = button.dataset.trendRunId;
|
|
1286
|
-
state.selectedTrendRunId = requestedRunId;
|
|
1287
|
-
state.historicalRun = null;
|
|
1288
|
-
state.historicalRerun = null;
|
|
1348
|
+
const requestedRunId = button.dataset.trendRunId;
|
|
1349
|
+
state.selectedTrendRunId = requestedRunId;
|
|
1350
|
+
state.historicalRun = null;
|
|
1351
|
+
state.historicalRerun = null;
|
|
1352
|
+
state.historicalStatusFilter = "";
|
|
1289
1353
|
renderTrendArea();
|
|
1290
1354
|
|
|
1291
1355
|
try {
|
|
@@ -1312,9 +1376,10 @@
|
|
|
1312
1376
|
|
|
1313
1377
|
async function loadTrendEnvironment(environment) {
|
|
1314
1378
|
state.trendEnvironment = environment;
|
|
1315
|
-
state.selectedTrendRunId = null;
|
|
1316
|
-
state.historicalRun = null;
|
|
1317
|
-
state.historicalRerun = null;
|
|
1379
|
+
state.selectedTrendRunId = null;
|
|
1380
|
+
state.historicalRun = null;
|
|
1381
|
+
state.historicalRerun = null;
|
|
1382
|
+
state.historicalStatusFilter = "";
|
|
1318
1383
|
const trendContent = document.getElementById("trend-content");
|
|
1319
1384
|
const trendHistory = document.getElementById("trend-history");
|
|
1320
1385
|
const trendCounter = document.getElementById("trend-run-count");
|
|
@@ -2559,35 +2624,35 @@
|
|
|
2559
2624
|
}
|
|
2560
2625
|
|
|
2561
2626
|
const viewMetadata = {
|
|
2562
|
-
overview: {
|
|
2563
|
-
label: "Resumen",
|
|
2564
|
-
description: "Estado de la corrida y señales que requieren atención.",
|
|
2565
|
-
icon: "
|
|
2566
|
-
},
|
|
2627
|
+
overview: {
|
|
2628
|
+
label: "Resumen",
|
|
2629
|
+
description: "Estado de la corrida y señales que requieren atención.",
|
|
2630
|
+
icon: "summary.png",
|
|
2631
|
+
},
|
|
2567
2632
|
executions: {
|
|
2568
2633
|
label: "Ejecuciones",
|
|
2569
2634
|
description: "Tendencias, historial y comparación entre corridas.",
|
|
2570
|
-
icon: "
|
|
2635
|
+
icon: "executions.png",
|
|
2571
2636
|
},
|
|
2572
2637
|
quality: {
|
|
2573
2638
|
label: "Calidad",
|
|
2574
2639
|
description: "Estabilidad, fallos recurrentes y rendimiento histórico.",
|
|
2575
|
-
icon: "
|
|
2640
|
+
icon: "quality.png",
|
|
2576
2641
|
},
|
|
2577
2642
|
analysis: {
|
|
2578
2643
|
label: "Análisis",
|
|
2579
2644
|
description: "Bandeja de trabajo para investigar y clasificar fallos.",
|
|
2580
|
-
icon: "
|
|
2645
|
+
icon: "analysis.png",
|
|
2581
2646
|
},
|
|
2582
2647
|
tests: {
|
|
2583
2648
|
label: "Pruebas",
|
|
2584
2649
|
description: "Explorador de casos, pasos, evidencias e historial por Jira.",
|
|
2585
|
-
icon: "
|
|
2650
|
+
icon: "tests.png",
|
|
2586
2651
|
},
|
|
2587
2652
|
preferences: {
|
|
2588
2653
|
label: "Preferencias",
|
|
2589
2654
|
description: "Apariencia y configuración local del espacio de trabajo.",
|
|
2590
|
-
icon: "
|
|
2655
|
+
icon: "preferences.png",
|
|
2591
2656
|
},
|
|
2592
2657
|
};
|
|
2593
2658
|
|
|
@@ -2747,7 +2812,9 @@
|
|
|
2747
2812
|
aria-current="${state.view === key ? "page" : "false"}"
|
|
2748
2813
|
title="${escapeHtml(item.label)}"
|
|
2749
2814
|
>
|
|
2750
|
-
<span class="sidebarIcon" aria-hidden="true"
|
|
2815
|
+
<span class="sidebarIcon" aria-hidden="true">
|
|
2816
|
+
<img class="sidebarIconImage" src="assets/menu-icons/${escapeHtml(item.icon)}" alt="">
|
|
2817
|
+
</span>
|
|
2751
2818
|
<span class="sidebarLabel">${escapeHtml(item.label)}</span>
|
|
2752
2819
|
${badges[key] ? `<span class="sidebarBadge">${escapeHtml(badges[key])}</span>` : ""}
|
|
2753
2820
|
</button>`).join("")}
|
|
@@ -2759,20 +2826,22 @@
|
|
|
2759
2826
|
</aside>`;
|
|
2760
2827
|
}
|
|
2761
2828
|
|
|
2762
|
-
function overviewLaunchpadMarkup() {
|
|
2763
|
-
const failed = run.tests.filter((test) => effectiveTestStatus(test) === "failed");
|
|
2764
|
-
const withoutComment = failed.filter((test) => !annotationFor(test).comment).length;
|
|
2765
|
-
|
|
2829
|
+
function overviewLaunchpadMarkup() {
|
|
2830
|
+
const failed = run.tests.filter((test) => effectiveTestStatus(test) === "failed");
|
|
2831
|
+
const withoutComment = failed.filter((test) => !annotationFor(test).comment).length;
|
|
2832
|
+
const launchIcon = (view) =>
|
|
2833
|
+
`<img class="overviewLaunchIcon" src="assets/menu-icons/${escapeHtml(viewMetadata[view].icon)}" alt="">`;
|
|
2834
|
+
return `<section class="overviewLaunchpad" aria-labelledby="overview-next-title">
|
|
2766
2835
|
<header>
|
|
2767
2836
|
<div><p class="eyebrow">Explorar</p><h2 id="overview-next-title">Continuá el análisis</h2></div>
|
|
2768
2837
|
<span>Cada área conserva el ambiente, los filtros y la prueba seleccionada.</span>
|
|
2769
|
-
</header>
|
|
2770
|
-
<div class="overviewLaunchGrid">
|
|
2771
|
-
<button type="button" data-nav-view="executions"
|
|
2772
|
-
<button type="button" data-nav-view="quality"
|
|
2773
|
-
<button type="button" data-nav-view="analysis"
|
|
2774
|
-
<button type="button" data-nav-view="tests"
|
|
2775
|
-
</div>
|
|
2838
|
+
</header>
|
|
2839
|
+
<div class="overviewLaunchGrid">
|
|
2840
|
+
<button type="button" data-nav-view="executions">${launchIcon("executions")}<strong>Ejecuciones</strong><small>${escapeHtml(run.trends?.totalRuns || 0)} corridas disponibles</small></button>
|
|
2841
|
+
<button type="button" data-nav-view="quality">${launchIcon("quality")}<strong>Calidad histórica</strong><small>Estabilidad, recurrencia y tiempos</small></button>
|
|
2842
|
+
<button type="button" data-nav-view="analysis">${launchIcon("analysis")}<strong>Análisis pendiente</strong><small>${withoutComment} fallos sin comentario</small></button>
|
|
2843
|
+
<button type="button" data-nav-view="tests">${launchIcon("tests")}<strong>Explorar pruebas</strong><small>${run.tests.length} ejecuciones en la corrida</small></button>
|
|
2844
|
+
</div>
|
|
2776
2845
|
</section>`;
|
|
2777
2846
|
}
|
|
2778
2847
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/finalize.cjs
CHANGED
|
@@ -435,7 +435,7 @@ function persistRun(database, run) {
|
|
|
435
435
|
system: run.system || {},
|
|
436
436
|
source: run.source || {},
|
|
437
437
|
execution: run.execution || null,
|
|
438
|
-
reporterVersion: "2.0.0-beta.
|
|
438
|
+
reporterVersion: "2.0.0-beta.9",
|
|
439
439
|
}),
|
|
440
440
|
],
|
|
441
441
|
);
|
|
@@ -932,7 +932,7 @@ async function finalizeRun(options = {}) {
|
|
|
932
932
|
if (!run) throw new Error(`No se encontró ${rawPath}`);
|
|
933
933
|
|
|
934
934
|
run.schemaVersion = DATABASE_SCHEMA_VERSION;
|
|
935
|
-
run.reporterVersion = "2.0.0-beta.
|
|
935
|
+
run.reporterVersion = "2.0.0-beta.9";
|
|
936
936
|
run.lifecycle = run.lifecycle || "completed";
|
|
937
937
|
run.source = run.source || {
|
|
938
938
|
branch: process.env.CI_COMMIT_REF_NAME || "",
|
package/jira.cjs
CHANGED
|
@@ -303,12 +303,12 @@ async function jiraRequest(config, pathname, options = {}) {
|
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
async function findMatchingIssues(config, fingerprint) {
|
|
306
|
-
const
|
|
306
|
+
const conditions = [
|
|
307
307
|
`project = "${config.projectKey}"`,
|
|
308
308
|
`issuetype = "${config.issueTypeName}"`,
|
|
309
309
|
`labels = "${fingerprint}"`,
|
|
310
|
-
"ORDER BY created DESC",
|
|
311
310
|
].join(" AND ");
|
|
311
|
+
const jql = `${conditions} ORDER BY created DESC`;
|
|
312
312
|
const query = new URLSearchParams({
|
|
313
313
|
jql,
|
|
314
314
|
fields: "summary,status,labels",
|
package/package.json
CHANGED
package/plugin.cjs
CHANGED
|
@@ -57,7 +57,7 @@ function registerElmuloReporter(on, config, options = {}) {
|
|
|
57
57
|
"unknown",
|
|
58
58
|
tagExpression: config.env?.TAGS || process.env.CYPRESS_TAGS || "",
|
|
59
59
|
lifecycle: "running",
|
|
60
|
-
reporterVersion: "2.0.0-beta.
|
|
60
|
+
reporterVersion: "2.0.0-beta.9",
|
|
61
61
|
execution: executionScript
|
|
62
62
|
? { runner: "npm", script: executionScript, args: executionArgs }
|
|
63
63
|
: null,
|
package/server.cjs
CHANGED
|
@@ -182,7 +182,7 @@ async function serveReport(options = {}) {
|
|
|
182
182
|
if (request.method === "GET" && url.pathname === "/api/health") {
|
|
183
183
|
sendJson(response, 200, {
|
|
184
184
|
ok: true,
|
|
185
|
-
version: "2.0.0-beta.
|
|
185
|
+
version: "2.0.0-beta.9",
|
|
186
186
|
schemaVersion: 3,
|
|
187
187
|
});
|
|
188
188
|
return;
|