@opensumi/ide-testing 2.21.13 → 2.22.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.
Files changed (109) hide show
  1. package/lib/browser/components/testing.explorer.tree.d.ts.map +1 -1
  2. package/lib/browser/components/testing.explorer.tree.js +7 -5
  3. package/lib/browser/components/testing.explorer.tree.js.map +1 -1
  4. package/lib/browser/components/testing.view.js +1 -1
  5. package/lib/browser/components/testing.view.js.map +1 -1
  6. package/lib/browser/icons/icons.d.ts +1 -0
  7. package/lib/browser/icons/icons.d.ts.map +1 -1
  8. package/lib/browser/icons/icons.js +15 -14
  9. package/lib/browser/icons/icons.js.map +1 -1
  10. package/lib/browser/index.js.map +1 -1
  11. package/lib/browser/outputPeek/test-output-peek.js +9 -9
  12. package/lib/browser/outputPeek/test-output-peek.js.map +1 -1
  13. package/lib/browser/outputPeek/test-peek-message.service.js.map +1 -1
  14. package/lib/browser/outputPeek/test-peek-opener.service.js +1 -1
  15. package/lib/browser/outputPeek/test-peek-opener.service.js.map +1 -1
  16. package/lib/browser/outputPeek/test-peek-widget.js +1 -1
  17. package/lib/browser/outputPeek/test-peek-widget.js.map +1 -1
  18. package/lib/browser/outputPeek/test-tree-container.js +2 -2
  19. package/lib/browser/outputPeek/test-tree-container.js.map +1 -1
  20. package/lib/browser/test-contextkey.service.js.map +1 -1
  21. package/lib/browser/test-decorations.js +19 -19
  22. package/lib/browser/test-decorations.js.map +1 -1
  23. package/lib/browser/test-profile.service.js.map +1 -1
  24. package/lib/browser/test-tree-view.model.d.ts +1 -0
  25. package/lib/browser/test-tree-view.model.d.ts.map +1 -1
  26. package/lib/browser/test-tree-view.model.js +13 -10
  27. package/lib/browser/test-tree-view.model.js.map +1 -1
  28. package/lib/browser/test.result.service.d.ts +1 -1
  29. package/lib/browser/test.result.service.d.ts.map +1 -1
  30. package/lib/browser/test.result.service.js +5 -5
  31. package/lib/browser/test.result.service.js.map +1 -1
  32. package/lib/browser/test.service.d.ts +4 -0
  33. package/lib/browser/test.service.d.ts.map +1 -1
  34. package/lib/browser/test.service.js +31 -4
  35. package/lib/browser/test.service.js.map +1 -1
  36. package/lib/browser/testing.contribution.d.ts.map +1 -1
  37. package/lib/browser/testing.contribution.js +21 -10
  38. package/lib/browser/testing.contribution.js.map +1 -1
  39. package/lib/common/commands.d.ts +1 -0
  40. package/lib/common/commands.d.ts.map +1 -1
  41. package/lib/common/commands.js +6 -1
  42. package/lib/common/commands.js.map +1 -1
  43. package/lib/common/constants.js +12 -12
  44. package/lib/common/constants.js.map +1 -1
  45. package/lib/common/getComputedState.d.ts +1 -1
  46. package/lib/common/getComputedState.d.ts.map +1 -1
  47. package/lib/common/getComputedState.js +1 -1
  48. package/lib/common/getComputedState.js.map +1 -1
  49. package/lib/common/index.d.ts +5 -0
  50. package/lib/common/index.d.ts.map +1 -1
  51. package/lib/common/index.js.map +1 -1
  52. package/lib/common/observableValue.d.ts +14 -0
  53. package/lib/common/observableValue.d.ts.map +1 -0
  54. package/lib/common/observableValue.js +23 -0
  55. package/lib/common/observableValue.js.map +1 -0
  56. package/lib/common/test-result.d.ts +2 -2
  57. package/lib/common/test-result.d.ts.map +1 -1
  58. package/lib/common/test-result.js +19 -19
  59. package/lib/common/test-result.js.map +1 -1
  60. package/lib/common/testCollection.d.ts +9 -8
  61. package/lib/common/testCollection.d.ts.map +1 -1
  62. package/lib/common/testCollection.js +27 -27
  63. package/lib/common/testCollection.js.map +1 -1
  64. package/lib/common/testId.js +21 -21
  65. package/lib/common/testId.js.map +1 -1
  66. package/lib/common/testingStates.js +11 -11
  67. package/lib/common/testingStates.js.map +1 -1
  68. package/lib/common/testingUri.d.ts +1 -1
  69. package/lib/common/testingUri.d.ts.map +1 -1
  70. package/lib/common/testingUri.js +16 -16
  71. package/lib/common/testingUri.js.map +1 -1
  72. package/package.json +14 -13
  73. package/src/browser/components/testing.explorer.tree.tsx +129 -0
  74. package/src/browser/components/testing.module.less +26 -0
  75. package/src/browser/components/testing.view.tsx +35 -0
  76. package/src/browser/icons/icons.less +31 -0
  77. package/src/browser/icons/icons.ts +31 -0
  78. package/src/browser/index.ts +51 -0
  79. package/src/browser/outputPeek/test-message-container.tsx +183 -0
  80. package/src/browser/outputPeek/test-output-peek.ts +282 -0
  81. package/src/browser/outputPeek/test-peek-message.service.ts +15 -0
  82. package/src/browser/outputPeek/test-peek-opener.service.ts +131 -0
  83. package/src/browser/outputPeek/test-peek-widget.less +86 -0
  84. package/src/browser/outputPeek/test-peek-widget.tsx +127 -0
  85. package/src/browser/outputPeek/test-tree-container.tsx +171 -0
  86. package/src/browser/test-contextkey.service.ts +24 -0
  87. package/src/browser/test-decorations.ts +567 -0
  88. package/src/browser/test-profile.service.ts +66 -0
  89. package/src/browser/test-tree-view.model.ts +304 -0
  90. package/src/browser/test.result.service.ts +193 -0
  91. package/src/browser/test.service.ts +190 -0
  92. package/src/browser/testing.contribution.ts +471 -0
  93. package/src/browser/theme.less +6 -0
  94. package/src/common/commands.ts +78 -0
  95. package/src/common/constants.ts +57 -0
  96. package/src/common/contextKeys.ts +0 -0
  97. package/src/common/getComputedState.ts +136 -0
  98. package/src/common/index.ts +55 -0
  99. package/src/common/observableValue.ts +27 -0
  100. package/src/common/test-profile.ts +25 -0
  101. package/src/common/test-result.ts +328 -0
  102. package/src/common/testCollection.ts +680 -0
  103. package/src/common/testId.ts +191 -0
  104. package/src/common/testing-view.ts +28 -0
  105. package/src/common/testingPeekOpener.ts +31 -0
  106. package/src/common/testingStates.ts +92 -0
  107. package/src/common/testingUri.ts +101 -0
  108. package/src/common/tree-view.model.ts +41 -0
  109. package/src/index.ts +1 -0
