@molecule/app-ide-react 1.15.0 → 1.17.0
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/README.md +193 -7
- package/dist/components/ChatPanel.d.ts +10 -1
- package/dist/components/ChatPanel.d.ts.map +1 -1
- package/dist/components/ChatPanel.js +136 -14
- package/dist/components/ChatPanel.js.map +1 -1
- package/dist/components/MarkdownContent.d.ts.map +1 -1
- package/dist/components/MarkdownContent.js +27 -7
- package/dist/components/MarkdownContent.js.map +1 -1
- package/dist/components/TestStatusBar.d.ts +56 -0
- package/dist/components/TestStatusBar.d.ts.map +1 -0
- package/dist/components/TestStatusBar.js +105 -0
- package/dist/components/TestStatusBar.js.map +1 -0
- package/dist/components/TestsCard.d.ts +15 -2
- package/dist/components/TestsCard.d.ts.map +1 -1
- package/dist/components/TestsCard.js +42 -9
- package/dist/components/TestsCard.js.map +1 -1
- package/dist/components/ToolCallCard.d.ts +7 -1
- package/dist/components/ToolCallCard.d.ts.map +1 -1
- package/dist/components/ToolCallCard.js +516 -161
- package/dist/components/ToolCallCard.js.map +1 -1
- package/dist/components/tests-bar-utilities.d.ts +78 -103
- package/dist/components/tests-bar-utilities.d.ts.map +1 -1
- package/dist/components/tests-bar-utilities.js +130 -201
- package/dist/components/tests-bar-utilities.js.map +1 -1
- package/dist/components/tests-card-utilities.d.ts +78 -2
- package/dist/components/tests-card-utilities.d.ts.map +1 -1
- package/dist/components/tests-card-utilities.js +134 -6
- package/dist/components/tests-card-utilities.js.map +1 -1
- package/dist/components/tool-call-utilities.d.ts +81 -7
- package/dist/components/tool-call-utilities.d.ts.map +1 -1
- package/dist/components/tool-call-utilities.js +146 -6
- package/dist/components/tool-call-utilities.js.map +1 -1
- package/dist/hooks/useTestsBarVisible.d.ts +16 -0
- package/dist/hooks/useTestsBarVisible.d.ts.map +1 -0
- package/dist/hooks/useTestsBarVisible.js +39 -0
- package/dist/hooks/useTestsBarVisible.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +60 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,236 +1,165 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The tests status bar — its visibility preference and the pure summary the bar
|
|
3
|
+
* renders. The component is `TestStatusBar.tsx`; the hook is
|
|
4
|
+
* `hooks/useTestsBarVisible.ts`.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* the
|
|
6
|
+
* Visibility is a PER-DEVICE, per-user display preference in localStorage, the
|
|
7
|
+
* same shape as `/timestamps` and `/sounds` — never project settings, so a
|
|
8
|
+
* viewer can hide the bar without changing what a teammate sees. It defaults to
|
|
9
|
+
* SHOWN: a run drives the project's preview as it goes, and a preview that moves
|
|
10
|
+
* on its own with nothing on screen to explain it is the problem this bar
|
|
11
|
+
* exists to remove.
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export const MAX_OUTPUT_LINES = 400;
|
|
12
|
-
/** Display order of the kinds: the preview-driven specs lead, unit tests follow. */
|
|
13
|
-
const KIND_ORDER = ['e2e', 'unit'];
|
|
14
|
-
/**
|
|
15
|
-
* Display order of the project directories within a kind: by path, with the
|
|
16
|
-
* workspace root (`.`) last — it is the least specific place a test can live.
|
|
13
|
+
* Shown, however, still means "once the project HAS tests" — see
|
|
14
|
+
* {@link shouldShowTestsBar}. The preference decides whether the person wants
|
|
15
|
+
* the bar; that predicate decides whether there is anything for it to say.
|
|
17
16
|
*
|
|
18
|
-
* @
|
|
19
|
-
* @param b - The other.
|
|
20
|
-
* @returns The sort order.
|
|
17
|
+
* @module
|
|
21
18
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return 1;
|
|
27
|
-
if (b === '.')
|
|
28
|
-
return -1;
|
|
29
|
-
return a.localeCompare(b);
|
|
30
|
-
}
|
|
19
|
+
/** localStorage key holding `'true'` / `'false'`. Absent = the default (shown). */
|
|
20
|
+
export const TESTS_BAR_STORAGE_KEY = 'mol_chat_show_tests_bar';
|
|
21
|
+
/** Window event dispatched (same tab) whenever the preference changes. */
|
|
22
|
+
export const TESTS_BAR_EVENT = 'mol:tests-bar-changed';
|
|
31
23
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
24
|
+
* Parses the stored preference. Only an explicit `'false'` hides the bar, so a
|
|
25
|
+
* missing or unreadable value keeps the default (shown).
|
|
34
26
|
*
|
|
35
|
-
* @param
|
|
36
|
-
* @returns
|
|
27
|
+
* @param raw - The raw localStorage value.
|
|
28
|
+
* @returns Whether the tests bar is visible.
|
|
37
29
|
*/
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
return item.workspaceLabel;
|
|
41
|
-
return item.workspace === '.' ? null : item.workspace;
|
|
30
|
+
export function parseTestsBarVisible(raw) {
|
|
31
|
+
return raw !== 'false';
|
|
42
32
|
}
|
|
43
|
-
/** A run that has not started. */
|
|
44
|
-
export const EMPTY_RUN_STATE = {
|
|
45
|
-
runId: null,
|
|
46
|
-
running: false,
|
|
47
|
-
queued: [],
|
|
48
|
-
currentId: null,
|
|
49
|
-
output: [],
|
|
50
|
-
results: {},
|
|
51
|
-
outcome: null,
|
|
52
|
-
error: null,
|
|
53
|
-
startedAt: null,
|
|
54
|
-
durationMs: null,
|
|
55
|
-
};
|
|
56
33
|
/**
|
|
57
|
-
*
|
|
58
|
-
* directory (whatever directories are present — `app`, `my-app/app`,
|
|
59
|
-
* `packages/web`, the root last), with the files sorted inside each group.
|
|
34
|
+
* Reads this device's preference.
|
|
60
35
|
*
|
|
61
|
-
* @
|
|
62
|
-
* @returns The groups, in display order. Empty groups are never produced.
|
|
36
|
+
* @returns Whether the tests bar is visible (default `true`).
|
|
63
37
|
*/
|
|
64
|
-
export function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const workspaces = [
|
|
68
|
-
...new Set(tests.filter((t) => t.kind === kind).map((t) => t.workspace)),
|
|
69
|
-
].sort(compareWorkspaces);
|
|
70
|
-
for (const workspace of workspaces) {
|
|
71
|
-
const items = tests
|
|
72
|
-
.filter((t) => t.kind === kind && t.workspace === workspace)
|
|
73
|
-
.slice()
|
|
74
|
-
.sort((a, b) => a.file.localeCompare(b.file));
|
|
75
|
-
if (items.length > 0)
|
|
76
|
-
groups.push({ kind, workspace, label: labelFor(items[0]), items });
|
|
77
|
-
}
|
|
38
|
+
export function getTestsBarVisible() {
|
|
39
|
+
try {
|
|
40
|
+
return parseTestsBarVisible(localStorage.getItem(TESTS_BAR_STORAGE_KEY));
|
|
78
41
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* How many tests there are of each kind.
|
|
83
|
-
*
|
|
84
|
-
* @param tests - Every discovered test.
|
|
85
|
-
* @returns The per-kind counts.
|
|
86
|
-
*/
|
|
87
|
-
export function countByKind(tests) {
|
|
88
|
-
return {
|
|
89
|
-
e2e: tests.filter((t) => t.kind === 'e2e').length,
|
|
90
|
-
unit: tests.filter((t) => t.kind === 'unit').length,
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* The tallies of the last run, over the tests that are still listed. Counted
|
|
95
|
-
* per FILE (one row, one verdict) so the collapsed summary matches the rows.
|
|
96
|
-
*
|
|
97
|
-
* @param tests - The currently listed tests.
|
|
98
|
-
* @param results - The per-id outcomes.
|
|
99
|
-
* @returns Passed/failed/skipped file counts.
|
|
100
|
-
*/
|
|
101
|
-
export function summarizeResults(tests, results) {
|
|
102
|
-
let passed = 0;
|
|
103
|
-
let failed = 0;
|
|
104
|
-
let skipped = 0;
|
|
105
|
-
for (const test of tests) {
|
|
106
|
-
const entry = results[test.id];
|
|
107
|
-
if (!entry)
|
|
108
|
-
continue;
|
|
109
|
-
if (entry.status === 'passed')
|
|
110
|
-
passed += 1;
|
|
111
|
-
else if (entry.status === 'failed')
|
|
112
|
-
failed += 1;
|
|
113
|
-
else
|
|
114
|
-
skipped += 1;
|
|
42
|
+
catch (_error) {
|
|
43
|
+
// localStorage unavailable (private mode, SSR) — fall back to the default.
|
|
44
|
+
return true;
|
|
115
45
|
}
|
|
116
|
-
return { passed, failed, skipped, reported: passed + failed + skipped };
|
|
117
46
|
}
|
|
118
47
|
/**
|
|
119
|
-
*
|
|
48
|
+
* Writes this device's preference and tells every mounted chat in this tab.
|
|
120
49
|
*
|
|
121
|
-
*
|
|
122
|
-
* anyway (a re-list may be in flight), and an unknown event type leaves the
|
|
123
|
-
* state untouched rather than throwing inside a stream handler.
|
|
124
|
-
*
|
|
125
|
-
* @param state - The current state.
|
|
126
|
-
* @param event - The event just received.
|
|
127
|
-
* @returns The next state (a new object whenever anything changed).
|
|
50
|
+
* @param visible - Whether the bar should be shown.
|
|
128
51
|
*/
|
|
129
|
-
export function
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
queued: [...event.ids],
|
|
142
|
-
currentId: null,
|
|
143
|
-
output: [],
|
|
144
|
-
results,
|
|
145
|
-
outcome: null,
|
|
146
|
-
error: null,
|
|
147
|
-
startedAt: Date.now(),
|
|
148
|
-
durationMs: null,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
case 'output': {
|
|
152
|
-
const output = [...state.output, ...event.chunk.split('\n')];
|
|
153
|
-
return {
|
|
154
|
-
...state,
|
|
155
|
-
currentId: event.id ?? state.currentId,
|
|
156
|
-
output: output.length > MAX_OUTPUT_LINES ? output.slice(-MAX_OUTPUT_LINES) : output,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
case 'result': {
|
|
160
|
-
return {
|
|
161
|
-
...state,
|
|
162
|
-
results: {
|
|
163
|
-
...state.results,
|
|
164
|
-
[event.id]: {
|
|
165
|
-
status: event.status,
|
|
166
|
-
...(event.durationMs != null ? { durationMs: event.durationMs } : {}),
|
|
167
|
-
passed: event.passed ?? 0,
|
|
168
|
-
failed: event.failed ?? 0,
|
|
169
|
-
skipped: event.skipped ?? 0,
|
|
170
|
-
...(event.output ? { output: event.output } : {}),
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
case 'done': {
|
|
176
|
-
return {
|
|
177
|
-
...state,
|
|
178
|
-
running: false,
|
|
179
|
-
currentId: null,
|
|
180
|
-
outcome: event.outcome,
|
|
181
|
-
error: event.error ?? null,
|
|
182
|
-
durationMs: event.durationMs ?? (state.startedAt ? Date.now() - state.startedAt : null),
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
default:
|
|
186
|
-
return state;
|
|
52
|
+
export function setTestsBarVisible(visible) {
|
|
53
|
+
try {
|
|
54
|
+
localStorage.setItem(TESTS_BAR_STORAGE_KEY, visible ? 'true' : 'false');
|
|
55
|
+
}
|
|
56
|
+
catch (_error) {
|
|
57
|
+
// Unwritable storage still fires the event, so the current tab follows.
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
window.dispatchEvent(new CustomEvent(TESTS_BAR_EVENT, { detail: { visible } }));
|
|
61
|
+
}
|
|
62
|
+
catch (_error) {
|
|
63
|
+
// No window (SSR) — nothing is mounted to notify.
|
|
187
64
|
}
|
|
188
65
|
}
|
|
189
66
|
/**
|
|
190
|
-
*
|
|
191
|
-
*
|
|
67
|
+
* What `/test on|off|toggle` means. Anything else is not a visibility request —
|
|
68
|
+
* bare `/test` opens the tests browser, which is a different thing entirely.
|
|
192
69
|
*
|
|
193
|
-
* @param
|
|
194
|
-
* @param
|
|
195
|
-
* @returns The
|
|
70
|
+
* @param args - The text after `/test`.
|
|
71
|
+
* @param current - The current visibility, for `toggle`.
|
|
72
|
+
* @returns The requested visibility, or null when the argument is not one.
|
|
196
73
|
*/
|
|
197
|
-
export function
|
|
198
|
-
|
|
74
|
+
export function parseTestsBarArg(args, current) {
|
|
75
|
+
const word = args.trim().toLowerCase();
|
|
76
|
+
if (word === 'on' || word === 'show' || word === 'bar on')
|
|
77
|
+
return true;
|
|
78
|
+
if (word === 'off' || word === 'hide' || word === 'bar off')
|
|
79
|
+
return false;
|
|
80
|
+
if (word === 'toggle' || word === 'bar')
|
|
81
|
+
return !current;
|
|
82
|
+
return null;
|
|
199
83
|
}
|
|
200
84
|
/**
|
|
201
|
-
* Whether
|
|
202
|
-
* named this row as current, or it is in the queue and has no verdict yet.
|
|
85
|
+
* Whether there is anything for the bar to report.
|
|
203
86
|
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
87
|
+
* A project with no tests yet gets NO bar. The strip earns its slot above the
|
|
88
|
+
* composer by accounting for something — a suite's verdict, a run driving the
|
|
89
|
+
* preview — and a project that has not been given tests has neither; an empty
|
|
90
|
+
* strip saying "Tests not run yet" is noise in exactly the projects that are
|
|
91
|
+
* least ready for it. It appears on its own the moment discovery finds a spec.
|
|
92
|
+
*
|
|
93
|
+
* The run clauses come second on purpose: a run in flight, a run-level error or
|
|
94
|
+
* a finished outcome all mean tests EXIST, whatever the discovered list happens
|
|
95
|
+
* to hold at that moment (a list can be empty because discovery has not
|
|
96
|
+
* answered yet, not because the project is bare).
|
|
97
|
+
*
|
|
98
|
+
* @param run - The live run state.
|
|
99
|
+
* @param tests - The discovered tests.
|
|
100
|
+
* @returns Whether the bar should render at all.
|
|
207
101
|
*/
|
|
208
|
-
export function
|
|
209
|
-
if (
|
|
210
|
-
return false;
|
|
211
|
-
if (state.currentId === id)
|
|
102
|
+
export function shouldShowTestsBar(run, tests) {
|
|
103
|
+
if (tests.length > 0)
|
|
212
104
|
return true;
|
|
213
|
-
|
|
105
|
+
if (run.running || run.error != null || run.outcome != null)
|
|
106
|
+
return true;
|
|
107
|
+
return Object.keys(run.results).length > 0;
|
|
214
108
|
}
|
|
215
109
|
/**
|
|
216
|
-
*
|
|
110
|
+
* Derive everything the bar shows from the run state.
|
|
217
111
|
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return item.title?.trim() || item.file;
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Whether a written path is a test file, so the bar can re-list the moment the
|
|
226
|
-
* agent writes a NEW spec instead of only on the next run or reload. Matches
|
|
227
|
-
* the same `*.spec.*` / `*.test.*` shape the host's discovery looks for, so a
|
|
228
|
-
* write that cannot change the list never costs a listing.
|
|
112
|
+
* The tone is deliberately NOT "whatever the last file did": a single failing
|
|
113
|
+
* file among twenty passing ones is a failing suite, because that is the thing
|
|
114
|
+
* the person has to act on. Running always wins, since a count that is still
|
|
115
|
+
* moving is not a verdict.
|
|
229
116
|
*
|
|
230
|
-
* @param
|
|
231
|
-
* @
|
|
117
|
+
* @param run - The chat panel's live run state.
|
|
118
|
+
* @param tests - The discovered tests, used to name the file running now.
|
|
119
|
+
* @returns The summary the bar renders.
|
|
232
120
|
*/
|
|
233
|
-
export function
|
|
234
|
-
|
|
121
|
+
export function summariseTestsBar(run, tests) {
|
|
122
|
+
let passed = 0;
|
|
123
|
+
let failed = 0;
|
|
124
|
+
let skipped = 0;
|
|
125
|
+
for (const entry of Object.values(run.results)) {
|
|
126
|
+
if (entry.status === 'passed')
|
|
127
|
+
passed++;
|
|
128
|
+
else if (entry.status === 'failed')
|
|
129
|
+
failed++;
|
|
130
|
+
else if (entry.status === 'skipped')
|
|
131
|
+
skipped++;
|
|
132
|
+
}
|
|
133
|
+
const byId = new Map(tests.map((test) => [test.id, test]));
|
|
134
|
+
const current = run.currentId ? (byId.get(run.currentId) ?? null) : null;
|
|
135
|
+
const progress = run.currentId ? run.cases[run.currentId] : undefined;
|
|
136
|
+
const currentCase = progress?.current ?? null;
|
|
137
|
+
const currentTest = currentCase
|
|
138
|
+
? currentCase.describe
|
|
139
|
+
? `${currentCase.describe} › ${currentCase.title}`
|
|
140
|
+
: currentCase.title
|
|
141
|
+
: null;
|
|
142
|
+
const done = passed + failed + skipped;
|
|
143
|
+
const remaining = run.running ? Math.max(0, run.queued.length - done) : 0;
|
|
144
|
+
const tone = run.running
|
|
145
|
+
? 'running'
|
|
146
|
+
: run.error
|
|
147
|
+
? 'error'
|
|
148
|
+
: run.outcome === 'cancelled' || run.outcome === 'skipped-by-user'
|
|
149
|
+
? 'stopped'
|
|
150
|
+
: failed > 0
|
|
151
|
+
? 'failing'
|
|
152
|
+
: passed > 0
|
|
153
|
+
? 'passing'
|
|
154
|
+
: 'idle';
|
|
155
|
+
return {
|
|
156
|
+
tone,
|
|
157
|
+
passed,
|
|
158
|
+
failed,
|
|
159
|
+
skipped,
|
|
160
|
+
remaining,
|
|
161
|
+
currentFile: current?.title ?? current?.file ?? null,
|
|
162
|
+
currentTest,
|
|
163
|
+
};
|
|
235
164
|
}
|
|
236
165
|
//# sourceMappingURL=tests-bar-utilities.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tests-bar-utilities.js","sourceRoot":"","sources":["../../src/components/tests-bar-utilities.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tests-bar-utilities.js","sourceRoot":"","sources":["../../src/components/tests-bar-utilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,25 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
import type { TestItem, TestKind, TestRunEvent, TestRunOutcome, TestStatus, TestWorkspace } from '../types.js';
|
|
11
|
+
/** The one test a file is on right now, named the way its runner names it. */
|
|
12
|
+
export interface TestCaseRef {
|
|
13
|
+
/** The runner's test title. */
|
|
14
|
+
title: string;
|
|
15
|
+
/** Its enclosing group (`describe`), when it has one. */
|
|
16
|
+
describe?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* What one FILE is doing while it runs: which test is on screen, and how its
|
|
20
|
+
* own tests have gone so far. Discarded the moment the file reports a `result`
|
|
21
|
+
* — the row's verdict pill takes over from there.
|
|
22
|
+
*/
|
|
23
|
+
export interface TestCaseProgress {
|
|
24
|
+
/** The test running right now, or `null` between tests. */
|
|
25
|
+
current: TestCaseRef | null;
|
|
26
|
+
passed: number;
|
|
27
|
+
failed: number;
|
|
28
|
+
skipped: number;
|
|
29
|
+
}
|
|
11
30
|
/** One rendered group of rows: a kind within a project directory. */
|
|
12
31
|
export interface TestGroup {
|
|
13
32
|
kind: TestKind;
|
|
@@ -38,6 +57,19 @@ export interface TestsRunState {
|
|
|
38
57
|
output: string[];
|
|
39
58
|
/** Per-id outcome from this run (and from earlier runs, until re-run). */
|
|
40
59
|
results: Record<string, TestResultEntry>;
|
|
60
|
+
/**
|
|
61
|
+
* Per-id LIVE per-test progress, for the files that are running right now.
|
|
62
|
+
* An entry exists only between a file's first `case` event and its `result`.
|
|
63
|
+
*/
|
|
64
|
+
cases: Record<string, TestCaseProgress>;
|
|
65
|
+
/** A skip was asked for and the run has not answered it yet. */
|
|
66
|
+
skipPending: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Skipping is not on offer: the host wired no `skipCurrent`, or it answered
|
|
69
|
+
* that there was nothing left to skip. The control is dropped — never
|
|
70
|
+
* replaced by an error the person cannot act on.
|
|
71
|
+
*/
|
|
72
|
+
skipUnavailable: boolean;
|
|
41
73
|
/** How the run ended, once it has. */
|
|
42
74
|
outcome: TestRunOutcome | null;
|
|
43
75
|
/** A run-level failure message (timeout, transport error) shown in the card. */
|
|
@@ -83,14 +115,58 @@ export declare function summarizeResults(tests: readonly TestItem[], results: Re
|
|
|
83
115
|
* Fold one streamed event into the run state.
|
|
84
116
|
*
|
|
85
117
|
* Deliberately total: an event for an id the card no longer lists is recorded
|
|
86
|
-
* anyway (a re-list may be in flight),
|
|
87
|
-
*
|
|
118
|
+
* anyway (a re-list may be in flight), a `case` that arrives out of order (after
|
|
119
|
+
* its file already reported a verdict) is dropped rather than resurrecting a
|
|
120
|
+
* finished row, and an unknown event type leaves the state untouched rather
|
|
121
|
+
* than throwing inside a stream handler.
|
|
88
122
|
*
|
|
89
123
|
* @param state - The current state.
|
|
90
124
|
* @param event - The event just received.
|
|
91
125
|
* @returns The next state (a new object whenever anything changed).
|
|
92
126
|
*/
|
|
93
127
|
export declare function applyTestRunEvent(state: TestsRunState, event: TestRunEvent): TestsRunState;
|
|
128
|
+
/**
|
|
129
|
+
* Record that the person asked to skip what is running. The state only says a
|
|
130
|
+
* request is OUT — the run's own `result` for the skipped file is what actually
|
|
131
|
+
* moves the row, so nothing here can make a skipped file read as anything else.
|
|
132
|
+
*
|
|
133
|
+
* @param state - The current state.
|
|
134
|
+
* @returns The next state, or the same one when there is nothing to skip.
|
|
135
|
+
*/
|
|
136
|
+
export declare function requestSkip(state: TestsRunState): TestsRunState;
|
|
137
|
+
/**
|
|
138
|
+
* Record that skipping is not on offer — either the host wired no `skipCurrent`
|
|
139
|
+
* or it answered that the run had already moved on. The control is dropped; the
|
|
140
|
+
* person is not shown an error about a race they did not cause.
|
|
141
|
+
*
|
|
142
|
+
* @param state - The current state.
|
|
143
|
+
* @returns The next state.
|
|
144
|
+
*/
|
|
145
|
+
export declare function markSkipUnavailable(state: TestsRunState): TestsRunState;
|
|
146
|
+
/**
|
|
147
|
+
* Whether the host can be asked to skip right now.
|
|
148
|
+
*
|
|
149
|
+
* @param state - The run state.
|
|
150
|
+
* @returns True when a Skip control belongs on screen.
|
|
151
|
+
*/
|
|
152
|
+
export declare function canSkipRun(state: TestsRunState): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Which row the Skip acts on: the one the stream named as current, or — when it
|
|
155
|
+
* has not named one yet — the single row still awaiting a verdict, because with
|
|
156
|
+
* exactly one candidate there is nothing to be ambiguous about.
|
|
157
|
+
*
|
|
158
|
+
* @param state - The run state.
|
|
159
|
+
* @returns The row's id, or `null` when the run is not on an identifiable row.
|
|
160
|
+
*/
|
|
161
|
+
export declare function currentRunRowId(state: TestsRunState): string | null;
|
|
162
|
+
/**
|
|
163
|
+
* The one-line name of the test a file is on: its group and its title, or just
|
|
164
|
+
* its title when the runner gave it no group.
|
|
165
|
+
*
|
|
166
|
+
* @param current - The running test, or `null`.
|
|
167
|
+
* @returns The label, or `` when nothing is named.
|
|
168
|
+
*/
|
|
169
|
+
export declare function testCaseLabel(current: TestCaseRef | null | undefined): string;
|
|
94
170
|
/**
|
|
95
171
|
* The state after a run that never produced a `done` event — the host's stream
|
|
96
172
|
* died, or its request failed before the server could answer.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tests-card-utilities.d.ts","sourceRoot":"","sources":["../../src/components/tests-card-utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,UAAU,EACV,aAAa,EACd,MAAM,aAAa,CAAA;AAEpB,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,QAAQ,CAAA;IACd,SAAS,EAAE,aAAa,CAAA;IACxB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAA;CAClB;AAED,mDAAmD;AACnD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,6DAA6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,OAAO,CAAA;IAChB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IACxC,sCAAsC;IACtC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IAC9B,gFAAgF;IAChF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,gGAAgG;AAChG,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAgCnC,kCAAkC;AAClC,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"tests-card-utilities.d.ts","sourceRoot":"","sources":["../../src/components/tests-card-utilities.ts"],"names":[],"mappings":"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"}
|