@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.
- package/lib/browser/components/testing.explorer.tree.d.ts.map +1 -1
- package/lib/browser/components/testing.explorer.tree.js +7 -5
- package/lib/browser/components/testing.explorer.tree.js.map +1 -1
- package/lib/browser/components/testing.view.js +1 -1
- package/lib/browser/components/testing.view.js.map +1 -1
- package/lib/browser/icons/icons.d.ts +1 -0
- package/lib/browser/icons/icons.d.ts.map +1 -1
- package/lib/browser/icons/icons.js +15 -14
- package/lib/browser/icons/icons.js.map +1 -1
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/outputPeek/test-output-peek.js +9 -9
- package/lib/browser/outputPeek/test-output-peek.js.map +1 -1
- package/lib/browser/outputPeek/test-peek-message.service.js.map +1 -1
- package/lib/browser/outputPeek/test-peek-opener.service.js +1 -1
- package/lib/browser/outputPeek/test-peek-opener.service.js.map +1 -1
- package/lib/browser/outputPeek/test-peek-widget.js +1 -1
- package/lib/browser/outputPeek/test-peek-widget.js.map +1 -1
- package/lib/browser/outputPeek/test-tree-container.js +2 -2
- package/lib/browser/outputPeek/test-tree-container.js.map +1 -1
- package/lib/browser/test-contextkey.service.js.map +1 -1
- package/lib/browser/test-decorations.js +19 -19
- package/lib/browser/test-decorations.js.map +1 -1
- package/lib/browser/test-profile.service.js.map +1 -1
- package/lib/browser/test-tree-view.model.d.ts +1 -0
- package/lib/browser/test-tree-view.model.d.ts.map +1 -1
- package/lib/browser/test-tree-view.model.js +13 -10
- package/lib/browser/test-tree-view.model.js.map +1 -1
- package/lib/browser/test.result.service.d.ts +1 -1
- package/lib/browser/test.result.service.d.ts.map +1 -1
- package/lib/browser/test.result.service.js +5 -5
- package/lib/browser/test.result.service.js.map +1 -1
- package/lib/browser/test.service.d.ts +4 -0
- package/lib/browser/test.service.d.ts.map +1 -1
- package/lib/browser/test.service.js +31 -4
- package/lib/browser/test.service.js.map +1 -1
- package/lib/browser/testing.contribution.d.ts.map +1 -1
- package/lib/browser/testing.contribution.js +21 -10
- package/lib/browser/testing.contribution.js.map +1 -1
- package/lib/common/commands.d.ts +1 -0
- package/lib/common/commands.d.ts.map +1 -1
- package/lib/common/commands.js +6 -1
- package/lib/common/commands.js.map +1 -1
- package/lib/common/constants.js +12 -12
- package/lib/common/constants.js.map +1 -1
- package/lib/common/getComputedState.d.ts +1 -1
- package/lib/common/getComputedState.d.ts.map +1 -1
- package/lib/common/getComputedState.js +1 -1
- package/lib/common/getComputedState.js.map +1 -1
- package/lib/common/index.d.ts +5 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js.map +1 -1
- package/lib/common/observableValue.d.ts +14 -0
- package/lib/common/observableValue.d.ts.map +1 -0
- package/lib/common/observableValue.js +23 -0
- package/lib/common/observableValue.js.map +1 -0
- package/lib/common/test-result.d.ts +2 -2
- package/lib/common/test-result.d.ts.map +1 -1
- package/lib/common/test-result.js +19 -19
- package/lib/common/test-result.js.map +1 -1
- package/lib/common/testCollection.d.ts +9 -8
- package/lib/common/testCollection.d.ts.map +1 -1
- package/lib/common/testCollection.js +27 -27
- package/lib/common/testCollection.js.map +1 -1
- package/lib/common/testId.js +21 -21
- package/lib/common/testId.js.map +1 -1
- package/lib/common/testingStates.js +11 -11
- package/lib/common/testingStates.js.map +1 -1
- package/lib/common/testingUri.d.ts +1 -1
- package/lib/common/testingUri.d.ts.map +1 -1
- package/lib/common/testingUri.js +16 -16
- package/lib/common/testingUri.js.map +1 -1
- package/package.json +14 -13
- package/src/browser/components/testing.explorer.tree.tsx +129 -0
- package/src/browser/components/testing.module.less +26 -0
- package/src/browser/components/testing.view.tsx +35 -0
- package/src/browser/icons/icons.less +31 -0
- package/src/browser/icons/icons.ts +31 -0
- package/src/browser/index.ts +51 -0
- package/src/browser/outputPeek/test-message-container.tsx +183 -0
- package/src/browser/outputPeek/test-output-peek.ts +282 -0
- package/src/browser/outputPeek/test-peek-message.service.ts +15 -0
- package/src/browser/outputPeek/test-peek-opener.service.ts +131 -0
- package/src/browser/outputPeek/test-peek-widget.less +86 -0
- package/src/browser/outputPeek/test-peek-widget.tsx +127 -0
- package/src/browser/outputPeek/test-tree-container.tsx +171 -0
- package/src/browser/test-contextkey.service.ts +24 -0
- package/src/browser/test-decorations.ts +567 -0
- package/src/browser/test-profile.service.ts +66 -0
- package/src/browser/test-tree-view.model.ts +304 -0
- package/src/browser/test.result.service.ts +193 -0
- package/src/browser/test.service.ts +190 -0
- package/src/browser/testing.contribution.ts +471 -0
- package/src/browser/theme.less +6 -0
- package/src/common/commands.ts +78 -0
- package/src/common/constants.ts +57 -0
- package/src/common/contextKeys.ts +0 -0
- package/src/common/getComputedState.ts +136 -0
- package/src/common/index.ts +55 -0
- package/src/common/observableValue.ts +27 -0
- package/src/common/test-profile.ts +25 -0
- package/src/common/test-result.ts +328 -0
- package/src/common/testCollection.ts +680 -0
- package/src/common/testId.ts +191 -0
- package/src/common/testing-view.ts +28 -0
- package/src/common/testingPeekOpener.ts +31 -0
- package/src/common/testingStates.ts +92 -0
- package/src/common/testingUri.ts +101 -0
- package/src/common/tree-view.model.ts +41 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
|
|
4
|
+
import { Injectable, Autowired } from '@opensumi/di';
|
|
5
|
+
import { AppConfig, ConfigProvider, IContextKeyService } from '@opensumi/ide-core-browser';
|
|
6
|
+
import { SplitPanel } from '@opensumi/ide-core-browser/lib/components';
|
|
7
|
+
import { InlineActionBar } from '@opensumi/ide-core-browser/lib/components/actions';
|
|
8
|
+
import { AbstractMenuService, MenuId } from '@opensumi/ide-core-browser/lib/menu/next';
|
|
9
|
+
import { PeekViewWidget } from '@opensumi/ide-monaco-enhance/lib/browser/peek-view';
|
|
10
|
+
import type { ICodeEditor } from '@opensumi/ide-monaco/lib/browser/monaco-api/types';
|
|
11
|
+
import { renderMarkdown } from '@opensumi/monaco-editor-core/esm/vs/base/browser/markdownRenderer';
|
|
12
|
+
|
|
13
|
+
import { TestPeekMessageToken } from '../../common';
|
|
14
|
+
import { TestMessageType } from '../../common/testCollection';
|
|
15
|
+
import { firstLine, hintMessagePeekHeight } from '../../common/testingStates';
|
|
16
|
+
|
|
17
|
+
import { TestMessageContainer } from './test-message-container';
|
|
18
|
+
import { TestDto } from './test-output-peek';
|
|
19
|
+
import { TestingPeekMessageServiceImpl } from './test-peek-message.service';
|
|
20
|
+
import { TestTreeContainer } from './test-tree-container';
|
|
21
|
+
|
|
22
|
+
import './test-peek-widget.less';
|
|
23
|
+
|
|
24
|
+
@Injectable({ multiple: true })
|
|
25
|
+
export class TestingOutputPeek extends PeekViewWidget {
|
|
26
|
+
@Autowired(TestPeekMessageToken)
|
|
27
|
+
private readonly testingPeekMessageService: TestingPeekMessageServiceImpl;
|
|
28
|
+
|
|
29
|
+
@Autowired(AbstractMenuService)
|
|
30
|
+
private readonly menuService: AbstractMenuService;
|
|
31
|
+
|
|
32
|
+
@Autowired(AppConfig)
|
|
33
|
+
private configContext: AppConfig;
|
|
34
|
+
|
|
35
|
+
public current?: TestDto;
|
|
36
|
+
|
|
37
|
+
constructor(public readonly editor: ICodeEditor, private readonly contextKeyService: IContextKeyService) {
|
|
38
|
+
super(editor, { isResizeable: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 在这里渲染测试结果
|
|
43
|
+
* 左侧:
|
|
44
|
+
* - markdown
|
|
45
|
+
* - plantText
|
|
46
|
+
* - monaco diff editor (用于 assertEquals)
|
|
47
|
+
* 右侧:
|
|
48
|
+
* - tree
|
|
49
|
+
*/
|
|
50
|
+
protected _fillBody(container: HTMLElement): void {
|
|
51
|
+
this.setCssClass('testing-output-peek-container');
|
|
52
|
+
ReactDOM.render(
|
|
53
|
+
<ConfigProvider value={this.configContext}>
|
|
54
|
+
<SplitPanel overflow='hidden' id='testing-message-horizontal' flex={1}>
|
|
55
|
+
<TestMessageContainer />
|
|
56
|
+
<TestTreeContainer />
|
|
57
|
+
</SplitPanel>
|
|
58
|
+
</ConfigProvider>,
|
|
59
|
+
container,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
protected async _fillActionBarOptions(container: HTMLElement): Promise<void> {
|
|
64
|
+
const menus = this.menuService.createMenu(MenuId.TestPeekTitleContext, this.contextKeyService);
|
|
65
|
+
return new Promise((res) => {
|
|
66
|
+
ReactDOM.render(
|
|
67
|
+
<ConfigProvider value={this.configContext}>
|
|
68
|
+
<InlineActionBar menus={menus} type='icon' context={[this.editor.getModel()?.uri.toString()!]} />
|
|
69
|
+
</ConfigProvider>,
|
|
70
|
+
container,
|
|
71
|
+
res,
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected applyClass(): void {
|
|
77
|
+
// not implemented
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
protected applyStyle(): void {
|
|
81
|
+
// not implemented
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public async showInPlace(dto: TestDto) {
|
|
85
|
+
const message = dto.messages[dto.messageIndex];
|
|
86
|
+
this.setTitle(
|
|
87
|
+
firstLine(
|
|
88
|
+
typeof message.message === 'string' ? message.message : renderMarkdown(message.message).element.outerText,
|
|
89
|
+
),
|
|
90
|
+
dto.test.label,
|
|
91
|
+
);
|
|
92
|
+
setTimeout(() => {
|
|
93
|
+
this.testingPeekMessageService._didReveal.fire(dto);
|
|
94
|
+
this.testingPeekMessageService._visibilityChange.fire(true);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public hide(): void {
|
|
99
|
+
super.dispose();
|
|
100
|
+
if (this._bodyElement) {
|
|
101
|
+
ReactDOM.unmountComponentAtNode(this._bodyElement);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public setModel(dto: TestDto): Promise<void> {
|
|
106
|
+
const message = dto.messages[dto.messageIndex];
|
|
107
|
+
const previous = this.current;
|
|
108
|
+
|
|
109
|
+
if (message.type !== TestMessageType.Error) {
|
|
110
|
+
return Promise.resolve();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!dto.revealLocation && !previous) {
|
|
114
|
+
return Promise.resolve();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
this.current = dto;
|
|
118
|
+
if (!dto.revealLocation) {
|
|
119
|
+
return this.showInPlace(dto);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.show(dto.revealLocation!.range, hintMessagePeekHeight(message));
|
|
123
|
+
this.editor.focus();
|
|
124
|
+
|
|
125
|
+
return this.showInPlace(dto);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { BasicRecycleTree } from '@opensumi/ide-components';
|
|
4
|
+
import { useInjectable } from '@opensumi/ide-core-browser';
|
|
5
|
+
import { Disposable, localize } from '@opensumi/ide-core-common';
|
|
6
|
+
import { Iterable } from '@opensumi/monaco-editor-core/esm/vs/base/common/iterator';
|
|
7
|
+
|
|
8
|
+
import { TestPeekMessageToken } from '../../common';
|
|
9
|
+
import { ITestResult, maxCountPriority, resultItemParents, TestResultServiceToken } from '../../common/test-result';
|
|
10
|
+
import { ITestMessage, ITestTaskState, TestResultItem, TestResultState } from '../../common/testCollection';
|
|
11
|
+
import { firstLine, parseMarkdownText } from '../../common/testingStates';
|
|
12
|
+
import { buildTestUri, TestUriType } from '../../common/testingUri';
|
|
13
|
+
import { ITestTreeData } from '../../common/tree-view.model';
|
|
14
|
+
import styles from '../components/testing.module.less';
|
|
15
|
+
import { getIconWithColor } from '../icons/icons';
|
|
16
|
+
import { TestResultServiceImpl } from '../test.result.service';
|
|
17
|
+
|
|
18
|
+
import { TestingPeekMessageServiceImpl } from './test-peek-message.service';
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
enum ETestTreeType {
|
|
22
|
+
RESULT = 'result',
|
|
23
|
+
TEST = 'test',
|
|
24
|
+
TASK = 'task',
|
|
25
|
+
MESSAGE = 'message',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ITestBaseTree<T> extends ITestTreeData<T> {
|
|
29
|
+
type: ETestTreeType;
|
|
30
|
+
context: unknown;
|
|
31
|
+
id: string;
|
|
32
|
+
label: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
ariaLabel?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const TestTreeContainer = () => {
|
|
38
|
+
const testResultService: TestResultServiceImpl = useInjectable(TestResultServiceToken);
|
|
39
|
+
const testingPeekMessageService: TestingPeekMessageServiceImpl = useInjectable(TestPeekMessageToken);
|
|
40
|
+
|
|
41
|
+
const [treeData, setTreeData] = useState<ITestBaseTree<ITestResult>[]>([]);
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const disposer: Disposable = new Disposable();
|
|
45
|
+
disposer.addDispose(testingPeekMessageService.onDidReveal((dto) => {}));
|
|
46
|
+
|
|
47
|
+
const toTreeResult = testResultService.results.map((e) => getRootChildren(e));
|
|
48
|
+
setTreeData(toTreeResult);
|
|
49
|
+
|
|
50
|
+
return disposer.dispose.bind(disposer);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
const resolveTestChildren = React.useCallback((node?: ITestBaseTree<unknown>) => {
|
|
54
|
+
if (!node) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
if (node.children && node.children.length > 0) {
|
|
58
|
+
return node.children;
|
|
59
|
+
}
|
|
60
|
+
return [];
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
const getItemIcon = React.useCallback((item: ITestResult) => {
|
|
64
|
+
const state = item.completedAt === undefined ? TestResultState.Running : maxCountPriority(item.counts);
|
|
65
|
+
return getIconWithColor(state);
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
const getTaskChildren = React.useCallback(
|
|
69
|
+
(result: ITestResult, test: TestResultItem, taskId: number): Iterable<ITestBaseTree<ITestMessage>> =>
|
|
70
|
+
Iterable.map(test.tasks[0].messages, (m, messageIndex) => {
|
|
71
|
+
const { message, location } = test.tasks[taskId].messages[messageIndex];
|
|
72
|
+
|
|
73
|
+
const uri = buildTestUri({
|
|
74
|
+
type: TestUriType.ResultMessage,
|
|
75
|
+
messageIndex,
|
|
76
|
+
resultId: result.id,
|
|
77
|
+
taskIndex: taskId,
|
|
78
|
+
testExtId: test.item.extId,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
type: ETestTreeType.MESSAGE,
|
|
83
|
+
context: uri,
|
|
84
|
+
// ** 这里应该解析 markdown 转为纯文本信息 **
|
|
85
|
+
label: firstLine(typeof message === 'string' ? message : parseMarkdownText(message.value)),
|
|
86
|
+
id: uri.toString(),
|
|
87
|
+
icon: '',
|
|
88
|
+
notExpandable: false,
|
|
89
|
+
location,
|
|
90
|
+
rawItem: m,
|
|
91
|
+
};
|
|
92
|
+
}),
|
|
93
|
+
[],
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const getTestChildren = React.useCallback(
|
|
97
|
+
(result: ITestResult, test: TestResultItem): Iterable<ITestBaseTree<ITestTaskState>> => {
|
|
98
|
+
const tasks = Iterable.filter(test.tasks, (task) => task.messages.length > 0);
|
|
99
|
+
return Iterable.map(tasks, (t, taskId) => {
|
|
100
|
+
const task = result.tasks[taskId];
|
|
101
|
+
return {
|
|
102
|
+
type: ETestTreeType.TASK,
|
|
103
|
+
context: String(taskId),
|
|
104
|
+
label: task.name ?? localize('test.task.unnamed'),
|
|
105
|
+
id: `${result.id}/${test.item.extId}/${taskId}`,
|
|
106
|
+
icon: '',
|
|
107
|
+
task,
|
|
108
|
+
notExpandable: false,
|
|
109
|
+
rawItem: t,
|
|
110
|
+
get children() {
|
|
111
|
+
return Array.from(getTaskChildren(result, test, taskId));
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
[],
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const getResultChildren = React.useCallback((result: ITestResult): Iterable<ITestBaseTree<TestResultItem>> => {
|
|
120
|
+
const tests = Iterable.filter(result.tests, (test) => test.tasks.some((t) => t.messages.length > 0));
|
|
121
|
+
return Iterable.map(tests, (test) => {
|
|
122
|
+
let description = '';
|
|
123
|
+
for (const parent of resultItemParents(result, test)) {
|
|
124
|
+
if (parent !== test) {
|
|
125
|
+
description = description ? parent.item.label + ' › ' + description : parent.item.label;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
type: ETestTreeType.TEST,
|
|
130
|
+
context: test.item.extId,
|
|
131
|
+
id: `${result.id}/${test.item.extId}`,
|
|
132
|
+
label: test.item.label,
|
|
133
|
+
get icon() {
|
|
134
|
+
return getIconWithColor(test.computedState);
|
|
135
|
+
},
|
|
136
|
+
notExpandable: false,
|
|
137
|
+
description,
|
|
138
|
+
rawItem: test,
|
|
139
|
+
get children() {
|
|
140
|
+
return Array.from(getTestChildren(result, test));
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
}, []);
|
|
145
|
+
|
|
146
|
+
const getRootChildren = React.useCallback(
|
|
147
|
+
(item: ITestResult): ITestBaseTree<ITestResult> => ({
|
|
148
|
+
type: ETestTreeType.RESULT,
|
|
149
|
+
context: item.id,
|
|
150
|
+
id: item.id,
|
|
151
|
+
label: item.name,
|
|
152
|
+
icon: '',
|
|
153
|
+
get iconClassName() {
|
|
154
|
+
return getItemIcon(item);
|
|
155
|
+
},
|
|
156
|
+
rawItem: item,
|
|
157
|
+
get children() {
|
|
158
|
+
return Array.from(getResultChildren(item));
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
[],
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<div className={styles.test_output_peek_tree}>
|
|
166
|
+
{treeData.length > 0 && (
|
|
167
|
+
<BasicRecycleTree treeData={treeData} height={500} resolveChildren={resolveTestChildren} />
|
|
168
|
+
)}
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Optional, Injectable, Autowired } from '@opensumi/di';
|
|
2
|
+
import { IContextKeyService, IContextKey, IScopedContextKeyService } from '@opensumi/ide-core-browser';
|
|
3
|
+
import { TestingIsPeekVisible } from '@opensumi/ide-core-browser/lib/contextkey/testing';
|
|
4
|
+
import { ContextKeyService } from '@opensumi/monaco-editor-core/esm/vs/platform/contextkey/browser/contextKeyService';
|
|
5
|
+
import { IContextKeyServiceTarget } from '@opensumi/monaco-editor-core/esm/vs/platform/contextkey/common/contextkey';
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class TestContextKey {
|
|
9
|
+
@Autowired(IContextKeyService)
|
|
10
|
+
private readonly globalContextKeyService: IContextKeyService;
|
|
11
|
+
|
|
12
|
+
private _contextKeyService: IScopedContextKeyService | undefined;
|
|
13
|
+
|
|
14
|
+
public readonly contextTestingIsPeekVisible: IContextKey<boolean>;
|
|
15
|
+
|
|
16
|
+
constructor(@Optional() dom?: HTMLElement | IContextKeyServiceTarget | ContextKeyService) {
|
|
17
|
+
this._contextKeyService = this.globalContextKeyService.createScoped(dom);
|
|
18
|
+
this.contextTestingIsPeekVisible = TestingIsPeekVisible.bind(this.contextKeyScoped);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public get contextKeyScoped(): IScopedContextKeyService {
|
|
22
|
+
return this._contextKeyService!;
|
|
23
|
+
}
|
|
24
|
+
}
|