playwright-reborn 0.2.2 → 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 +13 -0
- package/README.md +26 -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/options.js +4 -3
- 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 +1 -0
- package/dist/serialize.js +20 -8
- 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 +110 -54
- package/dist/ui/report.js +150 -162
- 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(''),
|
|
@@ -93,6 +95,7 @@
|
|
|
93
95
|
var canvas = document.querySelector('.atmosphere .bands');
|
|
94
96
|
if (!canvas || !canvas.getContext) return;
|
|
95
97
|
var ctx = canvas.getContext('2d');
|
|
98
|
+
if (!ctx) return;
|
|
96
99
|
var ratio = 1;
|
|
97
100
|
var columns = [];
|
|
98
101
|
var count = 22;
|
|
@@ -119,9 +122,9 @@
|
|
|
119
122
|
var t = reduce ? 8 : now / 1000;
|
|
120
123
|
ctx.clearRect(0, 0, w, h);
|
|
121
124
|
var wash = ctx.createLinearGradient(0, 0, 0, h);
|
|
122
|
-
wash.addColorStop(0, '
|
|
123
|
-
wash.addColorStop(0.42, '#
|
|
124
|
-
wash.addColorStop(1, '#
|
|
125
|
+
wash.addColorStop(0, 'rgba(' + rgb + ', 0.10)');
|
|
126
|
+
wash.addColorStop(0.42, '#080b0a');
|
|
127
|
+
wash.addColorStop(1, '#080808');
|
|
125
128
|
ctx.fillStyle = wash;
|
|
126
129
|
ctx.fillRect(0, 0, w, h);
|
|
127
130
|
columns.forEach(function (column) {
|
|
@@ -139,11 +142,16 @@
|
|
|
139
142
|
ctx.fillStyle = gradient;
|
|
140
143
|
ctx.fillRect(x - spread, 0, spread * 2, h * 0.92);
|
|
141
144
|
});
|
|
142
|
-
if (!reduce) requestAnimationFrame(draw);
|
|
145
|
+
if (!reduce && !document.hidden) curtainFrame = requestAnimationFrame(draw);
|
|
143
146
|
}
|
|
147
|
+
var curtainFrame = 0;
|
|
144
148
|
resize();
|
|
145
|
-
window.addEventListener('resize', resize);
|
|
146
|
-
|
|
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) {
|
|
147
155
|
if (!canvas.width) resize();
|
|
148
156
|
draw(now);
|
|
149
157
|
});
|
|
@@ -152,13 +160,14 @@
|
|
|
152
160
|
function watchHeader() {
|
|
153
161
|
var rail = document.querySelector('.rail');
|
|
154
162
|
if (!rail) return;
|
|
163
|
+
rail.addEventListener('focusin', function () { rail.classList.remove('is-hidden'); });
|
|
155
164
|
var lastY = window.scrollY;
|
|
156
165
|
window.addEventListener('scroll', function () {
|
|
157
166
|
var y = window.scrollY;
|
|
158
167
|
var down = y > lastY + 6;
|
|
159
168
|
var up = y < lastY - 6;
|
|
160
169
|
if (y < 24) rail.classList.remove('is-hidden');
|
|
161
|
-
else if (down) rail.classList.add('is-hidden');
|
|
170
|
+
else if (down && !rail.contains(document.activeElement)) rail.classList.add('is-hidden');
|
|
162
171
|
else if (up) rail.classList.remove('is-hidden');
|
|
163
172
|
lastY = y;
|
|
164
173
|
}, { passive: true });
|
|
@@ -185,16 +194,17 @@
|
|
|
185
194
|
}
|
|
186
195
|
|
|
187
196
|
function tabButton(id, label) {
|
|
188
|
-
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>';
|
|
189
198
|
}
|
|
190
199
|
|
|
191
200
|
function readRoute() {
|
|
192
|
-
var hash =
|
|
193
|
-
try {
|
|
194
|
-
|
|
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' }; }
|
|
195
206
|
if (TABS.indexOf(hash) !== -1) return { tab: hash };
|
|
196
|
-
if (
|
|
197
|
-
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 };
|
|
198
208
|
return { tab: 'overview' };
|
|
199
209
|
}
|
|
200
210
|
|
|
@@ -208,11 +218,13 @@
|
|
|
208
218
|
state.tab = tab;
|
|
209
219
|
document.querySelectorAll('[role="tab"]').forEach(function (button) {
|
|
210
220
|
button.setAttribute('aria-selected', button.dataset.tab === tab ? 'true' : 'false');
|
|
221
|
+
button.tabIndex = button.dataset.tab === tab ? 0 : -1;
|
|
211
222
|
});
|
|
212
223
|
TABS.forEach(function (name) {
|
|
213
224
|
var panel = document.getElementById('panel-' + name);
|
|
214
225
|
var on = name === tab;
|
|
215
226
|
panel.hidden = !on;
|
|
227
|
+
panel.setAttribute('aria-labelledby', 'tab-' + name);
|
|
216
228
|
panel.classList.toggle('panel', true);
|
|
217
229
|
if (on && !quiet && !reduce) {
|
|
218
230
|
panel.classList.remove('panel-enter');
|
|
@@ -224,25 +236,18 @@
|
|
|
224
236
|
if (tab === 'screenshots') ensureShots();
|
|
225
237
|
if (tab === 'logs') ensureLogs();
|
|
226
238
|
if (tab === 'files') ensureFiles();
|
|
227
|
-
writeHash();
|
|
228
|
-
|
|
239
|
+
writeHash(!quiet);
|
|
240
|
+
|
|
229
241
|
}
|
|
230
242
|
|
|
231
|
-
function writeHash() {
|
|
243
|
+
function writeHash(push) {
|
|
232
244
|
var next = state.tab === 'overview' ? 'overview' : state.tab;
|
|
233
245
|
if (state.tab === 'tests' && state.selectedId) next = 'tests/' + encodeURIComponent(state.selectedId);
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
var glow = document.getElementById('tab-glow');
|
|
240
|
-
var active = document.querySelector('.tab[aria-selected="true"]');
|
|
241
|
-
if (!bar || !glow || !active) return;
|
|
242
|
-
var barBox = bar.getBoundingClientRect();
|
|
243
|
-
var box = active.getBoundingClientRect();
|
|
244
|
-
glow.style.width = box.width + 'px';
|
|
245
|
-
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
|
+
}
|
|
246
251
|
}
|
|
247
252
|
|
|
248
253
|
function paintOverview() {
|
|
@@ -250,7 +255,7 @@
|
|
|
250
255
|
host.innerHTML = [
|
|
251
256
|
'<header class="hero">',
|
|
252
257
|
'<div><h1 class="word" id="word"></h1><p class="product" id="product"></p><p class="summary" id="summary"></p></div>',
|
|
253
|
-
'<p class="
|
|
258
|
+
'<p class="run-state" id="run-state"></p>',
|
|
254
259
|
'</header>',
|
|
255
260
|
'<div id="errors"></div>',
|
|
256
261
|
'<dl class="info" id="info"></dl>',
|
|
@@ -278,14 +283,15 @@
|
|
|
278
283
|
if (subtitle) product.textContent = subtitle;
|
|
279
284
|
else product.hidden = true;
|
|
280
285
|
document.getElementById('summary').textContent = data.summary || '';
|
|
281
|
-
|
|
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';
|
|
282
289
|
paintErrors();
|
|
283
290
|
paintInfo();
|
|
284
291
|
paintCounts(document.getElementById('legend'), false);
|
|
285
292
|
paintDuration();
|
|
286
293
|
paintStrip();
|
|
287
294
|
applyOverview();
|
|
288
|
-
showNow(state.selectedId);
|
|
289
295
|
}
|
|
290
296
|
|
|
291
297
|
function paintInfo() {
|
|
@@ -479,7 +485,7 @@
|
|
|
479
485
|
function paintCounts(host, withFind) {
|
|
480
486
|
var counts = data.counts || {};
|
|
481
487
|
var filters = [
|
|
482
|
-
['all', '
|
|
488
|
+
['all', 'tests', counts.total || 0],
|
|
483
489
|
['passed', 'passed', counts.passed || 0],
|
|
484
490
|
['failed', 'failed', counts.failed || 0],
|
|
485
491
|
['flaky', 'flaky', counts.flaky || 0],
|
|
@@ -517,7 +523,7 @@
|
|
|
517
523
|
}
|
|
518
524
|
|
|
519
525
|
function syncPressed() {
|
|
520
|
-
document.querySelectorAll('.count').forEach(function (button) {
|
|
526
|
+
document.querySelectorAll('.count[data-status]').forEach(function (button) {
|
|
521
527
|
button.setAttribute('aria-pressed', button.dataset.status === state.filter ? 'true' : 'false');
|
|
522
528
|
});
|
|
523
529
|
}
|
|
@@ -538,7 +544,7 @@
|
|
|
538
544
|
function paintStrip() {
|
|
539
545
|
var strip = document.getElementById('strip');
|
|
540
546
|
if (!data.tests.length) {
|
|
541
|
-
fill(strip, []);
|
|
547
|
+
fill(strip, [el('p', { class: 'empty' }, ['No tests ran.'])]);
|
|
542
548
|
return;
|
|
543
549
|
}
|
|
544
550
|
var max = data.tests.reduce(function (hi, test) { return Math.max(hi, test.duration || 0); }, 1);
|
|
@@ -547,7 +553,7 @@
|
|
|
547
553
|
});
|
|
548
554
|
strip.className = 'run-list';
|
|
549
555
|
strip.style.height = '';
|
|
550
|
-
|
|
556
|
+
var nodes = ordered.slice(0, state.timelineLimit).map(function (test) {
|
|
551
557
|
var fillBar = el('span', { class: 'run-fill', 'data-status': test.status });
|
|
552
558
|
fillBar.style.width = Math.max(2, Math.round(((test.duration || 0) / max) * 100)) + '%';
|
|
553
559
|
return el('button', {
|
|
@@ -562,51 +568,10 @@
|
|
|
562
568
|
el('span', { class: 'run-track' }, [fillBar]),
|
|
563
569
|
el('span', { class: 'run-time' }, [formatDuration(test.duration)]),
|
|
564
570
|
]);
|
|
565
|
-
}));
|
|
566
|
-
markStrip();
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
function paintCanvasStrip(host) {
|
|
570
|
-
var canvas = el('canvas', { class: 'strip-canvas', 'aria-label': 'Tests by duration' });
|
|
571
|
-
fill(host, [canvas]);
|
|
572
|
-
var hits = [];
|
|
573
|
-
function draw() {
|
|
574
|
-
var width = host.clientWidth || 600;
|
|
575
|
-
var height = 52;
|
|
576
|
-
var ratio = window.devicePixelRatio || 1;
|
|
577
|
-
canvas.width = Math.floor(width * ratio);
|
|
578
|
-
canvas.height = Math.floor(height * ratio);
|
|
579
|
-
canvas.style.width = width + 'px';
|
|
580
|
-
canvas.style.height = height + 'px';
|
|
581
|
-
var ctx = canvas.getContext('2d');
|
|
582
|
-
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
|
|
583
|
-
ctx.clearRect(0, 0, width, height);
|
|
584
|
-
var total = data.tests.reduce(function (sum, test) { return sum + Math.max(test.duration || 0, 1); }, 0);
|
|
585
|
-
var x = 0;
|
|
586
|
-
hits = [];
|
|
587
|
-
data.tests.forEach(function (test) {
|
|
588
|
-
var w = Math.max(2, (Math.max(test.duration || 0, 1) / total) * width);
|
|
589
|
-
ctx.fillStyle = canvasColor(test.status);
|
|
590
|
-
ctx.fillRect(x, 8, Math.max(1, w - 2), 36);
|
|
591
|
-
hits.push({ x: x, w: w, id: test.id });
|
|
592
|
-
x += w;
|
|
593
|
-
});
|
|
594
|
-
}
|
|
595
|
-
draw();
|
|
596
|
-
window.addEventListener('resize', draw);
|
|
597
|
-
canvas.addEventListener('mousemove', function (event) {
|
|
598
|
-
var rect = canvas.getBoundingClientRect();
|
|
599
|
-
var x = event.clientX - rect.left;
|
|
600
|
-
var hit = hits.find(function (item) { return x >= item.x && x < item.x + item.w; });
|
|
601
|
-
if (hit) showNow(hit.id);
|
|
602
|
-
});
|
|
603
|
-
canvas.addEventListener('mouseleave', function () { showNow(state.selectedId); });
|
|
604
|
-
canvas.addEventListener('click', function (event) {
|
|
605
|
-
var rect = canvas.getBoundingClientRect();
|
|
606
|
-
var x = event.clientX - rect.left;
|
|
607
|
-
var hit = hits.find(function (item) { return x >= item.x && x < item.x + item.w; });
|
|
608
|
-
if (hit) choose(hit.id, true);
|
|
609
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();
|
|
610
575
|
}
|
|
611
576
|
|
|
612
577
|
function canvasColor(status) {
|
|
@@ -617,7 +582,7 @@
|
|
|
617
582
|
}
|
|
618
583
|
|
|
619
584
|
function markStrip() {
|
|
620
|
-
var visible =
|
|
585
|
+
var visible = Object.create(null);
|
|
621
586
|
filteredTests().forEach(function (test) { visible[test.id] = true; });
|
|
622
587
|
document.querySelectorAll('.run-row').forEach(function (segment) {
|
|
623
588
|
segment.classList.toggle('is-dim', !visible[segment.dataset.id]);
|
|
@@ -637,7 +602,7 @@
|
|
|
637
602
|
}
|
|
638
603
|
|
|
639
604
|
function uniqueValues(pick) {
|
|
640
|
-
var seen =
|
|
605
|
+
var seen = Object.create(null);
|
|
641
606
|
data.tests.forEach(function (test) {
|
|
642
607
|
pick(test).forEach(function (value) {
|
|
643
608
|
if (value) seen[value] = true;
|
|
@@ -654,12 +619,12 @@
|
|
|
654
619
|
var nodes = [];
|
|
655
620
|
if (tags.length) {
|
|
656
621
|
nodes.push(el('span', { class: 'order-label' }, ['Tags']));
|
|
657
|
-
nodes.push(chip('tag-btn', '
|
|
622
|
+
nodes.push(chip('tag-btn', '', 'All', state.tag || ''));
|
|
658
623
|
tags.forEach(function (tag) { nodes.push(chip('tag-btn', tag, tag, state.tag)); });
|
|
659
624
|
}
|
|
660
625
|
if (data.showProjectFilter === true && projects.length > 1) {
|
|
661
626
|
nodes.push(el('span', { class: 'order-label' }, ['Project']));
|
|
662
|
-
nodes.push(chip('project-btn', '
|
|
627
|
+
nodes.push(chip('project-btn', '', 'All', state.projectFilter || ''));
|
|
663
628
|
projects.forEach(function (project) { nodes.push(chip('project-btn', project, project, state.projectFilter)); });
|
|
664
629
|
}
|
|
665
630
|
host.hidden = nodes.length === 0;
|
|
@@ -711,7 +676,7 @@
|
|
|
711
676
|
if (built.tests) return;
|
|
712
677
|
built.tests = true;
|
|
713
678
|
var host = document.getElementById('panel-tests');
|
|
714
|
-
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>';
|
|
715
680
|
paintCounts(document.getElementById('test-tools'), true);
|
|
716
681
|
paintTags();
|
|
717
682
|
paintOrder();
|
|
@@ -724,8 +689,13 @@
|
|
|
724
689
|
var host = document.getElementById('tests');
|
|
725
690
|
if (!host) return;
|
|
726
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
|
+
]);
|
|
727
697
|
if (!tests.length) {
|
|
728
|
-
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.'])]);
|
|
729
699
|
return;
|
|
730
700
|
}
|
|
731
701
|
if (state.order !== 'grouped') {
|
|
@@ -733,20 +703,20 @@
|
|
|
733
703
|
var shown = sorted.slice(0, state.listLimit);
|
|
734
704
|
var flat = shown.map(function (test) { return rowButton(test, true); });
|
|
735
705
|
if (shown.length < sorted.length) {
|
|
736
|
-
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']));
|
|
737
707
|
}
|
|
738
708
|
fill(host, flat);
|
|
739
709
|
return;
|
|
740
710
|
}
|
|
741
711
|
var groups = [];
|
|
742
|
-
var problemIds =
|
|
712
|
+
var problemIds = Object.create(null);
|
|
743
713
|
var problems = tests.filter(isProblem);
|
|
744
714
|
if (state.filter === 'all' && !state.query && problems.length && problems.length !== tests.length) {
|
|
745
715
|
problems.forEach(function (test) { problemIds[test.id] = true; });
|
|
746
716
|
groups.push({ name: 'Problems', tests: problems });
|
|
747
717
|
}
|
|
748
718
|
var byFile = [];
|
|
749
|
-
var index =
|
|
719
|
+
var index = Object.create(null);
|
|
750
720
|
tests.forEach(function (test) {
|
|
751
721
|
if (problemIds[test.id]) return;
|
|
752
722
|
if (index[test.file] == null) {
|
|
@@ -771,7 +741,7 @@
|
|
|
771
741
|
return el('div', { class: 'group' }, [el('p', { class: 'file-name' }, [group.name])].concat(rows));
|
|
772
742
|
}).filter(Boolean);
|
|
773
743
|
if (truncated) {
|
|
774
|
-
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']));
|
|
775
745
|
}
|
|
776
746
|
fill(host, nodes);
|
|
777
747
|
}
|
|
@@ -805,7 +775,7 @@
|
|
|
805
775
|
['logs', 'Logs'],
|
|
806
776
|
['shots', 'Screenshots'],
|
|
807
777
|
];
|
|
808
|
-
var tabs = el('div', { class: 'subtabs', role: '
|
|
778
|
+
var tabs = el('div', { class: 'subtabs', role: 'group', 'aria-label': 'Test details' }, panes.map(function (pane) {
|
|
809
779
|
return el('button', {
|
|
810
780
|
class: 'subtab',
|
|
811
781
|
type: 'button',
|
|
@@ -816,6 +786,7 @@
|
|
|
816
786
|
var body = [headerBlock(test), tabs];
|
|
817
787
|
if (test.attempts.length > 1) body.push(attemptTabs(test));
|
|
818
788
|
if (attempt) body.push(paneBody(test, attempt));
|
|
789
|
+
else body.push(el('p', { class: 'empty block' }, ['This test did not run.']));
|
|
819
790
|
fill(host, [el('div', { class: 'detail-body' }, body)]);
|
|
820
791
|
}
|
|
821
792
|
|
|
@@ -831,7 +802,7 @@
|
|
|
831
802
|
if (test.group && test.group.length) bits.push(el('p', { class: 'kicker' }, [test.group.join(' / ')]));
|
|
832
803
|
bits.push(el('h2', null, [test.title]));
|
|
833
804
|
var where = [el('span', null, [test.file + ':' + test.line])];
|
|
834
|
-
if (test.project) where.push(el('span', null, [test.project]));
|
|
805
|
+
if (data.showProjects === true && test.project) where.push(el('span', null, [test.project]));
|
|
835
806
|
(test.tags || []).forEach(function (tag) { where.push(el('span', null, [tag])); });
|
|
836
807
|
bits.push(el('p', { class: 'where' }, where));
|
|
837
808
|
bits.push(el('p', { class: 'status-line' }, [
|
|
@@ -859,7 +830,8 @@
|
|
|
859
830
|
|
|
860
831
|
function errorBlock(attempt) {
|
|
861
832
|
if (!attempt.errors || !attempt.errors.length) return null;
|
|
862
|
-
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];
|
|
863
835
|
var messages = attempt.errors.map(function (error) {
|
|
864
836
|
var nodes = [el('pre', null, [error.message || 'The test failed.'])];
|
|
865
837
|
if (error.location) nodes.push(el('p', { class: 'where-error' }, [error.location]));
|
|
@@ -949,8 +921,9 @@
|
|
|
949
921
|
var src = safeSrc(file.path);
|
|
950
922
|
var copy = el('div', { class: 'tile-copy' }, [
|
|
951
923
|
el('p', { class: 'tile-title' }, [test.title]),
|
|
924
|
+
el('p', { class: 'tile-meta' }, ['Attempt ' + (index + 1) + ' · ' + attemptLabel(attempt.status)]),
|
|
952
925
|
el('p', { class: 'tile-meta' }, [file.stepTitle || file.name || 'Screenshot']),
|
|
953
|
-
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']),
|
|
954
927
|
]);
|
|
955
928
|
var tile = el('div', { class: 'tile', 'data-role': file.role || '', 'data-status': test.status }, [
|
|
956
929
|
el('button', { class: 'shot', type: 'button', 'data-src': src, 'data-alt': file.name || test.title }, [
|
|
@@ -1014,7 +987,7 @@
|
|
|
1014
987
|
];
|
|
1015
988
|
if (attempt.stdout) nodes.push(el('div', { class: 'well' }, [el('p', null, ['Output']), el('pre', null, [attempt.stdout])]));
|
|
1016
989
|
if (attempt.stderr) nodes.push(el('div', { class: 'well' }, [el('p', null, ['Error output']), el('pre', null, [attempt.stderr])]));
|
|
1017
|
-
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']));
|
|
1018
991
|
var card = el('article', { class: 'log-card', 'data-blob': blob }, nodes);
|
|
1019
992
|
cards.push(card);
|
|
1020
993
|
});
|
|
@@ -1022,15 +995,21 @@
|
|
|
1022
995
|
fill(host, [
|
|
1023
996
|
el('h2', null, ['Logs']),
|
|
1024
997
|
el('input', { id: 'log-find', class: 'find', type: 'search', placeholder: 'Find in logs', 'aria-label': 'Find in logs' }),
|
|
1025
|
-
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),
|
|
1026
1000
|
]);
|
|
1027
1001
|
}
|
|
1028
1002
|
|
|
1029
1003
|
function applyLogFilter() {
|
|
1030
1004
|
var query = state.logQuery.trim().toLowerCase();
|
|
1005
|
+
var visible = 0;
|
|
1031
1006
|
document.querySelectorAll('.log-card').forEach(function (card) {
|
|
1032
1007
|
card.hidden = Boolean(query) && card.dataset.blob.indexOf(query) === -1;
|
|
1008
|
+
if (!card.hidden) visible += 1;
|
|
1033
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.';
|
|
1034
1013
|
}
|
|
1035
1014
|
|
|
1036
1015
|
function ensureFiles() {
|
|
@@ -1067,10 +1046,30 @@
|
|
|
1067
1046
|
}
|
|
1068
1047
|
|
|
1069
1048
|
function bind() {
|
|
1070
|
-
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
|
+
});
|
|
1071
1065
|
app.addEventListener('click', function (event) {
|
|
1072
1066
|
var target = event.target instanceof Element ? event.target : null;
|
|
1073
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
|
+
}
|
|
1074
1073
|
var tab = target.closest('.tab');
|
|
1075
1074
|
if (tab) {
|
|
1076
1075
|
showTab(tab.dataset.tab);
|
|
@@ -1084,7 +1083,7 @@
|
|
|
1084
1083
|
}
|
|
1085
1084
|
var opener = target.closest('.open-test');
|
|
1086
1085
|
if (opener) {
|
|
1087
|
-
openTest(opener.dataset.id, Number(opener.dataset.attempt || 0));
|
|
1086
|
+
openTest(opener.dataset.id, Number(opener.dataset.attempt || 0), opener.dataset.openPane);
|
|
1088
1087
|
return;
|
|
1089
1088
|
}
|
|
1090
1089
|
var view = target.closest('.view');
|
|
@@ -1121,7 +1120,7 @@
|
|
|
1121
1120
|
}
|
|
1122
1121
|
var tag = target.closest('.tag-btn');
|
|
1123
1122
|
if (tag) {
|
|
1124
|
-
state.tag = tag.dataset.value ||
|
|
1123
|
+
state.tag = tag.dataset.value || null;
|
|
1125
1124
|
state.listLimit = 200;
|
|
1126
1125
|
keepSelectionInFilter();
|
|
1127
1126
|
paintTags();
|
|
@@ -1131,7 +1130,7 @@
|
|
|
1131
1130
|
}
|
|
1132
1131
|
var projectButton = target.closest('.project-btn');
|
|
1133
1132
|
if (projectButton) {
|
|
1134
|
-
state.projectFilter = projectButton.dataset.value ||
|
|
1133
|
+
state.projectFilter = projectButton.dataset.value || null;
|
|
1135
1134
|
state.listLimit = 200;
|
|
1136
1135
|
keepSelectionInFilter();
|
|
1137
1136
|
paintTags();
|
|
@@ -1159,7 +1158,6 @@
|
|
|
1159
1158
|
paintList();
|
|
1160
1159
|
paintDetail();
|
|
1161
1160
|
markStrip();
|
|
1162
|
-
showNow(state.selectedId);
|
|
1163
1161
|
}
|
|
1164
1162
|
return;
|
|
1165
1163
|
}
|
|
@@ -1177,12 +1175,14 @@
|
|
|
1177
1175
|
if (pane) {
|
|
1178
1176
|
state.testPane = pane.dataset.pane || 'steps';
|
|
1179
1177
|
paintDetail();
|
|
1178
|
+
document.querySelector('.subtab[data-pane="' + state.testPane + '"]').focus();
|
|
1180
1179
|
return;
|
|
1181
1180
|
}
|
|
1182
1181
|
var attempt = target.closest('.attempt');
|
|
1183
1182
|
if (attempt) {
|
|
1184
1183
|
state.attempt = Number(attempt.dataset.index || 0);
|
|
1185
1184
|
paintDetail();
|
|
1185
|
+
document.querySelector('.attempt[data-index="' + state.attempt + '"]').focus();
|
|
1186
1186
|
return;
|
|
1187
1187
|
}
|
|
1188
1188
|
if (target.closest('#api-toggle')) {
|
|
@@ -1192,9 +1192,17 @@
|
|
|
1192
1192
|
if (toggle) toggle.focus();
|
|
1193
1193
|
return;
|
|
1194
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
|
+
}
|
|
1195
1201
|
if (target.closest('#show-rest')) {
|
|
1196
|
-
state.listLimit
|
|
1202
|
+
state.listLimit += 200;
|
|
1197
1203
|
paintList();
|
|
1204
|
+
var more = document.getElementById('show-rest');
|
|
1205
|
+
if (more) more.focus();
|
|
1198
1206
|
return;
|
|
1199
1207
|
}
|
|
1200
1208
|
var shot = target.closest('.shot');
|
|
@@ -1213,7 +1221,6 @@
|
|
|
1213
1221
|
paintList();
|
|
1214
1222
|
paintDetail();
|
|
1215
1223
|
markStrip();
|
|
1216
|
-
showNow(state.selectedId);
|
|
1217
1224
|
}, 80);
|
|
1218
1225
|
}
|
|
1219
1226
|
if (event.target.id === 'log-find') {
|
|
@@ -1222,21 +1229,12 @@
|
|
|
1222
1229
|
}
|
|
1223
1230
|
});
|
|
1224
1231
|
|
|
1225
|
-
app.addEventListener('mouseover', function (event) {
|
|
1226
|
-
var segment = event.target && event.target.closest ? event.target.closest('.run-row') : null;
|
|
1227
|
-
if (segment) showNow(segment.dataset.id);
|
|
1228
|
-
});
|
|
1229
|
-
app.addEventListener('mouseout', function (event) {
|
|
1230
|
-
var segment = event.target && event.target.closest ? event.target.closest('.run-row') : null;
|
|
1231
|
-
if (!segment) return;
|
|
1232
|
-
var next = event.relatedTarget && event.relatedTarget.closest ? event.relatedTarget.closest('.run-row') : null;
|
|
1233
|
-
if (!next) showNow(state.selectedId);
|
|
1234
|
-
});
|
|
1235
|
-
|
|
1236
1232
|
document.addEventListener('keydown', function (event) {
|
|
1237
|
-
|
|
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;
|
|
1238
1235
|
if (typing) {
|
|
1239
1236
|
if (event.key === 'Escape') {
|
|
1237
|
+
window.clearTimeout(findTimer);
|
|
1240
1238
|
event.target.value = '';
|
|
1241
1239
|
if (event.target.id === 'find') {
|
|
1242
1240
|
state.query = '';
|
|
@@ -1244,7 +1242,6 @@
|
|
|
1244
1242
|
paintList();
|
|
1245
1243
|
paintDetail();
|
|
1246
1244
|
markStrip();
|
|
1247
|
-
showNow(state.selectedId);
|
|
1248
1245
|
}
|
|
1249
1246
|
if (event.target.id === 'log-find') {
|
|
1250
1247
|
state.logQuery = '';
|
|
@@ -1254,7 +1251,8 @@
|
|
|
1254
1251
|
return;
|
|
1255
1252
|
}
|
|
1256
1253
|
if (event.key >= '1' && event.key <= '5') {
|
|
1257
|
-
|
|
1254
|
+
var destination = TABS[Number(event.key) - 1];
|
|
1255
|
+
if (destination) showTab(destination);
|
|
1258
1256
|
return;
|
|
1259
1257
|
}
|
|
1260
1258
|
if (event.key === '/') {
|
|
@@ -1276,7 +1274,7 @@
|
|
|
1276
1274
|
if (next) next.focus();
|
|
1277
1275
|
return;
|
|
1278
1276
|
}
|
|
1279
|
-
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;
|
|
1280
1278
|
var rows = Array.prototype.slice.call(document.querySelectorAll('#tests .row'));
|
|
1281
1279
|
if (!rows.length) return;
|
|
1282
1280
|
event.preventDefault();
|
|
@@ -1291,21 +1289,15 @@
|
|
|
1291
1289
|
|
|
1292
1290
|
function choose(id, resetFilter) {
|
|
1293
1291
|
if (!id || !testById(id)) return;
|
|
1294
|
-
if (resetFilter)
|
|
1295
|
-
state.filter = 'all';
|
|
1296
|
-
state.query = '';
|
|
1297
|
-
state.band = 'all';
|
|
1298
|
-
state.tag = 'all';
|
|
1299
|
-
state.projectFilter = 'all';
|
|
1300
|
-
var find = document.getElementById('find');
|
|
1301
|
-
if (find) find.value = '';
|
|
1302
|
-
}
|
|
1292
|
+
if (resetFilter) resetFilters();
|
|
1303
1293
|
if (state.selectedId !== id) {
|
|
1304
1294
|
var test = testById(id);
|
|
1305
1295
|
state.selectedId = id;
|
|
1306
1296
|
state.attempt = failedAttempt(test);
|
|
1307
1297
|
state.testPane = defaultPane(test);
|
|
1308
1298
|
}
|
|
1299
|
+
var position = filteredTests().findIndex(function (test) { return test.id === id; });
|
|
1300
|
+
state.listLimit = Math.max(state.listLimit, position + 1);
|
|
1309
1301
|
showTab('tests');
|
|
1310
1302
|
if (built.tests) {
|
|
1311
1303
|
syncPressed();
|
|
@@ -1316,37 +1308,46 @@
|
|
|
1316
1308
|
markStrip();
|
|
1317
1309
|
}
|
|
1318
1310
|
paintDuration();
|
|
1319
|
-
showNow(state.selectedId);
|
|
1320
1311
|
var row = document.querySelector('#tests .row[data-id="' + cssEscape(id) + '"]');
|
|
1312
|
+
if (row) row.focus({ preventScroll: true });
|
|
1321
1313
|
if (row && row.scrollIntoView) row.scrollIntoView({ block: 'nearest', behavior: reduce ? 'auto' : 'smooth' });
|
|
1322
1314
|
}
|
|
1323
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
|
+
|
|
1324
1328
|
function keepSelectionInFilter() {
|
|
1325
1329
|
var tests = filteredTests();
|
|
1330
|
+
markStrip();
|
|
1326
1331
|
if (tests.some(function (test) { return test.id === state.selectedId; })) return;
|
|
1327
1332
|
var next = tests[0];
|
|
1328
1333
|
if (!next) {
|
|
1329
1334
|
state.selectedId = null;
|
|
1335
|
+
writeHash();
|
|
1330
1336
|
return;
|
|
1331
1337
|
}
|
|
1332
1338
|
state.selectedId = next.id;
|
|
1333
1339
|
state.attempt = failedAttempt(next);
|
|
1334
1340
|
state.testPane = defaultPane(next);
|
|
1341
|
+
writeHash();
|
|
1335
1342
|
}
|
|
1336
1343
|
|
|
1337
|
-
function openTest(id, attempt) {
|
|
1344
|
+
function openTest(id, attempt, pane) {
|
|
1338
1345
|
var test = testById(id);
|
|
1339
1346
|
if (!test) return;
|
|
1340
|
-
|
|
1341
|
-
state.query = '';
|
|
1342
|
-
state.band = 'all';
|
|
1343
|
-
state.tag = 'all';
|
|
1344
|
-
state.projectFilter = 'all';
|
|
1345
|
-
var find = document.getElementById('find');
|
|
1346
|
-
if (find) find.value = '';
|
|
1347
|
+
resetFilters();
|
|
1347
1348
|
state.selectedId = id;
|
|
1348
1349
|
state.attempt = attempt;
|
|
1349
|
-
state.testPane = 'shots';
|
|
1350
|
+
state.testPane = pane === 'logs' ? 'logs' : 'shots';
|
|
1350
1351
|
showTab('tests');
|
|
1351
1352
|
if (built.tests) {
|
|
1352
1353
|
paintTags();
|
|
@@ -1355,43 +1356,30 @@
|
|
|
1355
1356
|
paintDetail();
|
|
1356
1357
|
markStrip();
|
|
1357
1358
|
}
|
|
1359
|
+
syncPressed();
|
|
1358
1360
|
paintDuration();
|
|
1361
|
+
document.getElementById('detail').scrollIntoView({ block: 'nearest' });
|
|
1359
1362
|
}
|
|
1360
1363
|
|
|
1361
1364
|
function openShot(src, alt) {
|
|
1362
1365
|
var safe = safeSrc(src);
|
|
1363
1366
|
if (!safe) return;
|
|
1364
1367
|
var close = el('button', { class: 'close-shot', type: 'button' }, ['Close']);
|
|
1365
|
-
var
|
|
1368
|
+
var returnFocus = document.activeElement;
|
|
1369
|
+
var dialog = el('dialog', { 'aria-label': alt || 'Screenshot' }, [close, el('img', { src: safe, alt: alt })]);
|
|
1366
1370
|
close.addEventListener('click', function () { dialog.close(); });
|
|
1367
1371
|
dialog.addEventListener('click', function (event) { if (event.target === dialog) dialog.close(); });
|
|
1368
|
-
dialog.addEventListener('close', function () { dialog.remove(); });
|
|
1372
|
+
dialog.addEventListener('close', function () { dialog.remove(); if (returnFocus && returnFocus.isConnected) returnFocus.focus(); });
|
|
1369
1373
|
document.body.appendChild(dialog);
|
|
1370
1374
|
dialog.showModal();
|
|
1371
1375
|
}
|
|
1372
1376
|
|
|
1373
|
-
function showNow(id) {
|
|
1374
|
-
var host = document.getElementById('now');
|
|
1375
|
-
if (!host) return;
|
|
1376
|
-
var test = id ? testById(id) : null;
|
|
1377
|
-
if (!test) {
|
|
1378
|
-
fill(host, [data.tests.length ? 'Hover a test, or click one.' : 'No tests ran.']);
|
|
1379
|
-
return;
|
|
1380
|
-
}
|
|
1381
|
-
fill(host, [
|
|
1382
|
-
el('span', { class: 'sw', 'data-status': test.status }, [statusLabel(test)]),
|
|
1383
|
-
el('span', { class: 'name' }, [test.title]),
|
|
1384
|
-
el('span', null, [formatDuration(test.duration)]),
|
|
1385
|
-
el('span', { class: 'now-file' }, [test.file]),
|
|
1386
|
-
]);
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
1377
|
function filteredTests() {
|
|
1390
1378
|
var query = state.query.trim().toLowerCase();
|
|
1391
1379
|
return data.tests.filter(function (test) {
|
|
1392
1380
|
if (state.filter !== 'all' && test.status !== state.filter) return false;
|
|
1393
|
-
if (state.tag !==
|
|
1394
|
-
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;
|
|
1395
1383
|
if (state.band !== 'all' && (test.status === 'skipped' || durationBand(test.duration) !== state.band)) return false;
|
|
1396
1384
|
if (!query) return true;
|
|
1397
1385
|
var blob = [test.title, test.file, test.project].concat(test.group || [], test.tags || []).join(' ').toLowerCase();
|
|
@@ -1405,7 +1393,7 @@
|
|
|
1405
1393
|
}
|
|
1406
1394
|
|
|
1407
1395
|
function testById(id) {
|
|
1408
|
-
return
|
|
1396
|
+
return testIndex.get(id) || null;
|
|
1409
1397
|
}
|
|
1410
1398
|
|
|
1411
1399
|
function failedAttempt(test) {
|
|
@@ -1419,7 +1407,7 @@
|
|
|
1419
1407
|
|
|
1420
1408
|
function defaultPane(test) {
|
|
1421
1409
|
if (!test) return 'steps';
|
|
1422
|
-
if (test
|
|
1410
|
+
if (isProblem(test)) return 'error';
|
|
1423
1411
|
return 'steps';
|
|
1424
1412
|
}
|
|
1425
1413
|
|