@@ -0,0 +1,136 @@
1
+ /* ---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ import { Iterable } from '@opensumi/monaco-editor-core/esm/vs/base/common/iterator';
7
+
8
+ import { TestResultState } from './testCollection';
9
+ import { maxPriority, statePriority } from './testingStates';
10
+
11
+ /**
12
+ * Accessor for nodes in get and refresh computed state.
13
+ */
14
+ export interface IComputedStateAccessor<T> {
15
+ getOwnState(item: T): TestResultState | undefined;
16
+ getCurrentComputedState(item: T): TestResultState;
17
+ setComputedState(item: T, state: TestResultState): void;
18
+ getChildren(item: T): Iterable<T>;
19
+ getParents(item: T): Iterable<T>;
20
+ }
21
+
22
+ export interface IComputedStateAndDurationAccessor<T> extends IComputedStateAccessor<T> {
23
+ getOwnDuration(item: T): number | undefined;
24
+ getCurrentComputedDuration(item: T): number | undefined;
25
+ setComputedDuration(item: T, duration: number | undefined): void;
26
+ }
27
+
28
+ export const isDurationAccessor = <T>(
29
+ accessor: IComputedStateAccessor<T>,
30
+ ): accessor is IComputedStateAndDurationAccessor<T> => 'getOwnDuration' in accessor;
31
+
32
+ /**
33
+ * Gets the computed state for the node.
34
+ * @param force whether to refresh the computed state for this node, even
35
+ * if it was previously set.
36
+ */
37
+
38
+ export const getComputedState = <T>(accessor: IComputedStateAccessor<T>, node: T, force = false) => {
39
+ let computed = accessor.getCurrentComputedState(node);
40
+ if (computed === undefined || force) {
41
+ computed = accessor.getOwnState(node) ?? TestResultState.Unset;
42
+ for (const child of accessor.getChildren(node)) {
43
+ computed = maxPriority(computed, getComputedState(accessor, child));
44
+ }
45
+
46
+ accessor.setComputedState(node, computed);
47
+ }
48
+
49
+ return computed;
50
+ };
51
+
52
+ export const getComputedDuration = <T>(
53
+ accessor: IComputedStateAndDurationAccessor<T>,
54
+ node: T,
55
+ force = false,
56
+ ): number | undefined => {
57
+ let computed = accessor.getCurrentComputedDuration(node);
58
+ if (computed === undefined || force) {
59
+ const own = accessor.getOwnDuration(node);
60
+ if (own !== undefined) {
61
+ computed = own;
62
+ } else {
63
+ computed = undefined;
64
+ for (const child of accessor.getChildren(node)) {
65
+ const d = getComputedDuration(accessor, child);
66
+ if (d !== undefined) {
67
+ computed = (computed || 0) + d;
68
+ }
69
+ }
70
+ }
71
+
72
+ accessor.setComputedDuration(node, computed);
73
+ }
74
+
75
+ return computed;
76
+ };
77
+
78
+ /**
79
+ * Refreshes the computed state for the node and its parents. Any changes
80
+ * elements cause `addUpdated` to be called.
81
+ */
82
+ export const refreshComputedState = <T>(
83
+ accessor: IComputedStateAccessor<T>,
84
+ node: T,
85
+ explicitNewComputedState?: TestResultState,
86
+ ) => {
87
+ const oldState = accessor.getCurrentComputedState(node);
88
+ const oldPriority = statePriority[oldState];
89
+ const newState = explicitNewComputedState ?? getComputedState(accessor, node, true);
90
+ const newPriority = statePriority[newState];
91
+ const toUpdate = new Set<T>();
92
+
93
+ if (newPriority !== oldPriority) {
94
+ accessor.setComputedState(node, newState);
95
+ toUpdate.add(node);
96
+
97
+ if (newPriority > oldPriority) {
98
+ // Update all parents to ensure they're at least this priority.
99
+ for (const parent of accessor.getParents(node)) {
100
+ const prev = accessor.getCurrentComputedState(parent);
101
+ if (prev !== undefined && statePriority[prev] >= newPriority) {
102
+ break;
103
+ }
104
+
105
+ accessor.setComputedState(parent, newState);
106
+ toUpdate.add(parent);
107
+ }
108
+ } else if (newPriority < oldPriority) {
109
+ // Re-render all parents of this node whose computed priority might have come from this node
110
+ for (const parent of accessor.getParents(node)) {
111
+ const prev = accessor.getCurrentComputedState(parent);
112
+ if (prev === undefined || statePriority[prev] > oldPriority) {
113
+ break;
114
+ }
115
+
116
+ accessor.setComputedState(parent, getComputedState(accessor, parent, true));
117
+ toUpdate.add(parent);
118
+ }
119
+ }
120
+ }
121
+
122
+ if (isDurationAccessor(accessor)) {
123
+ for (const parent of Iterable.concat(Iterable.single(node), accessor.getParents(node))) {
124
+ const oldDuration = accessor.getCurrentComputedDuration(parent);
125
+ const newDuration = getComputedDuration(accessor, parent, true);
126
+ if (oldDuration === newDuration) {
127
+ break;
128
+ }
129
+
130
+ accessor.setComputedDuration(parent, newDuration);
131
+ toUpdate.add(parent);
132
+ }
133
+ }
134
+
135
+ return toUpdate;
136
+ };
@@ -0,0 +1,55 @@
1
+ import { Event, IDisposable, CancellationToken } from '@opensumi/ide-core-browser';
2
+
3
+ import { ObservableValue } from './observableValue';
4
+ import { ITestResult } from './test-result';
5
+ import {
6
+ InternalTestItem,
7
+ MainThreadTestCollection,
8
+ ResolvedTestRunRequest,
9
+ RunTestForControllerRequest,
10
+ TestRunProfileBitset,
11
+ TestsDiff,
12
+ } from './testCollection';
13
+
14
+ export * from './testId';
15
+
16
+ export interface ITestController {
17
+ readonly id: string;
18
+ readonly label: string;
19
+ readonly canRefresh: ObservableValue<boolean>;
20
+ configureRunProfile(profileId: number): void;
21
+ expandTest(testId: string, levels: number): Promise<void>;
22
+ refreshTests(token: CancellationToken): Promise<void>;
23
+ runTests(request: RunTestForControllerRequest, token: CancellationToken): Promise<void>;
24
+ }
25
+
26
+ export const TestServiceToken = Symbol('TestService');
27
+ export const TestDecorationsToken = Symbol('TestDecorationsToken');
28
+ export const TestPeekMessageToken = Symbol('TestPeekMessageToken');
29
+
30
+ export interface ITestingPeekMessageService {
31
+ onDidReveal: Event<any>;
32
+ }
33
+
34
+ export interface ITestService {
35
+ readonly collection: MainThreadTestCollection;
36
+
37
+ registerTestController(id: string, testController: ITestController): IDisposable;
38
+ runTests(req: AmbiguousRunTestsRequest, token?: CancellationToken): Promise<ITestResult>;
39
+ publishDiff(controllerId: string, diff: TestsDiff): void;
40
+ runResolvedTests(req: ResolvedTestRunRequest, token?: CancellationToken): Promise<ITestResult>;
41
+ onDidProcessDiff: Event<TestsDiff>;
42
+ getTestController(controllerId: string): ITestController | undefined;
43
+ refreshTests(controllerId?: string): Promise<void>;
44
+ }
45
+
46
+ export interface AmbiguousRunTestsRequest {
47
+ /** Group to run */
48
+ group: TestRunProfileBitset;
49
+ /** Tests to run. Allowed to be from different controllers */
50
+ tests: readonly InternalTestItem[];
51
+ /** Tests to exclude. If not given, the current UI excluded tests are used */
52
+ exclude?: InternalTestItem[];
53
+ /** Whether this was triggered from an auto run. */
54
+ isAutoRun?: boolean;
55
+ }
@@ -0,0 +1,27 @@
1
+ import { Disposable, Emitter, Event } from '@opensumi/ide-core-common';
2
+
3
+ export interface IObservableValue<T> {
4
+ onDidChange: Event<T>;
5
+ readonly value: T;
6
+ }
7
+
8
+ export class ObservableValue<T> extends Disposable implements IObservableValue<T> {
9
+ private readonly changeEmitter = this.registerDispose(new Emitter<T>());
10
+
11
+ public readonly onDidChange = this.changeEmitter.event;
12
+
13
+ public get value() {
14
+ return this._value;
15
+ }
16
+
17
+ public set value(v: T) {
18
+ if (v !== this._value) {
19
+ this._value = v;
20
+ this.changeEmitter.fire(v);
21
+ }
22
+ }
23
+
24
+ constructor(private _value: T) {
25
+ super();
26
+ }
27
+ }
@@ -0,0 +1,25 @@
1
+ import { ITestController, TestId } from '../index';
2
+
3
+ import { InternalTestItem, ITestRunProfile, TestRunProfileBitset } from './testCollection';
4
+
5
+ export const sorter = (a: ITestRunProfile, b: ITestRunProfile) => {
6
+ if (a.isDefault !== b.isDefault) {
7
+ return a.isDefault ? -1 : 1;
8
+ }
9
+
10
+ return a.label.localeCompare(b.label);
11
+ };
12
+
13
+ export const canUseProfileWithTest = (profile: ITestRunProfile, test: InternalTestItem) =>
14
+ profile.controllerId === test.controllerId &&
15
+ (TestId.isRoot(test.item.extId) || !profile.tag || test.item.tags.includes(profile.tag));
16
+
17
+ export const TestProfileServiceToken = Symbol('TestProfileService');
18
+
19
+ export interface ITestProfileService {
20
+ addProfile(controller: ITestController, profile: ITestRunProfile): void;
21
+ removeProfile(controllerId: string, profileId?: number): void;
22
+
23
+ getBaseDefaultsProfile(group: TestRunProfileBitset): ITestRunProfile[];
24
+ getControllerProfiles(controllerId: string): ITestRunProfile[];
25
+ }
@@ -0,0 +1,328 @@
1
+ import { Emitter, formatLocalize, localize } from '@opensumi/ide-core-common';
2
+
3
+ import { IComputedStateAccessor, refreshComputedState } from './getComputedState';
4
+ import {
5
+ ExtensionRunTestsRequest,
6
+ IRichLocation,
7
+ ISerializedTestResults,
8
+ ITestItem,
9
+ ITestMessage,
10
+ ITestOutputMessage,
11
+ ITestRunTask,
12
+ ITestTaskState,
13
+ ResolvedTestRunRequest,
14
+ SerializedTestMessage,
15
+ TestItemExpandState,
16
+ TestResultItem,
17
+ TestResultState,
18
+ } from './testCollection';
19
+ import { maxPriority, statesInOrder } from './testingStates';
20
+
21
+ export type TestStateCount = { [K in TestResultState]: number };
22
+
23
+ export const makeEmptyCounts = () => {
24
+ const o: Partial<TestStateCount> = {};
25
+ for (const state of statesInOrder) {
26
+ o[state] = 0;
27
+ }
28
+
29
+ return o as TestStateCount;
30
+ };
31
+ export interface ITestRunTaskResults extends ITestRunTask {
32
+ readonly coverage: any | undefined;
33
+
34
+ readonly otherMessages: ITestOutputMessage[];
35
+ }
36
+
37
+ export const TestResultServiceToken = Symbol('TestResultService');
38
+
39
+ export const enum TestResultItemChangeReason {
40
+ Retired,
41
+ ParentRetired,
42
+ ComputedStateChange,
43
+ OwnStateChange,
44
+ }
45
+
46
+ interface TestResultItemWithChildren extends TestResultItem {
47
+ children: TestResultItemWithChildren[];
48
+ }
49
+
50
+ const itemToNode = (controllerId: string, item: ITestItem, parent: string | null): TestResultItemWithChildren => ({
51
+ parent,
52
+ controllerId,
53
+ expand: TestItemExpandState.NotExpandable,
54
+ item: { ...item },
55
+ children: [],
56
+ tasks: [],
57
+ ownComputedState: TestResultState.Unset,
58
+ computedState: TestResultState.Unset,
59
+ retired: false,
60
+ });
61
+
62
+ export type TestResultItemChange = { item: TestResultItem; result: ITestResult } & (
63
+ | {
64
+ reason:
65
+ | TestResultItemChangeReason.Retired
66
+ | TestResultItemChangeReason.ParentRetired
67
+ | TestResultItemChangeReason.ComputedStateChange;
68
+ }
69
+ | { reason: TestResultItemChangeReason.OwnStateChange; previous: TestResultState }
70
+ );
71
+
72
+ export interface ITestResultService {
73
+ createTestResult(req: ResolvedTestRunRequest | ExtensionRunTestsRequest): ITestResult;
74
+ addTestResult(result: ITestResult): void;
75
+ getResult(resultId: string): ITestResult | undefined;
76
+ readonly results: ReadonlyArray<ITestResult>;
77
+ }
78
+
79
+ export const maxCountPriority = (counts: Readonly<TestStateCount>) => {
80
+ for (const state of statesInOrder) {
81
+ if (counts[state] > 0) {
82
+ return state;
83
+ }
84
+ }
85
+
86
+ return TestResultState.Unset;
87
+ };
88
+
89
+ export const resultItemParents = function* (results: ITestResult, item: TestResultItem) {
90
+ let i: TestResultItem | undefined = item;
91
+ while (i) {
92
+ yield i;
93
+ i = i.parent ? results.getStateById(i.parent) : undefined;
94
+ }
95
+ };
96
+
97
+ export interface ITestResult {
98
+ readonly counts: Readonly<TestStateCount>;
99
+
100
+ readonly id: string;
101
+
102
+ readonly completedAt: number | undefined;
103
+
104
+ readonly request: ResolvedTestRunRequest;
105
+
106
+ readonly name: string;
107
+
108
+ tests: IterableIterator<TestResultItem>;
109
+
110
+ tasks: ReadonlyArray<ITestRunTaskResults>;
111
+
112
+ getStateById(testExtId: string): TestResultItem | undefined;
113
+
114
+ getOutput(): Promise<string>;
115
+
116
+ toJSON(): ISerializedTestResults | undefined;
117
+
118
+ updateState(testId: string, taskId: string, state: TestResultState, duration?: number): void;
119
+
120
+ appendOutput(output: string, taskId: string, location?: IRichLocation, testId?: string): void;
121
+
122
+ addTestChainToRun(controllerId: string, chain: ReadonlyArray<ITestItem>): void;
123
+
124
+ addTask(task: ITestRunTask): void;
125
+
126
+ markTaskComplete(taskId: string): void;
127
+
128
+ markComplete(): void;
129
+ }
130
+
131
+ export class TestResultImpl implements ITestResult {
132
+ private readonly completeEmitter = new Emitter<void>();
133
+ private readonly changeEmitter = new Emitter<TestResultItemChange>();
134
+ private readonly testById = new Map<string, TestResultItemWithChildren>();
135
+
136
+ private _completedAt?: number;
137
+
138
+ public readonly name: string = formatLocalize('test.result.runFinished', new Date().toLocaleString());
139
+ public readonly tasks: ITestRunTaskResults[] = [];
140
+ public readonly onChange = this.changeEmitter.event;
141
+ public readonly onComplete = this.completeEmitter.event;
142
+ public readonly counts: { [K in TestResultState]: number } = makeEmptyCounts();
143
+
144
+ public get completedAt() {
145
+ return this._completedAt;
146
+ }
147
+
148
+ public get tests() {
149
+ return this.testById.values();
150
+ }
151
+
152
+ constructor(public readonly id: string, public readonly request: ResolvedTestRunRequest) {}
153
+
154
+ protected setAllToState(
155
+ state: TestResultState,
156
+ taskId: string,
157
+ when: (task: ITestTaskState, item: TestResultItem) => boolean,
158
+ ) {
159
+ const index = this.mustGetTaskIndex(taskId);
160
+ for (const test of this.testById.values()) {
161
+ if (when(test.tasks[index], test)) {
162
+ this.fireUpdateAndRefresh(test, index, state);
163
+ }
164
+ }
165
+ }
166
+
167
+ private readonly computedStateAccessor: IComputedStateAccessor<TestResultItemWithChildren> = {
168
+ getOwnState: (i) => i.ownComputedState,
169
+ getCurrentComputedState: (i) => i.computedState,
170
+ setComputedState: (i, s) => (i.computedState = s),
171
+ getChildren: (i) => i.children,
172
+ getParents: (i) => {
173
+ const { testById: testByExtId } = this;
174
+ return (function* () {
175
+ for (let parentId = i.parent; parentId; ) {
176
+ const parent = testByExtId.get(parentId);
177
+ if (!parent) {
178
+ break;
179
+ }
180
+
181
+ yield parent;
182
+ parentId = parent.parent;
183
+ }
184
+ })();
185
+ },
186
+ };
187
+
188
+ private addTestToRun(controllerId: string, item: ITestItem, parent: string | null) {
189
+ const node = itemToNode(controllerId, item, parent);
190
+ this.testById.set(item.extId, node);
191
+ this.counts[TestResultState.Unset]++;
192
+
193
+ if (parent) {
194
+ this.testById.get(parent)?.children.push(node);
195
+ }
196
+
197
+ if (this.tasks.length) {
198
+ this.tasks.forEach(() => {
199
+ node.tasks.push({ duration: undefined, messages: [], state: TestResultState.Queued });
200
+ });
201
+ }
202
+
203
+ return node;
204
+ }
205
+
206
+ private mustGetTaskIndex(taskId: string) {
207
+ const index = this.tasks.findIndex((t) => t.id === taskId);
208
+ if (index === -1) {
209
+ throw new Error(`Unknown task ${taskId} in updateState`);
210
+ }
211
+
212
+ return index;
213
+ }
214
+
215
+ private fireUpdateAndRefresh(entry: TestResultItem, taskIndex: number, newState: TestResultState) {
216
+ const previousOwnComputed = entry.ownComputedState;
217
+ entry.tasks[taskIndex].state = newState;
218
+ const newOwnComputed = maxPriority(...entry.tasks.map((t) => t.state));
219
+ if (newOwnComputed === previousOwnComputed) {
220
+ return;
221
+ }
222
+
223
+ entry.ownComputedState = newOwnComputed;
224
+ this.counts[previousOwnComputed]--;
225
+ this.counts[newOwnComputed]++;
226
+ refreshComputedState(this.computedStateAccessor, entry).forEach((t) =>
227
+ this.changeEmitter.fire(
228
+ t === entry
229
+ ? {
230
+ item: entry,
231
+ result: this,
232
+ reason: TestResultItemChangeReason.OwnStateChange,
233
+ previous: previousOwnComputed,
234
+ }
235
+ : { item: t, result: this, reason: TestResultItemChangeReason.ComputedStateChange },
236
+ ),
237
+ );
238
+ }
239
+
240
+ getStateById(testExtId: string): TestResultItem | undefined {
241
+ return this.testById.get(testExtId);
242
+ }
243
+
244
+ getOutput(): Promise<string> {
245
+ throw new Error('Method not implemented.');
246
+ }
247
+ toJSON(): ISerializedTestResults | undefined {
248
+ throw new Error('Method not implemented.');
249
+ }
250
+ updateState(testId: string, taskId: string, state: TestResultState, duration?: number): void {
251
+ const entry = this.testById.get(testId);
252
+ if (!entry) {
253
+ return;
254
+ }
255
+
256
+ const index = this.mustGetTaskIndex(taskId);
257
+ if (duration !== undefined) {
258
+ entry.tasks[index].duration = duration;
259
+ entry.ownDuration = Math.max(entry.ownDuration || 0, duration);
260
+ }
261
+
262
+ this.fireUpdateAndRefresh(entry, index, state);
263
+ }
264
+ appendMessage(testId: string, taskId: string, message: ITestMessage | SerializedTestMessage) {
265
+ const entry = this.testById.get(testId);
266
+ if (!entry) {
267
+ return;
268
+ }
269
+
270
+ entry.tasks[this.mustGetTaskIndex(taskId)].messages.push(message as ITestMessage);
271
+ this.changeEmitter.fire({
272
+ item: entry,
273
+ result: this,
274
+ reason: TestResultItemChangeReason.OwnStateChange,
275
+ previous: entry.ownComputedState,
276
+ });
277
+ }
278
+ appendOutput(output: string, taskId: string, location?: IRichLocation, testId?: string): void {
279
+ throw new Error('Method not implemented.');
280
+ }
281
+ addTestChainToRun(controllerId: string, chain: readonly ITestItem[]): void {
282
+ let parent = this.testById.get(chain[0].extId);
283
+ if (!parent) {
284
+ parent = this.addTestToRun(controllerId, chain[0], null);
285
+ }
286
+
287
+ for (let i = 1; i < chain.length; i++) {
288
+ parent = this.addTestToRun(controllerId, chain[i], parent.item.extId);
289
+ }
290
+
291
+ for (let i = 0; i < this.tasks.length; i++) {
292
+ this.fireUpdateAndRefresh(parent, i, TestResultState.Queued);
293
+ }
294
+
295
+ return undefined;
296
+ }
297
+ addTask(task: ITestRunTask): void {
298
+ const index = this.tasks.length;
299
+ // ** coverage not implemented **
300
+ this.tasks.push({ ...task, coverage: undefined, otherMessages: [] });
301
+ for (const test of this.tests) {
302
+ test.tasks.push({ duration: undefined, messages: [], state: TestResultState.Unset });
303
+ this.fireUpdateAndRefresh(test, index, TestResultState.Queued);
304
+ }
305
+ }
306
+ markTaskComplete(taskId: string): void {
307
+ this.tasks[this.mustGetTaskIndex(taskId)].running = false;
308
+ this.setAllToState(
309
+ TestResultState.Unset,
310
+ taskId,
311
+ (t) => t.state === TestResultState.Queued || t.state === TestResultState.Running,
312
+ );
313
+ }
314
+ markComplete(): void {
315
+ if (this._completedAt !== undefined) {
316
+ throw new Error('cannot complete a test result multiple times');
317
+ }
318
+
319
+ for (const task of this.tasks) {
320
+ if (task.running) {
321
+ this.markTaskComplete(task.id);
322
+ }
323
+ }
324
+
325
+ this._completedAt = Date.now();
326
+ this.completeEmitter.fire();
327
+ }
328
+ }