jestronaut 0.2.0 → 0.3.16
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/LICENSE +21 -0
- package/README.md +6 -2
- package/bin/jestronaut.js +21 -27
- package/index.js +1 -3
- package/lib/constants.js +1 -5
- package/lib/reporter.js +34 -85
- package/lib/state.js +21 -38
- package/lib/ui/app.js +20 -0
- package/lib/ui/components/Dashboard.js +179 -0
- package/lib/ui/components/Footer.js +33 -0
- package/lib/ui/components/Header.js +19 -0
- package/lib/ui/components/Progress.js +26 -0
- package/lib/ui/components/ResultsList.js +26 -0
- package/lib/ui/components/ScrollableBox.js +20 -0
- package/lib/ui/components/ScrollableList.js +30 -0
- package/lib/ui/components/Stats.js +13 -0
- package/lib/ui/components/SuiteDetailOverlay.js +111 -0
- package/lib/ui/components/SuitesList.js +37 -0
- package/lib/ui/components/TestDetailOverlay.js +75 -0
- package/lib/ui/store.js +18 -0
- package/package.json +8 -5
- package/lib/ui/keys.js +0 -140
- package/lib/ui/overlays/suiteDetail.js +0 -123
- package/lib/ui/overlays/testDetail.js +0 -86
- package/lib/ui/panels/footer.js +0 -46
- package/lib/ui/panels/header.js +0 -23
- package/lib/ui/panels/progress.js +0 -30
- package/lib/ui/panels/results.js +0 -41
- package/lib/ui/panels/stats.js +0 -27
- package/lib/ui/panels/suites.js +0 -66
- package/lib/ui/screen.js +0 -100
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const blessed = require('blessed');
|
|
4
|
-
|
|
5
|
-
function createTestDetail(screen) {
|
|
6
|
-
const widget = blessed.box({
|
|
7
|
-
top: '8%', left: '8%', width: '84%', height: '84%',
|
|
8
|
-
label: ' Test Failure Detail ',
|
|
9
|
-
border: { type: 'line' },
|
|
10
|
-
tags: true, scrollable: true, alwaysScroll: true,
|
|
11
|
-
keys: true, vi: true,
|
|
12
|
-
scrollbar: { ch: '|', style: { fg: 'red' } },
|
|
13
|
-
style: {
|
|
14
|
-
border: { fg: 'red' }, label: { fg: 'red', bold: true },
|
|
15
|
-
bg: '#0d0000', fg: 'white',
|
|
16
|
-
},
|
|
17
|
-
padding: { left: 2, right: 2, top: 1, bottom: 1 },
|
|
18
|
-
hidden: true,
|
|
19
|
-
});
|
|
20
|
-
screen.append(widget);
|
|
21
|
-
return widget;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function openTestDetail(widget, failure, stats) {
|
|
25
|
-
const rawMsg = (failure.messages || []).join('\n');
|
|
26
|
-
const expectedMatch = rawMsg.match(/Expected[:\s]+(.+)/);
|
|
27
|
-
const receivedMatch = rawMsg.match(/Received[:\s]+(.+)/);
|
|
28
|
-
const stackLines = rawMsg.split('\n')
|
|
29
|
-
.filter(l => l.trim().startsWith('at '))
|
|
30
|
-
.map(l => l.trim());
|
|
31
|
-
|
|
32
|
-
const lines = [
|
|
33
|
-
`{red-fg}{bold}FAILED: ${failure.suiteName} > ${failure.title}{/bold}{/red-fg}`,
|
|
34
|
-
'',
|
|
35
|
-
`{yellow-fg}Suite :{/yellow-fg} ${failure.suiteName}`,
|
|
36
|
-
`{yellow-fg}Test :{/yellow-fg} ${failure.title}`,
|
|
37
|
-
`{yellow-fg}Duration:{/yellow-fg} ${failure.duration != null ? failure.duration + 'ms' : 'N/A'}`,
|
|
38
|
-
'',
|
|
39
|
-
'{cyan-fg}── Error Message ──────────────────────────────────────────────────{/cyan-fg}',
|
|
40
|
-
'',
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
if (expectedMatch) lines.push(` {green-fg}Expected:{/green-fg} ${expectedMatch[1].trim()}`);
|
|
44
|
-
if (receivedMatch) lines.push(` {red-fg}Received:{/red-fg} ${receivedMatch[1].trim()}`);
|
|
45
|
-
|
|
46
|
-
lines.push('');
|
|
47
|
-
rawMsg.split('\n').slice(0, 15).forEach(l =>
|
|
48
|
-
lines.push(` ${l.replace(/\{/g, '(').replace(/\}/g, ')')}`)
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
lines.push(
|
|
52
|
-
'',
|
|
53
|
-
'{cyan-fg}── Stack Trace ─────────────────────────────────────────────────────{/cyan-fg}',
|
|
54
|
-
'',
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
if (stackLines.length > 0) {
|
|
58
|
-
const firstUser = stackLines.findIndex(l => !l.includes('node_modules'));
|
|
59
|
-
stackLines.forEach((l, i) => {
|
|
60
|
-
if (i === firstUser) lines.push(` {yellow-fg}> ${l}{/yellow-fg}`);
|
|
61
|
-
else lines.push(` {grey-fg}${l}{/grey-fg}`);
|
|
62
|
-
});
|
|
63
|
-
} else {
|
|
64
|
-
lines.push(' {grey-fg}(no stack trace){/grey-fg}');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
lines.push(
|
|
68
|
-
'',
|
|
69
|
-
'{cyan-fg}── Run Metrics ─────────────────────────────────────────────────────{/cyan-fg}',
|
|
70
|
-
'',
|
|
71
|
-
` {white-fg}Passed :{/white-fg} {green-fg}${stats.passed}{/green-fg}`,
|
|
72
|
-
` {white-fg}Failed :{/white-fg} {red-fg}${stats.failed}{/red-fg}`,
|
|
73
|
-
` {white-fg}Skipped :{/white-fg} {yellow-fg}${stats.skipped}{/yellow-fg}`,
|
|
74
|
-
` {white-fg}Elapsed :{/white-fg} ${((Date.now() - stats.startTime) / 1000).toFixed(1)}s`,
|
|
75
|
-
'',
|
|
76
|
-
'{grey-fg} [Esc] back [j/k] scroll{/grey-fg}',
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
widget.setLabel(` Test Failure: ${failure.title} `);
|
|
80
|
-
widget.setContent(lines.join('\n'));
|
|
81
|
-
widget.scrollTo(0);
|
|
82
|
-
widget.show();
|
|
83
|
-
widget.setFront();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
module.exports = { createTestDetail, openTestDetail };
|
package/lib/ui/panels/footer.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const blessed = require('blessed');
|
|
4
|
-
const { SPINNER } = require('../../constants');
|
|
5
|
-
|
|
6
|
-
function createFooter(screen) {
|
|
7
|
-
const widget = blessed.box({
|
|
8
|
-
bottom: 0, left: 0, width: '100%', height: 3,
|
|
9
|
-
tags: true,
|
|
10
|
-
style: { fg: 'white', bg: '#111133' },
|
|
11
|
-
});
|
|
12
|
-
screen.append(widget);
|
|
13
|
-
return widget;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function updateFooter(widget, state) {
|
|
17
|
-
const endTime = state.stats.endTime || Date.now();
|
|
18
|
-
const elapsed = ((endTime - state.stats.startTime) / 1000).toFixed(1);
|
|
19
|
-
const suiteStr = `${state.stats.suitesCompleted}/${state.stats.suites} suites`;
|
|
20
|
-
const spin = SPINNER[state.spinFrame];
|
|
21
|
-
const running = Object.values(state.suites).filter(s => !s.done).length;
|
|
22
|
-
const runningStr = running > 0 ? ` {yellow-fg}${spin} ${running} running{/yellow-fg} |` : '';
|
|
23
|
-
const hint = _getHint(state);
|
|
24
|
-
|
|
25
|
-
widget.setContent(
|
|
26
|
-
`{center}{grey-fg} Time: ${elapsed}s |${runningStr} ${suiteStr} | ${hint} | [q] quit {/grey-fg}{/center}`
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function _getHint(state) {
|
|
31
|
-
if (state.testDetailOpen) {
|
|
32
|
-
return '{cyan-fg}[Esc]{/cyan-fg} close | {cyan-fg}[j/k]{/cyan-fg} scroll';
|
|
33
|
-
}
|
|
34
|
-
if (state.suiteDetailOpen) {
|
|
35
|
-
return '{cyan-fg}[j/k]{/cyan-fg} navigate failed tests | {cyan-fg}[Enter]{/cyan-fg} open failure | {cyan-fg}[Esc]{/cyan-fg} back';
|
|
36
|
-
}
|
|
37
|
-
if (state.watchWaiting) {
|
|
38
|
-
return '{yellow-fg}[a]{/yellow-fg} run all tests';
|
|
39
|
-
}
|
|
40
|
-
if (state.focus === 'results') {
|
|
41
|
-
return '{cyan-fg}[Tab]{/cyan-fg} switch panel | {cyan-fg}[Enter]{/cyan-fg} open failure';
|
|
42
|
-
}
|
|
43
|
-
return '{cyan-fg}[Tab]{/cyan-fg} switch panel | {cyan-fg}[Enter]{/cyan-fg} open suite';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
module.exports = { createFooter, updateFooter };
|
package/lib/ui/panels/header.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const blessed = require('blessed');
|
|
4
|
-
|
|
5
|
-
function createHeader(screen) {
|
|
6
|
-
const widget = blessed.box({
|
|
7
|
-
top: 0, left: 0, width: '100%', height: 2,
|
|
8
|
-
content: '{center}{bold} JEST TEST DASHBOARD {/bold}{/center}',
|
|
9
|
-
tags: true,
|
|
10
|
-
style: { fg: 'white', bg: 'blue', bold: true },
|
|
11
|
-
});
|
|
12
|
-
screen.append(widget);
|
|
13
|
-
return widget;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function updateHeader(widget, ok) {
|
|
17
|
-
widget.style.bg = ok ? 'green' : 'red';
|
|
18
|
-
widget.setContent(
|
|
19
|
-
`{center}{bold} ${ok ? 'ALL TESTS PASSED' : 'SOME TESTS FAILED'} {/bold}{/center}`
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
module.exports = { createHeader, updateHeader };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const blessed = require('blessed');
|
|
4
|
-
|
|
5
|
-
function createProgress(screen) {
|
|
6
|
-
const widget = blessed.box({
|
|
7
|
-
top: 4, left: 0, width: '100%', height: 2,
|
|
8
|
-
tags: true,
|
|
9
|
-
style: { fg: 'white', bg: '#111133' },
|
|
10
|
-
});
|
|
11
|
-
screen.append(widget);
|
|
12
|
-
return widget;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function updateProgress(widget, stats, screenWidth) {
|
|
16
|
-
const suiteTotal = stats.suites || 1;
|
|
17
|
-
const pct = Math.min(100, Math.round((stats.suitesCompleted / suiteTotal) * 100));
|
|
18
|
-
const bar = _buildBar(pct, screenWidth, stats.failed > 0);
|
|
19
|
-
widget.setContent(` Progress: ${bar} ${pct}%`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function _buildBar(pct, screenWidth, hasFailed) {
|
|
23
|
-
const w = Math.max(20, (screenWidth || 80) - 20);
|
|
24
|
-
const filled = Math.round((pct / 100) * w);
|
|
25
|
-
const bar = '#'.repeat(filled) + '-'.repeat(w - filled);
|
|
26
|
-
const color = hasFailed ? 'red' : 'green';
|
|
27
|
-
return `{${color}-fg}${bar}{/${color}-fg}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
module.exports = { createProgress, updateProgress };
|
package/lib/ui/panels/results.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const blessed = require('blessed');
|
|
4
|
-
|
|
5
|
-
function createResults(screen) {
|
|
6
|
-
const widget = blessed.list({
|
|
7
|
-
top: 6, left: 0, width: '65%', bottom: 3,
|
|
8
|
-
label: ' Test Results ',
|
|
9
|
-
border: { type: 'line' },
|
|
10
|
-
tags: true, scrollable: true, alwaysScroll: true,
|
|
11
|
-
keys: false, mouse: false,
|
|
12
|
-
scrollbar: { ch: '|', style: { fg: 'cyan' } },
|
|
13
|
-
style: {
|
|
14
|
-
border: { fg: 'cyan' }, label: { fg: 'cyan', bold: true },
|
|
15
|
-
bg: '#0a0a1a', item: { fg: 'white', bg: '#0a0a1a' },
|
|
16
|
-
selected: { bg: '#1a1a4a', bold: true },
|
|
17
|
-
},
|
|
18
|
-
padding: { left: 1, right: 1 },
|
|
19
|
-
});
|
|
20
|
-
screen.append(widget);
|
|
21
|
-
return widget;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function refreshResults(widget, state) {
|
|
25
|
-
const overlayOpen = state.suiteDetailOpen || state.testDetailOpen;
|
|
26
|
-
const active = !overlayOpen && state.focus === 'results' && state.resultCursor >= 0;
|
|
27
|
-
widget.setItems(state.resultLines);
|
|
28
|
-
if (active) {
|
|
29
|
-
widget.select(state.resultCursor);
|
|
30
|
-
widget.scrollTo(state.resultCursor);
|
|
31
|
-
} else {
|
|
32
|
-
widget.select(-1);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function updateBorder(widget, focused) {
|
|
37
|
-
widget.style.border.fg = focused ? 'white' : 'cyan';
|
|
38
|
-
widget.setLabel(focused ? ' Test Results [FOCUSED] ' : ' Test Results ');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
module.exports = { createResults, refreshResults, updateBorder };
|
package/lib/ui/panels/stats.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const blessed = require('blessed');
|
|
4
|
-
|
|
5
|
-
function createStats(screen) {
|
|
6
|
-
const widget = blessed.box({
|
|
7
|
-
top: 2, left: 0, width: '100%', height: 2,
|
|
8
|
-
tags: true,
|
|
9
|
-
style: { fg: 'white', bg: '#111133' },
|
|
10
|
-
});
|
|
11
|
-
screen.append(widget);
|
|
12
|
-
return widget;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function updateStats(widget, stats) {
|
|
16
|
-
const { passed, failed, skipped, total } = stats;
|
|
17
|
-
widget.setContent(
|
|
18
|
-
'{center}' +
|
|
19
|
-
`{green-fg}{bold} PASSED: ${passed} {/bold}{/green-fg}` +
|
|
20
|
-
`{red-fg}{bold} FAILED: ${failed} {/bold}{/red-fg}` +
|
|
21
|
-
`{yellow-fg}{bold} SKIPPED: ${skipped} {/bold}{/yellow-fg}` +
|
|
22
|
-
`{white-fg} TOTAL: ${total} {/white-fg}` +
|
|
23
|
-
'{/center}'
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = { createStats, updateStats };
|
package/lib/ui/panels/suites.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const blessed = require('blessed');
|
|
4
|
-
const { SPINNER } = require('../../constants');
|
|
5
|
-
|
|
6
|
-
function createSuites(screen) {
|
|
7
|
-
const widget = blessed.list({
|
|
8
|
-
top: 6, right: 0, width: '35%', bottom: 3,
|
|
9
|
-
label: ' Suites ',
|
|
10
|
-
border: { type: 'line' },
|
|
11
|
-
tags: true, scrollable: true, alwaysScroll: true,
|
|
12
|
-
keys: false, mouse: false,
|
|
13
|
-
scrollbar: { ch: '|', style: { fg: 'magenta' } },
|
|
14
|
-
style: {
|
|
15
|
-
border: { fg: 'magenta' }, label: { fg: 'magenta', bold: true },
|
|
16
|
-
bg: '#0a0a1a', item: { fg: 'white', bg: '#0a0a1a' },
|
|
17
|
-
selected: { bg: '#1a0a3a', bold: true },
|
|
18
|
-
},
|
|
19
|
-
padding: { left: 1, right: 1 },
|
|
20
|
-
});
|
|
21
|
-
screen.append(widget);
|
|
22
|
-
return widget;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function updateSuites(widget, state) {
|
|
26
|
-
const spin = SPINNER[state.spinFrame];
|
|
27
|
-
const items = state.suiteOrder.map((path, i) => {
|
|
28
|
-
const s = state.suites[path];
|
|
29
|
-
const name = path.split('/').pop().replace(/\.test\.[jt]sx?$/, '');
|
|
30
|
-
const elapsed = s.startTime ? ` ${((Date.now() - s.startTime) / 1000).toFixed(1)}s` : '';
|
|
31
|
-
|
|
32
|
-
let icon, detail;
|
|
33
|
-
if (s.done) {
|
|
34
|
-
icon = s.failed > 0 ? '{red-fg}FAIL{/red-fg}' : '{green-fg}PASS{/green-fg}';
|
|
35
|
-
detail = ` {grey-fg}[${s.passed}p ${s.failed}f]{/grey-fg}`;
|
|
36
|
-
} else {
|
|
37
|
-
icon = `{yellow-fg}${spin}{/yellow-fg}`;
|
|
38
|
-
detail = `{grey-fg}${elapsed} [${s.passed}p ${s.failed}f]{/grey-fg}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const runningLines = s.running && s.running.size > 0
|
|
42
|
-
? '\n' + [...s.running].map(t => ` {cyan-fg}> ${t}{/cyan-fg}`).join('\n')
|
|
43
|
-
: '';
|
|
44
|
-
|
|
45
|
-
const isCursor = state.focus === 'suites' && !state.suiteDetailOpen && !state.testDetailOpen && i === state.suiteCursor;
|
|
46
|
-
const hint = isCursor ? ' {cyan-fg}[Enter]{/cyan-fg}' : '';
|
|
47
|
-
|
|
48
|
-
return `${icon} {white-fg}${name}{/white-fg}${detail}${hint}${runningLines}`;
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
widget.setItems(items.length ? items : ['{grey-fg}waiting...{/grey-fg}']);
|
|
52
|
-
const active = state.focus === 'suites' && !state.suiteDetailOpen && !state.testDetailOpen;
|
|
53
|
-
if (active && state.suiteCursor >= 0) {
|
|
54
|
-
widget.select(state.suiteCursor);
|
|
55
|
-
widget.scrollTo(state.suiteCursor);
|
|
56
|
-
} else {
|
|
57
|
-
widget.select(-1);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function updateBorder(widget, focused) {
|
|
62
|
-
widget.style.border.fg = focused ? 'white' : 'magenta';
|
|
63
|
-
widget.setLabel(focused ? ' Suites [FOCUSED] ' : ' Suites ');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
module.exports = { createSuites, updateSuites, updateBorder };
|
package/lib/ui/screen.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const blessed = require('blessed');
|
|
4
|
-
const { SPINNER } = require('../constants');
|
|
5
|
-
const { createHeader, updateHeader } = require('./panels/header');
|
|
6
|
-
const { createStats, updateStats } = require('./panels/stats');
|
|
7
|
-
const { createProgress, updateProgress } = require('./panels/progress');
|
|
8
|
-
const { createResults, refreshResults, updateBorder: updateResultsBorder } = require('./panels/results');
|
|
9
|
-
const { createSuites, updateSuites, updateBorder: updateSuitesBorder } = require('./panels/suites');
|
|
10
|
-
const { createFooter, updateFooter } = require('./panels/footer');
|
|
11
|
-
const { createSuiteDetail } = require('./overlays/suiteDetail');
|
|
12
|
-
const { createTestDetail } = require('./overlays/testDetail');
|
|
13
|
-
const { bindKeys, refreshOpenSuiteDetail } = require('./keys');
|
|
14
|
-
|
|
15
|
-
function createScreen(state) {
|
|
16
|
-
// Reuse screen and widgets across watch re-runs — Jest re-instantiates the
|
|
17
|
-
// reporter on every run, but we must not create a second blessed screen.
|
|
18
|
-
if (global.__jestronaut_ui__) {
|
|
19
|
-
const { screen, widgets, startTicker, state: sharedState } = global.__jestronaut_ui__;
|
|
20
|
-
screen.realloc();
|
|
21
|
-
return {
|
|
22
|
-
screen, widgets,
|
|
23
|
-
renderAll: () => renderAll(screen, widgets, sharedState),
|
|
24
|
-
refreshOpenSuiteDetail: () => refreshOpenSuiteDetail(widgets, sharedState),
|
|
25
|
-
startTicker,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const screen = blessed.screen({
|
|
30
|
-
smartCSR: true,
|
|
31
|
-
title: 'Jest Dashboard',
|
|
32
|
-
fullUnicode: false,
|
|
33
|
-
warnings: false,
|
|
34
|
-
terminal: 'xterm-256color',
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const widgets = {
|
|
38
|
-
header: createHeader(screen),
|
|
39
|
-
stats: createStats(screen),
|
|
40
|
-
progress: createProgress(screen),
|
|
41
|
-
results: createResults(screen),
|
|
42
|
-
suites: createSuites(screen),
|
|
43
|
-
footer: createFooter(screen),
|
|
44
|
-
suiteDetail: createSuiteDetail(screen),
|
|
45
|
-
testDetail: createTestDetail(screen),
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// render helpers passed to key bindings
|
|
49
|
-
const render = {
|
|
50
|
-
all: () => renderAll(screen, widgets, state),
|
|
51
|
-
destroy: () => {
|
|
52
|
-
if (state._ticker) clearInterval(state._ticker);
|
|
53
|
-
screen.destroy();
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
bindKeys(screen, widgets, state, render);
|
|
58
|
-
|
|
59
|
-
function startTicker() {
|
|
60
|
-
if (state._ticker) clearInterval(state._ticker);
|
|
61
|
-
state._ticker = setInterval(() => {
|
|
62
|
-
state.spinFrame = (state.spinFrame + 1) % SPINNER.length;
|
|
63
|
-
updateSuites(widgets.suites, state);
|
|
64
|
-
updateFooter(widgets.footer, state);
|
|
65
|
-
screen.render();
|
|
66
|
-
}, 120);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
global.__jestronaut_ui__ = { screen, widgets, startTicker, state };
|
|
70
|
-
|
|
71
|
-
startTicker();
|
|
72
|
-
renderAll(screen, widgets, state);
|
|
73
|
-
|
|
74
|
-
return { screen, widgets, renderAll: () => renderAll(screen, widgets, state), refreshOpenSuiteDetail: () => refreshOpenSuiteDetail(widgets, state), startTicker };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function renderAll(screen, widgets, state) {
|
|
78
|
-
// Only pass keypresses to Jest's watch mode when truly idle:
|
|
79
|
-
// watch waiting, no overlays, and no results to navigate
|
|
80
|
-
global.__jestronaut_block_jest_input__ = !(
|
|
81
|
-
state.watchWaiting &&
|
|
82
|
-
!state.suiteDetailOpen &&
|
|
83
|
-
!state.testDetailOpen &&
|
|
84
|
-
state.resultLines.length === 0
|
|
85
|
-
);
|
|
86
|
-
updateStats(widgets.stats, state.stats);
|
|
87
|
-
updateProgress(widgets.progress, state.stats, screen.width);
|
|
88
|
-
updateSuites(widgets.suites, state);
|
|
89
|
-
updateFooter(widgets.footer, state);
|
|
90
|
-
_updateBorders(widgets, state);
|
|
91
|
-
refreshResults(widgets.results, state);
|
|
92
|
-
screen.render();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function _updateBorders(widgets, state) {
|
|
96
|
-
updateResultsBorder(widgets.results, state.focus === 'results');
|
|
97
|
-
updateSuitesBorder(widgets.suites, state.focus === 'suites');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
module.exports = { createScreen };
|