playwright-reborn 0.2.1 → 0.2.3
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/CHANGELOG.md +22 -0
- package/README.md +36 -9
- package/dist/fixture.js +4 -3
- package/dist/fixture.js.map +1 -1
- package/dist/format.js +15 -2
- package/dist/format.js.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/info.d.ts +1 -0
- package/dist/info.js +10 -0
- package/dist/info.js.map +1 -1
- package/dist/model.d.ts +8 -0
- package/dist/options.d.ts +17 -1
- package/dist/options.js +48 -4
- package/dist/options.js.map +1 -1
- package/dist/paths.js +19 -11
- package/dist/paths.js.map +1 -1
- package/dist/render.js +42 -24
- package/dist/render.js.map +1 -1
- package/dist/serialize.d.ts +9 -1
- package/dist/serialize.js +40 -9
- package/dist/serialize.js.map +1 -1
- package/dist/status.js +4 -4
- package/dist/status.js.map +1 -1
- package/dist/ui/report.css +142 -84
- package/dist/ui/report.js +300 -193
- package/package.json +4 -3
package/dist/ui/report.js
CHANGED
|
@@ -17,20 +17,22 @@
|
|
|
17
17
|
var TABS = ['overview', 'tests', 'screenshots'];
|
|
18
18
|
if (data.showLogs !== false) TABS.push('logs');
|
|
19
19
|
if (data.showFiles !== false) TABS.push('files');
|
|
20
|
+
var testIndex = new Map(data.tests.map(function (test) { return [test.id, test]; }));
|
|
20
21
|
var route = readRoute();
|
|
21
22
|
var state = {
|
|
22
23
|
tab: route.tab,
|
|
23
24
|
filter: 'all',
|
|
24
25
|
query: '',
|
|
25
|
-
selectedId: route.id
|
|
26
|
+
selectedId: testIndex.has(route.id) ? route.id : initialFailure(),
|
|
26
27
|
attempt: 0,
|
|
27
28
|
showApi: false,
|
|
28
29
|
testPane: 'steps',
|
|
29
30
|
listLimit: 200,
|
|
31
|
+
timelineLimit: 200,
|
|
30
32
|
shotFilter: 'all',
|
|
31
33
|
logQuery: '',
|
|
32
|
-
tag:
|
|
33
|
-
projectFilter:
|
|
34
|
+
tag: null,
|
|
35
|
+
projectFilter: null,
|
|
34
36
|
overview: data.overview === 'timeline' ? 'timeline' : 'chart',
|
|
35
37
|
order: 'grouped',
|
|
36
38
|
band: 'all',
|
|
@@ -49,7 +51,7 @@
|
|
|
49
51
|
'<div class="shell">',
|
|
50
52
|
'<aside class="rail">',
|
|
51
53
|
'<div class="tabbar" role="tablist" aria-label="Report">',
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
TABS.map(function (id) {
|
|
54
56
|
return tabButton(id, id.charAt(0).toUpperCase() + id.slice(1));
|
|
55
57
|
}).join(''),
|
|
@@ -70,17 +72,18 @@
|
|
|
70
72
|
document.body.dataset.accent = accentName();
|
|
71
73
|
document.title = companyName() + (data.summary ? ' · ' + data.summary : '');
|
|
72
74
|
fill(document.getElementById('meta'), metaBits().map(function (bit) { return el('span', null, [bit]); }));
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
var footBits = [];
|
|
76
|
+
if (data.showCredit === true) footBits.push(el('span', null, ['Open source by World of Z']));
|
|
77
|
+
footBits.push(el('span', null, [formatWhen(data.generatedAt)]));
|
|
78
|
+
footBits.push(el('span', null, ['Keys 1 onward switch pages. Press / to find a test.']));
|
|
79
|
+
fill(document.getElementById('foot'), footBits);
|
|
78
80
|
var BANDS = [
|
|
79
81
|
['under1', 'Under 1 minute'],
|
|
80
82
|
['1to3', '1 to 3 minutes'],
|
|
81
83
|
['3to5', '3 to 5 minutes'],
|
|
82
84
|
['over5', 'Over 5 minutes'],
|
|
83
85
|
];
|
|
86
|
+
var CHART_COLORS = ['var(--accent)', 'rgba(255,255,255,0.72)', 'rgba(255,255,255,0.42)', 'rgba(255,255,255,0.18)'];
|
|
84
87
|
|
|
85
88
|
paintOverview();
|
|
86
89
|
showTab(state.tab, true);
|
|
@@ -92,6 +95,7 @@
|
|
|
92
95
|
var canvas = document.querySelector('.atmosphere .bands');
|
|
93
96
|
if (!canvas || !canvas.getContext) return;
|
|
94
97
|
var ctx = canvas.getContext('2d');
|
|
98
|
+
if (!ctx) return;
|
|
95
99
|
var ratio = 1;
|
|
96
100
|
var columns = [];
|
|
97
101
|
var count = 22;
|
|
@@ -118,9 +122,9 @@
|
|
|
118
122
|
var t = reduce ? 8 : now / 1000;
|
|
119
123
|
ctx.clearRect(0, 0, w, h);
|
|
120
124
|
var wash = ctx.createLinearGradient(0, 0, 0, h);
|
|
121
|
-
wash.addColorStop(0, '
|
|
122
|
-
wash.addColorStop(0.42, '#
|
|
123
|
-
wash.addColorStop(1, '#
|
|
125
|
+
wash.addColorStop(0, 'rgba(' + rgb + ', 0.10)');
|
|
126
|
+
wash.addColorStop(0.42, '#080b0a');
|
|
127
|
+
wash.addColorStop(1, '#080808');
|
|
124
128
|
ctx.fillStyle = wash;
|
|
125
129
|
ctx.fillRect(0, 0, w, h);
|
|
126
130
|
columns.forEach(function (column) {
|
|
@@ -138,11 +142,16 @@
|
|
|
138
142
|
ctx.fillStyle = gradient;
|
|
139
143
|
ctx.fillRect(x - spread, 0, spread * 2, h * 0.92);
|
|
140
144
|
});
|
|
141
|
-
if (!reduce) requestAnimationFrame(draw);
|
|
145
|
+
if (!reduce && !document.hidden) curtainFrame = requestAnimationFrame(draw);
|
|
142
146
|
}
|
|
147
|
+
var curtainFrame = 0;
|
|
143
148
|
resize();
|
|
144
|
-
window.addEventListener('resize', resize);
|
|
145
|
-
|
|
149
|
+
window.addEventListener('resize', function () { resize(); if (reduce) draw(0); });
|
|
150
|
+
document.addEventListener('visibilitychange', function () {
|
|
151
|
+
cancelAnimationFrame(curtainFrame);
|
|
152
|
+
if (!document.hidden) curtainFrame = requestAnimationFrame(draw);
|
|
153
|
+
});
|
|
154
|
+
curtainFrame = requestAnimationFrame(function (now) {
|
|
146
155
|
if (!canvas.width) resize();
|
|
147
156
|
draw(now);
|
|
148
157
|
});
|
|
@@ -151,13 +160,14 @@
|
|
|
151
160
|
function watchHeader() {
|
|
152
161
|
var rail = document.querySelector('.rail');
|
|
153
162
|
if (!rail) return;
|
|
163
|
+
rail.addEventListener('focusin', function () { rail.classList.remove('is-hidden'); });
|
|
154
164
|
var lastY = window.scrollY;
|
|
155
165
|
window.addEventListener('scroll', function () {
|
|
156
166
|
var y = window.scrollY;
|
|
157
167
|
var down = y > lastY + 6;
|
|
158
168
|
var up = y < lastY - 6;
|
|
159
169
|
if (y < 24) rail.classList.remove('is-hidden');
|
|
160
|
-
else if (down) rail.classList.add('is-hidden');
|
|
170
|
+
else if (down && !rail.contains(document.activeElement)) rail.classList.add('is-hidden');
|
|
161
171
|
else if (up) rail.classList.remove('is-hidden');
|
|
162
172
|
lastY = y;
|
|
163
173
|
}, { passive: true });
|
|
@@ -184,16 +194,17 @@
|
|
|
184
194
|
}
|
|
185
195
|
|
|
186
196
|
function tabButton(id, label) {
|
|
187
|
-
return '<button class="tab" role="tab" type="button" data-tab="' + id + '" aria-selected="false" aria-controls="panel-' + id + '">' + label + '</button>';
|
|
197
|
+
return '<button id="tab-' + id + '" class="tab" role="tab" type="button" data-tab="' + id + '" aria-selected="false" aria-controls="panel-' + id + '">' + label + '</button>';
|
|
188
198
|
}
|
|
189
199
|
|
|
190
200
|
function readRoute() {
|
|
191
|
-
var hash =
|
|
192
|
-
try {
|
|
193
|
-
|
|
201
|
+
var hash = location.hash.slice(1);
|
|
202
|
+
try {
|
|
203
|
+
if (hash.indexOf('tests/') === 0) return { tab: 'tests', id: decodeURIComponent(hash.slice(6)) };
|
|
204
|
+
hash = decodeURIComponent(hash);
|
|
205
|
+
} catch (error) { return { tab: 'overview' }; }
|
|
194
206
|
if (TABS.indexOf(hash) !== -1) return { tab: hash };
|
|
195
|
-
if (
|
|
196
|
-
if (data.tests.some(function (test) { return test.id === hash; })) return { tab: 'tests', id: hash };
|
|
207
|
+
if (testIndex.has(hash)) return { tab: 'tests', id: hash };
|
|
197
208
|
return { tab: 'overview' };
|
|
198
209
|
}
|
|
199
210
|
|
|
@@ -207,11 +218,13 @@
|
|
|
207
218
|
state.tab = tab;
|
|
208
219
|
document.querySelectorAll('[role="tab"]').forEach(function (button) {
|
|
209
220
|
button.setAttribute('aria-selected', button.dataset.tab === tab ? 'true' : 'false');
|
|
221
|
+
button.tabIndex = button.dataset.tab === tab ? 0 : -1;
|
|
210
222
|
});
|
|
211
223
|
TABS.forEach(function (name) {
|
|
212
224
|
var panel = document.getElementById('panel-' + name);
|
|
213
225
|
var on = name === tab;
|
|
214
226
|
panel.hidden = !on;
|
|
227
|
+
panel.setAttribute('aria-labelledby', 'tab-' + name);
|
|
215
228
|
panel.classList.toggle('panel', true);
|
|
216
229
|
if (on && !quiet && !reduce) {
|
|
217
230
|
panel.classList.remove('panel-enter');
|
|
@@ -223,33 +236,26 @@
|
|
|
223
236
|
if (tab === 'screenshots') ensureShots();
|
|
224
237
|
if (tab === 'logs') ensureLogs();
|
|
225
238
|
if (tab === 'files') ensureFiles();
|
|
226
|
-
writeHash();
|
|
227
|
-
|
|
239
|
+
writeHash(!quiet);
|
|
240
|
+
|
|
228
241
|
}
|
|
229
242
|
|
|
230
|
-
function writeHash() {
|
|
243
|
+
function writeHash(push) {
|
|
231
244
|
var next = state.tab === 'overview' ? 'overview' : state.tab;
|
|
232
245
|
if (state.tab === 'tests' && state.selectedId) next = 'tests/' + encodeURIComponent(state.selectedId);
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
var glow = document.getElementById('tab-glow');
|
|
239
|
-
var active = document.querySelector('.tab[aria-selected="true"]');
|
|
240
|
-
if (!bar || !glow || !active) return;
|
|
241
|
-
var barBox = bar.getBoundingClientRect();
|
|
242
|
-
var box = active.getBoundingClientRect();
|
|
243
|
-
glow.style.width = box.width + 'px';
|
|
244
|
-
glow.style.transform = 'translateX(' + (box.left - barBox.left - 4) + 'px)';
|
|
246
|
+
if (location.hash === '#' + next) return;
|
|
247
|
+
if (window.history && history.replaceState) {
|
|
248
|
+
var url = location.protocol === 'about:' ? location.href.split('#')[0] + '#' + next : '#' + next;
|
|
249
|
+
try { history[push ? 'pushState' : 'replaceState'](null, '', url); } catch (error) { /* Some artifact viewers block history updates. */ }
|
|
250
|
+
}
|
|
245
251
|
}
|
|
246
252
|
|
|
247
253
|
function paintOverview() {
|
|
248
254
|
var host = document.getElementById('panel-overview');
|
|
249
255
|
host.innerHTML = [
|
|
250
256
|
'<header class="hero">',
|
|
251
|
-
'<div><h1 class="word" id="word"></h1><p class="
|
|
252
|
-
'<p class="
|
|
257
|
+
'<div><h1 class="word" id="word"></h1><p class="product" id="product"></p><p class="summary" id="summary"></p></div>',
|
|
258
|
+
'<p class="run-state" id="run-state"></p>',
|
|
253
259
|
'</header>',
|
|
254
260
|
'<div id="errors"></div>',
|
|
255
261
|
'<dl class="info" id="info"></dl>',
|
|
@@ -265,22 +271,27 @@
|
|
|
265
271
|
'</div>',
|
|
266
272
|
'</div>',
|
|
267
273
|
'<p class="section-note" id="range-note"></p>',
|
|
268
|
-
'<div class="
|
|
274
|
+
'<div class="charts" id="duration"></div>',
|
|
269
275
|
'<div class="strip-window" id="strip-window"><div class="strip-scroll"><div class="strip" id="strip" role="group" aria-label="Tests by time"></div></div></div>',
|
|
270
276
|
'</div>',
|
|
271
277
|
'</section>',
|
|
272
278
|
].join('');
|
|
273
279
|
var word = document.getElementById('word');
|
|
274
280
|
word.textContent = companyName();
|
|
281
|
+
var product = document.getElementById('product');
|
|
282
|
+
var subtitle = typeof data.productSubtitle === 'string' ? data.productSubtitle.trim() : 'Test Automation';
|
|
283
|
+
if (subtitle) product.textContent = subtitle;
|
|
284
|
+
else product.hidden = true;
|
|
275
285
|
document.getElementById('summary').textContent = data.summary || '';
|
|
276
|
-
|
|
286
|
+
var runState = document.getElementById('run-state');
|
|
287
|
+
runState.dataset.status = data.status;
|
|
288
|
+
runState.textContent = { passed: 'Run passed', failed: 'Run failed', timedout: 'Run timed out', interrupted: 'Run interrupted' }[data.status] || 'Run finished';
|
|
277
289
|
paintErrors();
|
|
278
290
|
paintInfo();
|
|
279
291
|
paintCounts(document.getElementById('legend'), false);
|
|
280
292
|
paintDuration();
|
|
281
293
|
paintStrip();
|
|
282
294
|
applyOverview();
|
|
283
|
-
showNow(state.selectedId);
|
|
284
295
|
}
|
|
285
296
|
|
|
286
297
|
function paintInfo() {
|
|
@@ -317,29 +328,125 @@
|
|
|
317
328
|
return data.tests.filter(function (test) { return test.status !== 'skipped'; });
|
|
318
329
|
}
|
|
319
330
|
|
|
320
|
-
function
|
|
321
|
-
var host = document.getElementById('duration');
|
|
322
|
-
if (!host) return;
|
|
331
|
+
function bandCounts() {
|
|
323
332
|
var counts = { under1: 0, '1to3': 0, '3to5': 0, over5: 0 };
|
|
324
333
|
countedTests().forEach(function (test) {
|
|
325
334
|
counts[durationBand(test.duration)] += 1;
|
|
326
335
|
});
|
|
336
|
+
return counts;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function chartStyle() {
|
|
340
|
+
return data.chartStyle === 'pie' || data.chartStyle === 'bar' ? data.chartStyle : 'both';
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function polar(cx, cy, radius, degrees) {
|
|
344
|
+
var rad = (degrees - 90) * Math.PI / 180;
|
|
345
|
+
return { x: cx + radius * Math.cos(rad), y: cy + radius * Math.sin(rad) };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function piePath(start, end) {
|
|
349
|
+
var span = end - start;
|
|
350
|
+
if (span >= 359.99) return '';
|
|
351
|
+
var from = polar(110, 110, 96, start);
|
|
352
|
+
var to = polar(110, 110, 96, end);
|
|
353
|
+
var large = span > 180 ? 1 : 0;
|
|
354
|
+
return 'M 110 110 L ' + from.x.toFixed(2) + ' ' + from.y.toFixed(2) + ' A 96 96 0 ' + large + ' 1 ' + to.x.toFixed(2) + ' ' + to.y.toFixed(2) + ' Z';
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function paintPie(counts) {
|
|
358
|
+
var total = 0;
|
|
359
|
+
BANDS.forEach(function (band) { total += counts[band[0]]; });
|
|
360
|
+
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
361
|
+
svg.setAttribute('viewBox', '0 0 220 220');
|
|
362
|
+
svg.setAttribute('class', 'pie');
|
|
363
|
+
svg.setAttribute('role', 'img');
|
|
364
|
+
svg.setAttribute('aria-label', 'Tests by duration');
|
|
365
|
+
if (!total) {
|
|
366
|
+
var empty = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
|
|
367
|
+
empty.setAttribute('cx', '110');
|
|
368
|
+
empty.setAttribute('cy', '110');
|
|
369
|
+
empty.setAttribute('r', '96');
|
|
370
|
+
empty.setAttribute('fill', 'rgba(255,255,255,0.08)');
|
|
371
|
+
svg.appendChild(empty);
|
|
372
|
+
return svg;
|
|
373
|
+
}
|
|
374
|
+
var angle = 0;
|
|
375
|
+
var full = null;
|
|
376
|
+
BANDS.forEach(function (band, index) {
|
|
377
|
+
var count = counts[band[0]];
|
|
378
|
+
if (!count) return;
|
|
379
|
+
var sweep = (count / total) * 360;
|
|
380
|
+
if (sweep >= 359.99) {
|
|
381
|
+
full = index;
|
|
382
|
+
angle += sweep;
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
386
|
+
path.setAttribute('d', piePath(angle, angle + sweep));
|
|
387
|
+
path.setAttribute('fill', CHART_COLORS[index]);
|
|
388
|
+
path.setAttribute('data-slice', band[0]);
|
|
389
|
+
path.setAttribute('class', 'slice');
|
|
390
|
+
svg.appendChild(path);
|
|
391
|
+
angle += sweep;
|
|
392
|
+
});
|
|
393
|
+
if (full !== null) {
|
|
394
|
+
var circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
|
|
395
|
+
circle.setAttribute('cx', '110');
|
|
396
|
+
circle.setAttribute('cy', '110');
|
|
397
|
+
circle.setAttribute('r', '96');
|
|
398
|
+
circle.setAttribute('fill', CHART_COLORS[full]);
|
|
399
|
+
circle.setAttribute('data-slice', BANDS[full][0]);
|
|
400
|
+
circle.setAttribute('class', 'slice');
|
|
401
|
+
svg.appendChild(circle);
|
|
402
|
+
}
|
|
403
|
+
return svg;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function paintDuration() {
|
|
407
|
+
var host = document.getElementById('duration');
|
|
408
|
+
if (!host) return;
|
|
409
|
+
var counts = bandCounts();
|
|
327
410
|
var max = 1;
|
|
328
411
|
BANDS.forEach(function (band) { max = Math.max(max, counts[band[0]]); });
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
412
|
+
var style = chartStyle();
|
|
413
|
+
var nodes = [];
|
|
414
|
+
if (style !== 'bar') nodes.push(paintPie(counts));
|
|
415
|
+
if (style !== 'pie') {
|
|
416
|
+
nodes.push(el('div', { class: 'bars' }, BANDS.map(function (band, index) {
|
|
417
|
+
var fillBar = el('span', { class: 'band-fill' });
|
|
418
|
+
fillBar.style.width = Math.round((counts[band[0]] / max) * 100) + '%';
|
|
419
|
+
fillBar.style.background = CHART_COLORS[index];
|
|
420
|
+
return el('button', {
|
|
421
|
+
class: 'band',
|
|
422
|
+
type: 'button',
|
|
423
|
+
'data-band': band[0],
|
|
424
|
+
'aria-pressed': state.band === band[0] ? 'true' : 'false',
|
|
425
|
+
}, [
|
|
426
|
+
el('span', { class: 'swatch' }),
|
|
427
|
+
el('span', { class: 'band-label' }, [band[1]]),
|
|
428
|
+
el('span', { class: 'n' }, [String(counts[band[0]])]),
|
|
429
|
+
el('span', { class: 'band-track' }, [fillBar]),
|
|
430
|
+
]);
|
|
431
|
+
})));
|
|
432
|
+
} else {
|
|
433
|
+
nodes.push(el('div', { class: 'bars' }, BANDS.map(function (band, index) {
|
|
434
|
+
return el('button', {
|
|
435
|
+
class: 'band band-key',
|
|
436
|
+
type: 'button',
|
|
437
|
+
'data-band': band[0],
|
|
438
|
+
'aria-pressed': state.band === band[0] ? 'true' : 'false',
|
|
439
|
+
}, [
|
|
440
|
+
el('span', { class: 'swatch' }),
|
|
441
|
+
el('span', { class: 'band-label' }, [band[1]]),
|
|
442
|
+
el('span', { class: 'n' }, [String(counts[band[0]])]),
|
|
443
|
+
]);
|
|
444
|
+
})));
|
|
445
|
+
}
|
|
446
|
+
fill(host, nodes);
|
|
447
|
+
host.querySelectorAll('.swatch').forEach(function (swatch, index) {
|
|
448
|
+
swatch.style.background = CHART_COLORS[index % CHART_COLORS.length];
|
|
449
|
+
});
|
|
343
450
|
}
|
|
344
451
|
|
|
345
452
|
function applyOverview() {
|
|
@@ -378,7 +485,7 @@
|
|
|
378
485
|
function paintCounts(host, withFind) {
|
|
379
486
|
var counts = data.counts || {};
|
|
380
487
|
var filters = [
|
|
381
|
-
['all', '
|
|
488
|
+
['all', 'tests', counts.total || 0],
|
|
382
489
|
['passed', 'passed', counts.passed || 0],
|
|
383
490
|
['failed', 'failed', counts.failed || 0],
|
|
384
491
|
['flaky', 'flaky', counts.flaky || 0],
|
|
@@ -416,7 +523,7 @@
|
|
|
416
523
|
}
|
|
417
524
|
|
|
418
525
|
function syncPressed() {
|
|
419
|
-
document.querySelectorAll('.count').forEach(function (button) {
|
|
526
|
+
document.querySelectorAll('.count[data-status]').forEach(function (button) {
|
|
420
527
|
button.setAttribute('aria-pressed', button.dataset.status === state.filter ? 'true' : 'false');
|
|
421
528
|
});
|
|
422
529
|
}
|
|
@@ -437,7 +544,7 @@
|
|
|
437
544
|
function paintStrip() {
|
|
438
545
|
var strip = document.getElementById('strip');
|
|
439
546
|
if (!data.tests.length) {
|
|
440
|
-
fill(strip, []);
|
|
547
|
+
fill(strip, [el('p', { class: 'empty' }, ['No tests ran.'])]);
|
|
441
548
|
return;
|
|
442
549
|
}
|
|
443
550
|
var max = data.tests.reduce(function (hi, test) { return Math.max(hi, test.duration || 0); }, 1);
|
|
@@ -446,7 +553,7 @@
|
|
|
446
553
|
});
|
|
447
554
|
strip.className = 'run-list';
|
|
448
555
|
strip.style.height = '';
|
|
449
|
-
|
|
556
|
+
var nodes = ordered.slice(0, state.timelineLimit).map(function (test) {
|
|
450
557
|
var fillBar = el('span', { class: 'run-fill', 'data-status': test.status });
|
|
451
558
|
fillBar.style.width = Math.max(2, Math.round(((test.duration || 0) / max) * 100)) + '%';
|
|
452
559
|
return el('button', {
|
|
@@ -461,51 +568,10 @@
|
|
|
461
568
|
el('span', { class: 'run-track' }, [fillBar]),
|
|
462
569
|
el('span', { class: 'run-time' }, [formatDuration(test.duration)]),
|
|
463
570
|
]);
|
|
464
|
-
}));
|
|
465
|
-
markStrip();
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
function paintCanvasStrip(host) {
|
|
469
|
-
var canvas = el('canvas', { class: 'strip-canvas', 'aria-label': 'Tests by duration' });
|
|
470
|
-
fill(host, [canvas]);
|
|
471
|
-
var hits = [];
|
|
472
|
-
function draw() {
|
|
473
|
-
var width = host.clientWidth || 600;
|
|
474
|
-
var height = 52;
|
|
475
|
-
var ratio = window.devicePixelRatio || 1;
|
|
476
|
-
canvas.width = Math.floor(width * ratio);
|
|
477
|
-
canvas.height = Math.floor(height * ratio);
|
|
478
|
-
canvas.style.width = width + 'px';
|
|
479
|
-
canvas.style.height = height + 'px';
|
|
480
|
-
var ctx = canvas.getContext('2d');
|
|
481
|
-
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
|
|
482
|
-
ctx.clearRect(0, 0, width, height);
|
|
483
|
-
var total = data.tests.reduce(function (sum, test) { return sum + Math.max(test.duration || 0, 1); }, 0);
|
|
484
|
-
var x = 0;
|
|
485
|
-
hits = [];
|
|
486
|
-
data.tests.forEach(function (test) {
|
|
487
|
-
var w = Math.max(2, (Math.max(test.duration || 0, 1) / total) * width);
|
|
488
|
-
ctx.fillStyle = canvasColor(test.status);
|
|
489
|
-
ctx.fillRect(x, 8, Math.max(1, w - 2), 36);
|
|
490
|
-
hits.push({ x: x, w: w, id: test.id });
|
|
491
|
-
x += w;
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
draw();
|
|
495
|
-
window.addEventListener('resize', draw);
|
|
496
|
-
canvas.addEventListener('mousemove', function (event) {
|
|
497
|
-
var rect = canvas.getBoundingClientRect();
|
|
498
|
-
var x = event.clientX - rect.left;
|
|
499
|
-
var hit = hits.find(function (item) { return x >= item.x && x < item.x + item.w; });
|
|
500
|
-
if (hit) showNow(hit.id);
|
|
501
|
-
});
|
|
502
|
-
canvas.addEventListener('mouseleave', function () { showNow(state.selectedId); });
|
|
503
|
-
canvas.addEventListener('click', function (event) {
|
|
504
|
-
var rect = canvas.getBoundingClientRect();
|
|
505
|
-
var x = event.clientX - rect.left;
|
|
506
|
-
var hit = hits.find(function (item) { return x >= item.x && x < item.x + item.w; });
|
|
507
|
-
if (hit) choose(hit.id, true);
|
|
508
571
|
});
|
|
572
|
+
if (ordered.length > state.timelineLimit) nodes.push(el('button', { class: 'more', type: 'button', id: 'show-more-timeline' }, ['Show more tests']));
|
|
573
|
+
fill(strip, nodes);
|
|
574
|
+
markStrip();
|
|
509
575
|
}
|
|
510
576
|
|
|
511
577
|
function canvasColor(status) {
|
|
@@ -516,7 +582,7 @@
|
|
|
516
582
|
}
|
|
517
583
|
|
|
518
584
|
function markStrip() {
|
|
519
|
-
var visible =
|
|
585
|
+
var visible = Object.create(null);
|
|
520
586
|
filteredTests().forEach(function (test) { visible[test.id] = true; });
|
|
521
587
|
document.querySelectorAll('.run-row').forEach(function (segment) {
|
|
522
588
|
segment.classList.toggle('is-dim', !visible[segment.dataset.id]);
|
|
@@ -525,8 +591,18 @@
|
|
|
525
591
|
});
|
|
526
592
|
}
|
|
527
593
|
|
|
594
|
+
function keptTag(tag) {
|
|
595
|
+
var pattern = typeof data.ignoreTags === 'string' ? data.ignoreTags : '^@?HC2T-';
|
|
596
|
+
if (!pattern) return true;
|
|
597
|
+
try {
|
|
598
|
+
return !new RegExp(pattern, 'i').test(tag);
|
|
599
|
+
} catch (error) {
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
528
604
|
function uniqueValues(pick) {
|
|
529
|
-
var seen =
|
|
605
|
+
var seen = Object.create(null);
|
|
530
606
|
data.tests.forEach(function (test) {
|
|
531
607
|
pick(test).forEach(function (value) {
|
|
532
608
|
if (value) seen[value] = true;
|
|
@@ -538,17 +614,17 @@
|
|
|
538
614
|
function paintTags() {
|
|
539
615
|
var host = document.getElementById('tags');
|
|
540
616
|
if (!host) return;
|
|
541
|
-
var tags = uniqueValues(function (test) { return test.tags || []; });
|
|
617
|
+
var tags = uniqueValues(function (test) { return (test.tags || []).filter(keptTag); });
|
|
542
618
|
var projects = uniqueValues(function (test) { return test.project ? [test.project] : []; });
|
|
543
619
|
var nodes = [];
|
|
544
620
|
if (tags.length) {
|
|
545
621
|
nodes.push(el('span', { class: 'order-label' }, ['Tags']));
|
|
546
|
-
nodes.push(chip('tag-btn', '
|
|
622
|
+
nodes.push(chip('tag-btn', '', 'All', state.tag || ''));
|
|
547
623
|
tags.forEach(function (tag) { nodes.push(chip('tag-btn', tag, tag, state.tag)); });
|
|
548
624
|
}
|
|
549
|
-
if (projects.length > 1) {
|
|
625
|
+
if (data.showProjectFilter === true && projects.length > 1) {
|
|
550
626
|
nodes.push(el('span', { class: 'order-label' }, ['Project']));
|
|
551
|
-
nodes.push(chip('project-btn', '
|
|
627
|
+
nodes.push(chip('project-btn', '', 'All', state.projectFilter || ''));
|
|
552
628
|
projects.forEach(function (project) { nodes.push(chip('project-btn', project, project, state.projectFilter)); });
|
|
553
629
|
}
|
|
554
630
|
host.hidden = nodes.length === 0;
|
|
@@ -600,7 +676,7 @@
|
|
|
600
676
|
if (built.tests) return;
|
|
601
677
|
built.tests = true;
|
|
602
678
|
var host = document.getElementById('panel-tests');
|
|
603
|
-
host.innerHTML = '<div class="legend" id="test-tools"></div><div class="tags" id="tags"></div><div class="order" id="order"></div><div class="split"><div id="tests"></div><section class="detail" id="detail"></section></div>';
|
|
679
|
+
host.innerHTML = '<h2 class="visually-hidden">Tests</h2><div class="legend" id="test-tools"></div><div class="tags" id="tags"></div><div class="order" id="order"></div><div class="list-summary" id="list-summary"></div><div class="split"><div id="tests"></div><section class="detail" id="detail"></section></div>';
|
|
604
680
|
paintCounts(document.getElementById('test-tools'), true);
|
|
605
681
|
paintTags();
|
|
606
682
|
paintOrder();
|
|
@@ -613,8 +689,13 @@
|
|
|
613
689
|
var host = document.getElementById('tests');
|
|
614
690
|
if (!host) return;
|
|
615
691
|
var tests = filteredTests();
|
|
692
|
+
var summary = document.getElementById('list-summary');
|
|
693
|
+
if (summary) fill(summary, [
|
|
694
|
+
el('span', { role: 'status', 'aria-live': 'polite' }, [tests.length + ' of ' + data.tests.length + ' tests']),
|
|
695
|
+
hasFilters() ? el('button', { type: 'button', class: 'reset-filters' }, ['Clear filters']) : null,
|
|
696
|
+
]);
|
|
616
697
|
if (!tests.length) {
|
|
617
|
-
fill(host, [el('p', { class: 'empty' }, [data.tests.length ? 'No tests match.' : 'No tests ran.'])]);
|
|
698
|
+
fill(host, [el('p', { class: 'empty' }, [data.tests.length ? 'No tests match. Clear filters or try another search.' : 'No tests ran.'])]);
|
|
618
699
|
return;
|
|
619
700
|
}
|
|
620
701
|
if (state.order !== 'grouped') {
|
|
@@ -622,20 +703,20 @@
|
|
|
622
703
|
var shown = sorted.slice(0, state.listLimit);
|
|
623
704
|
var flat = shown.map(function (test) { return rowButton(test, true); });
|
|
624
705
|
if (shown.length < sorted.length) {
|
|
625
|
-
flat.push(el('button', { class: 'more', type: 'button', id: 'show-rest' }, ['Show
|
|
706
|
+
flat.push(el('button', { class: 'more', type: 'button', id: 'show-rest' }, ['Show more tests']));
|
|
626
707
|
}
|
|
627
708
|
fill(host, flat);
|
|
628
709
|
return;
|
|
629
710
|
}
|
|
630
711
|
var groups = [];
|
|
631
|
-
var problemIds =
|
|
712
|
+
var problemIds = Object.create(null);
|
|
632
713
|
var problems = tests.filter(isProblem);
|
|
633
714
|
if (state.filter === 'all' && !state.query && problems.length && problems.length !== tests.length) {
|
|
634
715
|
problems.forEach(function (test) { problemIds[test.id] = true; });
|
|
635
716
|
groups.push({ name: 'Problems', tests: problems });
|
|
636
717
|
}
|
|
637
718
|
var byFile = [];
|
|
638
|
-
var index =
|
|
719
|
+
var index = Object.create(null);
|
|
639
720
|
tests.forEach(function (test) {
|
|
640
721
|
if (problemIds[test.id]) return;
|
|
641
722
|
if (index[test.file] == null) {
|
|
@@ -660,7 +741,7 @@
|
|
|
660
741
|
return el('div', { class: 'group' }, [el('p', { class: 'file-name' }, [group.name])].concat(rows));
|
|
661
742
|
}).filter(Boolean);
|
|
662
743
|
if (truncated) {
|
|
663
|
-
nodes.push(el('button', { class: 'more', type: 'button', id: 'show-rest' }, ['Show
|
|
744
|
+
nodes.push(el('button', { class: 'more', type: 'button', id: 'show-rest' }, ['Show more tests']));
|
|
664
745
|
}
|
|
665
746
|
fill(host, nodes);
|
|
666
747
|
}
|
|
@@ -694,7 +775,7 @@
|
|
|
694
775
|
['logs', 'Logs'],
|
|
695
776
|
['shots', 'Screenshots'],
|
|
696
777
|
];
|
|
697
|
-
var tabs = el('div', { class: 'subtabs', role: '
|
|
778
|
+
var tabs = el('div', { class: 'subtabs', role: 'group', 'aria-label': 'Test details' }, panes.map(function (pane) {
|
|
698
779
|
return el('button', {
|
|
699
780
|
class: 'subtab',
|
|
700
781
|
type: 'button',
|
|
@@ -705,6 +786,7 @@
|
|
|
705
786
|
var body = [headerBlock(test), tabs];
|
|
706
787
|
if (test.attempts.length > 1) body.push(attemptTabs(test));
|
|
707
788
|
if (attempt) body.push(paneBody(test, attempt));
|
|
789
|
+
else body.push(el('p', { class: 'empty block' }, ['This test did not run.']));
|
|
708
790
|
fill(host, [el('div', { class: 'detail-body' }, body)]);
|
|
709
791
|
}
|
|
710
792
|
|
|
@@ -720,7 +802,7 @@
|
|
|
720
802
|
if (test.group && test.group.length) bits.push(el('p', { class: 'kicker' }, [test.group.join(' / ')]));
|
|
721
803
|
bits.push(el('h2', null, [test.title]));
|
|
722
804
|
var where = [el('span', null, [test.file + ':' + test.line])];
|
|
723
|
-
if (test.project) where.push(el('span', null, [test.project]));
|
|
805
|
+
if (data.showProjects === true && test.project) where.push(el('span', null, [test.project]));
|
|
724
806
|
(test.tags || []).forEach(function (tag) { where.push(el('span', null, [tag])); });
|
|
725
807
|
bits.push(el('p', { class: 'where' }, where));
|
|
726
808
|
bits.push(el('p', { class: 'status-line' }, [
|
|
@@ -748,7 +830,8 @@
|
|
|
748
830
|
|
|
749
831
|
function errorBlock(attempt) {
|
|
750
832
|
if (!attempt.errors || !attempt.errors.length) return null;
|
|
751
|
-
var
|
|
833
|
+
var images = (attempt.attachments || []).filter(function (item) { return item.kind === 'image' && safeSrc(item.path); });
|
|
834
|
+
var image = images.find(function (item) { return item.role === 'failure'; }) || images[images.length - 1];
|
|
752
835
|
var messages = attempt.errors.map(function (error) {
|
|
753
836
|
var nodes = [el('pre', null, [error.message || 'The test failed.'])];
|
|
754
837
|
if (error.location) nodes.push(el('p', { class: 'where-error' }, [error.location]));
|
|
@@ -838,8 +921,9 @@
|
|
|
838
921
|
var src = safeSrc(file.path);
|
|
839
922
|
var copy = el('div', { class: 'tile-copy' }, [
|
|
840
923
|
el('p', { class: 'tile-title' }, [test.title]),
|
|
924
|
+
el('p', { class: 'tile-meta' }, ['Attempt ' + (index + 1) + ' · ' + attemptLabel(attempt.status)]),
|
|
841
925
|
el('p', { class: 'tile-meta' }, [file.stepTitle || file.name || 'Screenshot']),
|
|
842
|
-
el('button', { class: 'open-test', type: 'button', 'data-id': test.id, 'data-attempt': String(index) }, ['Open test']),
|
|
926
|
+
el('button', { class: 'open-test', type: 'button', 'data-id': test.id, 'data-attempt': String(index), 'data-open-pane': 'shots' }, ['Open test']),
|
|
843
927
|
]);
|
|
844
928
|
var tile = el('div', { class: 'tile', 'data-role': file.role || '', 'data-status': test.status }, [
|
|
845
929
|
el('button', { class: 'shot', type: 'button', 'data-src': src, 'data-alt': file.name || test.title }, [
|
|
@@ -903,7 +987,7 @@
|
|
|
903
987
|
];
|
|
904
988
|
if (attempt.stdout) nodes.push(el('div', { class: 'well' }, [el('p', null, ['Output']), el('pre', null, [attempt.stdout])]));
|
|
905
989
|
if (attempt.stderr) nodes.push(el('div', { class: 'well' }, [el('p', null, ['Error output']), el('pre', null, [attempt.stderr])]));
|
|
906
|
-
nodes.push(el('button', { class: 'open-test', type: 'button', 'data-id': test.id, 'data-attempt': String(index) }, ['Open test']));
|
|
990
|
+
nodes.push(el('button', { class: 'open-test', type: 'button', 'data-id': test.id, 'data-attempt': String(index), 'data-open-pane': 'logs' }, ['Open test']));
|
|
907
991
|
var card = el('article', { class: 'log-card', 'data-blob': blob }, nodes);
|
|
908
992
|
cards.push(card);
|
|
909
993
|
});
|
|
@@ -911,15 +995,21 @@
|
|
|
911
995
|
fill(host, [
|
|
912
996
|
el('h2', null, ['Logs']),
|
|
913
997
|
el('input', { id: 'log-find', class: 'find', type: 'search', placeholder: 'Find in logs', 'aria-label': 'Find in logs' }),
|
|
914
|
-
el('
|
|
998
|
+
el('p', { class: 'empty', id: 'log-empty', hidden: cards.length > 0 }, ['No logs in this run.']),
|
|
999
|
+
el('div', { id: 'log-list' }, cards),
|
|
915
1000
|
]);
|
|
916
1001
|
}
|
|
917
1002
|
|
|
918
1003
|
function applyLogFilter() {
|
|
919
1004
|
var query = state.logQuery.trim().toLowerCase();
|
|
1005
|
+
var visible = 0;
|
|
920
1006
|
document.querySelectorAll('.log-card').forEach(function (card) {
|
|
921
1007
|
card.hidden = Boolean(query) && card.dataset.blob.indexOf(query) === -1;
|
|
1008
|
+
if (!card.hidden) visible += 1;
|
|
922
1009
|
});
|
|
1010
|
+
var empty = document.getElementById('log-empty');
|
|
1011
|
+
empty.hidden = visible > 0;
|
|
1012
|
+
empty.textContent = query ? 'No logs match. Try another search.' : 'No logs in this run.';
|
|
923
1013
|
}
|
|
924
1014
|
|
|
925
1015
|
function ensureFiles() {
|
|
@@ -956,10 +1046,30 @@
|
|
|
956
1046
|
}
|
|
957
1047
|
|
|
958
1048
|
function bind() {
|
|
959
|
-
window.addEventListener('
|
|
1049
|
+
window.addEventListener('hashchange', function () {
|
|
1050
|
+
var next = readRoute();
|
|
1051
|
+
if (next.tab === 'tests' && next.id && testById(next.id)) {
|
|
1052
|
+
resetFilters();
|
|
1053
|
+
state.selectedId = next.id;
|
|
1054
|
+
state.attempt = failedAttempt(testById(next.id));
|
|
1055
|
+
state.testPane = defaultPane(testById(next.id));
|
|
1056
|
+
if (built.tests) { paintTags(); paintOrder(); paintList(); paintDetail(); syncPressed(); }
|
|
1057
|
+
}
|
|
1058
|
+
showTab(next.tab, true);
|
|
1059
|
+
});
|
|
1060
|
+
document.querySelector('.skip').addEventListener('click', function (event) {
|
|
1061
|
+
event.preventDefault();
|
|
1062
|
+
showTab('tests');
|
|
1063
|
+
document.getElementById('find').focus();
|
|
1064
|
+
});
|
|
960
1065
|
app.addEventListener('click', function (event) {
|
|
961
1066
|
var target = event.target instanceof Element ? event.target : null;
|
|
962
1067
|
if (!target) return;
|
|
1068
|
+
if (target.closest('.reset-filters')) {
|
|
1069
|
+
resetFilters(); keepSelectionInFilter(); paintTags(); paintOrder(); paintDuration(); paintList(); paintDetail(); syncPressed();
|
|
1070
|
+
document.getElementById('find').focus();
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
963
1073
|
var tab = target.closest('.tab');
|
|
964
1074
|
if (tab) {
|
|
965
1075
|
showTab(tab.dataset.tab);
|
|
@@ -973,7 +1083,7 @@
|
|
|
973
1083
|
}
|
|
974
1084
|
var opener = target.closest('.open-test');
|
|
975
1085
|
if (opener) {
|
|
976
|
-
openTest(opener.dataset.id, Number(opener.dataset.attempt || 0));
|
|
1086
|
+
openTest(opener.dataset.id, Number(opener.dataset.attempt || 0), opener.dataset.openPane);
|
|
977
1087
|
return;
|
|
978
1088
|
}
|
|
979
1089
|
var view = target.closest('.view');
|
|
@@ -982,9 +1092,10 @@
|
|
|
982
1092
|
applyOverview();
|
|
983
1093
|
return;
|
|
984
1094
|
}
|
|
985
|
-
var band = target.closest('.band');
|
|
1095
|
+
var band = target.closest('.band') || target.closest('.slice');
|
|
986
1096
|
if (band) {
|
|
987
|
-
|
|
1097
|
+
var bandId = band.dataset.band || band.getAttribute('data-slice');
|
|
1098
|
+
state.band = state.band === bandId ? 'all' : bandId;
|
|
988
1099
|
state.order = state.band === 'all' ? state.order : 'slowest';
|
|
989
1100
|
state.listLimit = 200;
|
|
990
1101
|
keepSelectionInFilter();
|
|
@@ -1009,7 +1120,7 @@
|
|
|
1009
1120
|
}
|
|
1010
1121
|
var tag = target.closest('.tag-btn');
|
|
1011
1122
|
if (tag) {
|
|
1012
|
-
state.tag = tag.dataset.value ||
|
|
1123
|
+
state.tag = tag.dataset.value || null;
|
|
1013
1124
|
state.listLimit = 200;
|
|
1014
1125
|
keepSelectionInFilter();
|
|
1015
1126
|
paintTags();
|
|
@@ -1019,7 +1130,7 @@
|
|
|
1019
1130
|
}
|
|
1020
1131
|
var projectButton = target.closest('.project-btn');
|
|
1021
1132
|
if (projectButton) {
|
|
1022
|
-
state.projectFilter = projectButton.dataset.value ||
|
|
1133
|
+
state.projectFilter = projectButton.dataset.value || null;
|
|
1023
1134
|
state.listLimit = 200;
|
|
1024
1135
|
keepSelectionInFilter();
|
|
1025
1136
|
paintTags();
|
|
@@ -1047,7 +1158,6 @@
|
|
|
1047
1158
|
paintList();
|
|
1048
1159
|
paintDetail();
|
|
1049
1160
|
markStrip();
|
|
1050
|
-
showNow(state.selectedId);
|
|
1051
1161
|
}
|
|
1052
1162
|
return;
|
|
1053
1163
|
}
|
|
@@ -1065,12 +1175,14 @@
|
|
|
1065
1175
|
if (pane) {
|
|
1066
1176
|
state.testPane = pane.dataset.pane || 'steps';
|
|
1067
1177
|
paintDetail();
|
|
1178
|
+
document.querySelector('.subtab[data-pane="' + state.testPane + '"]').focus();
|
|
1068
1179
|
return;
|
|
1069
1180
|
}
|
|
1070
1181
|
var attempt = target.closest('.attempt');
|
|
1071
1182
|
if (attempt) {
|
|
1072
1183
|
state.attempt = Number(attempt.dataset.index || 0);
|
|
1073
1184
|
paintDetail();
|
|
1185
|
+
document.querySelector('.attempt[data-index="' + state.attempt + '"]').focus();
|
|
1074
1186
|
return;
|
|
1075
1187
|
}
|
|
1076
1188
|
if (target.closest('#api-toggle')) {
|
|
@@ -1080,9 +1192,17 @@
|
|
|
1080
1192
|
if (toggle) toggle.focus();
|
|
1081
1193
|
return;
|
|
1082
1194
|
}
|
|
1195
|
+
if (target.closest('#show-more-timeline')) {
|
|
1196
|
+
state.timelineLimit += 200; paintStrip();
|
|
1197
|
+
var moreTimeline = document.getElementById('show-more-timeline');
|
|
1198
|
+
if (moreTimeline) moreTimeline.focus();
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1083
1201
|
if (target.closest('#show-rest')) {
|
|
1084
|
-
state.listLimit
|
|
1202
|
+
state.listLimit += 200;
|
|
1085
1203
|
paintList();
|
|
1204
|
+
var more = document.getElementById('show-rest');
|
|
1205
|
+
if (more) more.focus();
|
|
1086
1206
|
return;
|
|
1087
1207
|
}
|
|
1088
1208
|
var shot = target.closest('.shot');
|
|
@@ -1101,7 +1221,6 @@
|
|
|
1101
1221
|
paintList();
|
|
1102
1222
|
paintDetail();
|
|
1103
1223
|
markStrip();
|
|
1104
|
-
showNow(state.selectedId);
|
|
1105
1224
|
}, 80);
|
|
1106
1225
|
}
|
|
1107
1226
|
if (event.target.id === 'log-find') {
|
|
@@ -1110,21 +1229,12 @@
|
|
|
1110
1229
|
}
|
|
1111
1230
|
});
|
|
1112
1231
|
|
|
1113
|
-
app.addEventListener('mouseover', function (event) {
|
|
1114
|
-
var segment = event.target && event.target.closest ? event.target.closest('.run-row') : null;
|
|
1115
|
-
if (segment) showNow(segment.dataset.id);
|
|
1116
|
-
});
|
|
1117
|
-
app.addEventListener('mouseout', function (event) {
|
|
1118
|
-
var segment = event.target && event.target.closest ? event.target.closest('.run-row') : null;
|
|
1119
|
-
if (!segment) return;
|
|
1120
|
-
var next = event.relatedTarget && event.relatedTarget.closest ? event.relatedTarget.closest('.run-row') : null;
|
|
1121
|
-
if (!next) showNow(state.selectedId);
|
|
1122
|
-
});
|
|
1123
|
-
|
|
1124
1232
|
document.addEventListener('keydown', function (event) {
|
|
1125
|
-
|
|
1233
|
+
if (event.defaultPrevented || event.isComposing || event.metaKey || event.ctrlKey || event.altKey || document.querySelector('dialog[open]')) return;
|
|
1234
|
+
var typing = event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement || event.target instanceof HTMLSelectElement || event.target.isContentEditable;
|
|
1126
1235
|
if (typing) {
|
|
1127
1236
|
if (event.key === 'Escape') {
|
|
1237
|
+
window.clearTimeout(findTimer);
|
|
1128
1238
|
event.target.value = '';
|
|
1129
1239
|
if (event.target.id === 'find') {
|
|
1130
1240
|
state.query = '';
|
|
@@ -1132,7 +1242,6 @@
|
|
|
1132
1242
|
paintList();
|
|
1133
1243
|
paintDetail();
|
|
1134
1244
|
markStrip();
|
|
1135
|
-
showNow(state.selectedId);
|
|
1136
1245
|
}
|
|
1137
1246
|
if (event.target.id === 'log-find') {
|
|
1138
1247
|
state.logQuery = '';
|
|
@@ -1142,7 +1251,8 @@
|
|
|
1142
1251
|
return;
|
|
1143
1252
|
}
|
|
1144
1253
|
if (event.key >= '1' && event.key <= '5') {
|
|
1145
|
-
|
|
1254
|
+
var destination = TABS[Number(event.key) - 1];
|
|
1255
|
+
if (destination) showTab(destination);
|
|
1146
1256
|
return;
|
|
1147
1257
|
}
|
|
1148
1258
|
if (event.key === '/') {
|
|
@@ -1164,7 +1274,7 @@
|
|
|
1164
1274
|
if (next) next.focus();
|
|
1165
1275
|
return;
|
|
1166
1276
|
}
|
|
1167
|
-
if (state.tab !== 'tests' || (event.key !== 'ArrowDown' && event.key !== 'ArrowUp')) return;
|
|
1277
|
+
if (state.tab !== 'tests' || !event.target.closest || !event.target.closest('#tests') || (event.key !== 'ArrowDown' && event.key !== 'ArrowUp')) return;
|
|
1168
1278
|
var rows = Array.prototype.slice.call(document.querySelectorAll('#tests .row'));
|
|
1169
1279
|
if (!rows.length) return;
|
|
1170
1280
|
event.preventDefault();
|
|
@@ -1179,21 +1289,15 @@
|
|
|
1179
1289
|
|
|
1180
1290
|
function choose(id, resetFilter) {
|
|
1181
1291
|
if (!id || !testById(id)) return;
|
|
1182
|
-
if (resetFilter)
|
|
1183
|
-
state.filter = 'all';
|
|
1184
|
-
state.query = '';
|
|
1185
|
-
state.band = 'all';
|
|
1186
|
-
state.tag = 'all';
|
|
1187
|
-
state.projectFilter = 'all';
|
|
1188
|
-
var find = document.getElementById('find');
|
|
1189
|
-
if (find) find.value = '';
|
|
1190
|
-
}
|
|
1292
|
+
if (resetFilter) resetFilters();
|
|
1191
1293
|
if (state.selectedId !== id) {
|
|
1192
1294
|
var test = testById(id);
|
|
1193
1295
|
state.selectedId = id;
|
|
1194
1296
|
state.attempt = failedAttempt(test);
|
|
1195
1297
|
state.testPane = defaultPane(test);
|
|
1196
1298
|
}
|
|
1299
|
+
var position = filteredTests().findIndex(function (test) { return test.id === id; });
|
|
1300
|
+
state.listLimit = Math.max(state.listLimit, position + 1);
|
|
1197
1301
|
showTab('tests');
|
|
1198
1302
|
if (built.tests) {
|
|
1199
1303
|
syncPressed();
|
|
@@ -1204,37 +1308,46 @@
|
|
|
1204
1308
|
markStrip();
|
|
1205
1309
|
}
|
|
1206
1310
|
paintDuration();
|
|
1207
|
-
showNow(state.selectedId);
|
|
1208
1311
|
var row = document.querySelector('#tests .row[data-id="' + cssEscape(id) + '"]');
|
|
1312
|
+
if (row) row.focus({ preventScroll: true });
|
|
1209
1313
|
if (row && row.scrollIntoView) row.scrollIntoView({ block: 'nearest', behavior: reduce ? 'auto' : 'smooth' });
|
|
1210
1314
|
}
|
|
1211
1315
|
|
|
1316
|
+
function hasFilters() {
|
|
1317
|
+
return state.filter !== 'all' || state.query.trim() || state.band !== 'all' || state.tag !== null || state.projectFilter !== null;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
function resetFilters() {
|
|
1321
|
+
window.clearTimeout(findTimer);
|
|
1322
|
+
state.filter = 'all'; state.query = ''; state.band = 'all'; state.tag = null; state.projectFilter = null;
|
|
1323
|
+
state.listLimit = 200;
|
|
1324
|
+
var find = document.getElementById('find');
|
|
1325
|
+
if (find) find.value = '';
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1212
1328
|
function keepSelectionInFilter() {
|
|
1213
1329
|
var tests = filteredTests();
|
|
1330
|
+
markStrip();
|
|
1214
1331
|
if (tests.some(function (test) { return test.id === state.selectedId; })) return;
|
|
1215
1332
|
var next = tests[0];
|
|
1216
1333
|
if (!next) {
|
|
1217
1334
|
state.selectedId = null;
|
|
1335
|
+
writeHash();
|
|
1218
1336
|
return;
|
|
1219
1337
|
}
|
|
1220
1338
|
state.selectedId = next.id;
|
|
1221
1339
|
state.attempt = failedAttempt(next);
|
|
1222
1340
|
state.testPane = defaultPane(next);
|
|
1341
|
+
writeHash();
|
|
1223
1342
|
}
|
|
1224
1343
|
|
|
1225
|
-
function openTest(id, attempt) {
|
|
1344
|
+
function openTest(id, attempt, pane) {
|
|
1226
1345
|
var test = testById(id);
|
|
1227
1346
|
if (!test) return;
|
|
1228
|
-
|
|
1229
|
-
state.query = '';
|
|
1230
|
-
state.band = 'all';
|
|
1231
|
-
state.tag = 'all';
|
|
1232
|
-
state.projectFilter = 'all';
|
|
1233
|
-
var find = document.getElementById('find');
|
|
1234
|
-
if (find) find.value = '';
|
|
1347
|
+
resetFilters();
|
|
1235
1348
|
state.selectedId = id;
|
|
1236
1349
|
state.attempt = attempt;
|
|
1237
|
-
state.testPane = 'shots';
|
|
1350
|
+
state.testPane = pane === 'logs' ? 'logs' : 'shots';
|
|
1238
1351
|
showTab('tests');
|
|
1239
1352
|
if (built.tests) {
|
|
1240
1353
|
paintTags();
|
|
@@ -1243,43 +1356,30 @@
|
|
|
1243
1356
|
paintDetail();
|
|
1244
1357
|
markStrip();
|
|
1245
1358
|
}
|
|
1359
|
+
syncPressed();
|
|
1246
1360
|
paintDuration();
|
|
1361
|
+
document.getElementById('detail').scrollIntoView({ block: 'nearest' });
|
|
1247
1362
|
}
|
|
1248
1363
|
|
|
1249
1364
|
function openShot(src, alt) {
|
|
1250
1365
|
var safe = safeSrc(src);
|
|
1251
1366
|
if (!safe) return;
|
|
1252
1367
|
var close = el('button', { class: 'close-shot', type: 'button' }, ['Close']);
|
|
1253
|
-
var
|
|
1368
|
+
var returnFocus = document.activeElement;
|
|
1369
|
+
var dialog = el('dialog', { 'aria-label': alt || 'Screenshot' }, [close, el('img', { src: safe, alt: alt })]);
|
|
1254
1370
|
close.addEventListener('click', function () { dialog.close(); });
|
|
1255
1371
|
dialog.addEventListener('click', function (event) { if (event.target === dialog) dialog.close(); });
|
|
1256
|
-
dialog.addEventListener('close', function () { dialog.remove(); });
|
|
1372
|
+
dialog.addEventListener('close', function () { dialog.remove(); if (returnFocus && returnFocus.isConnected) returnFocus.focus(); });
|
|
1257
1373
|
document.body.appendChild(dialog);
|
|
1258
1374
|
dialog.showModal();
|
|
1259
1375
|
}
|
|
1260
1376
|
|
|
1261
|
-
function showNow(id) {
|
|
1262
|
-
var host = document.getElementById('now');
|
|
1263
|
-
if (!host) return;
|
|
1264
|
-
var test = id ? testById(id) : null;
|
|
1265
|
-
if (!test) {
|
|
1266
|
-
fill(host, [data.tests.length ? 'Hover a test, or click one.' : 'No tests ran.']);
|
|
1267
|
-
return;
|
|
1268
|
-
}
|
|
1269
|
-
fill(host, [
|
|
1270
|
-
el('span', { class: 'sw', 'data-status': test.status }, [statusLabel(test)]),
|
|
1271
|
-
el('span', { class: 'name' }, [test.title]),
|
|
1272
|
-
el('span', null, [formatDuration(test.duration)]),
|
|
1273
|
-
el('span', { class: 'now-file' }, [test.file]),
|
|
1274
|
-
]);
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
1377
|
function filteredTests() {
|
|
1278
1378
|
var query = state.query.trim().toLowerCase();
|
|
1279
1379
|
return data.tests.filter(function (test) {
|
|
1280
1380
|
if (state.filter !== 'all' && test.status !== state.filter) return false;
|
|
1281
|
-
if (state.tag !==
|
|
1282
|
-
if (state.projectFilter !==
|
|
1381
|
+
if (state.tag !== null && (test.tags || []).indexOf(state.tag) === -1) return false;
|
|
1382
|
+
if (state.projectFilter !== null && test.project !== state.projectFilter) return false;
|
|
1283
1383
|
if (state.band !== 'all' && (test.status === 'skipped' || durationBand(test.duration) !== state.band)) return false;
|
|
1284
1384
|
if (!query) return true;
|
|
1285
1385
|
var blob = [test.title, test.file, test.project].concat(test.group || [], test.tags || []).join(' ').toLowerCase();
|
|
@@ -1293,7 +1393,7 @@
|
|
|
1293
1393
|
}
|
|
1294
1394
|
|
|
1295
1395
|
function testById(id) {
|
|
1296
|
-
return
|
|
1396
|
+
return testIndex.get(id) || null;
|
|
1297
1397
|
}
|
|
1298
1398
|
|
|
1299
1399
|
function failedAttempt(test) {
|
|
@@ -1307,7 +1407,7 @@
|
|
|
1307
1407
|
|
|
1308
1408
|
function defaultPane(test) {
|
|
1309
1409
|
if (!test) return 'steps';
|
|
1310
|
-
if (test
|
|
1410
|
+
if (isProblem(test)) return 'error';
|
|
1311
1411
|
return 'steps';
|
|
1312
1412
|
}
|
|
1313
1413
|
|
|
@@ -1361,12 +1461,19 @@
|
|
|
1361
1461
|
return value;
|
|
1362
1462
|
}
|
|
1363
1463
|
|
|
1464
|
+
function commitText() {
|
|
1465
|
+
var row = (data.info || []).find(function (item) { return item.label === 'Commit'; });
|
|
1466
|
+
return row && row.value ? row.value : '';
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1364
1469
|
function metaBits() {
|
|
1365
1470
|
var bits = [];
|
|
1366
|
-
if (data.projectName) bits.push(data.projectName);
|
|
1367
|
-
if (Array.isArray(data.projects) && data.projects.length) bits.push(data.projects.join(', '));
|
|
1471
|
+
if (data.showProjects === true && data.projectName) bits.push(data.projectName);
|
|
1472
|
+
if (data.showProjects === true && Array.isArray(data.projects) && data.projects.length) bits.push(data.projects.join(', '));
|
|
1368
1473
|
if (data.startTime) bits.push(formatWhen(data.startTime));
|
|
1369
|
-
|
|
1474
|
+
var sha = commitText();
|
|
1475
|
+
if (sha) bits.push(sha);
|
|
1476
|
+
if (data.showPlaywrightVersion === true && data.playwrightVersion) bits.push('Playwright ' + data.playwrightVersion);
|
|
1370
1477
|
if (data.shard) bits.push('Shard ' + data.shard);
|
|
1371
1478
|
return bits;
|
|
1372
1479
|
}
|