Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/comments/test/browser/commentsView.test.ts
5248 views
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 assert from 'assert';
7
import { workbenchInstantiationService } from '../../../../test/browser/workbenchTestServices.js';
8
import { IRange, Range } from '../../../../../editor/common/core/range.js';
9
import { CommentsPanel } from '../../browser/commentsView.js';
10
import { CommentService, ICommentController, ICommentInfo, ICommentService, INotebookCommentInfo } from '../../browser/commentService.js';
11
import { Comment, CommentInput, CommentReaction, CommentThread, CommentThreadCollapsibleState, CommentThreadState } from '../../../../../editor/common/languages.js';
12
import { Emitter, Event } from '../../../../../base/common/event.js';
13
import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';
14
import { IViewContainerModel, IViewDescriptor, IViewDescriptorService, IViewPaneContainer, ViewContainer, ViewContainerLocation } from '../../../../common/views.js';
15
import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';
16
import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';
17
import { IContextViewService } from '../../../../../platform/contextview/browser/contextView.js';
18
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
19
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
20
import { CancellationToken } from '../../../../../base/common/cancellation.js';
21
import { URI, UriComponents } from '../../../../../base/common/uri.js';
22
import { IHoverService } from '../../../../../platform/hover/browser/hover.js';
23
import { NullHoverService } from '../../../../../platform/hover/test/browser/nullHoverService.js';
24
import { SyncDescriptor } from '../../../../../platform/instantiation/common/descriptors.js';
25
26
class TestCommentThread implements CommentThread<IRange> {
27
isDocumentCommentThread(): this is CommentThread<IRange> {
28
return true;
29
}
30
constructor(public readonly commentThreadHandle: number,
31
public readonly controllerHandle: number,
32
public readonly threadId: string,
33
public readonly resource: string,
34
public readonly range: IRange,
35
public readonly comments: Comment[]) { }
36
37
readonly onDidChangeComments: Event<readonly Comment[] | undefined> = new Emitter<readonly Comment[] | undefined>().event;
38
readonly onDidChangeInitialCollapsibleState: Event<CommentThreadCollapsibleState | undefined> = new Emitter<CommentThreadCollapsibleState | undefined>().event;
39
canReply: boolean = false;
40
readonly onDidChangeInput: Event<CommentInput | undefined> = new Emitter<CommentInput | undefined>().event;
41
readonly onDidChangeRange: Event<IRange> = new Emitter<IRange>().event;
42
readonly onDidChangeLabel: Event<string | undefined> = new Emitter<string | undefined>().event;
43
readonly onDidChangeCollapsibleState: Event<CommentThreadCollapsibleState | undefined> = new Emitter<CommentThreadCollapsibleState | undefined>().event;
44
readonly onDidChangeState: Event<CommentThreadState | undefined> = new Emitter<CommentThreadState | undefined>().event;
45
readonly onDidChangeCanReply: Event<boolean> = new Emitter<boolean>().event;
46
isDisposed: boolean = false;
47
isTemplate: boolean = false;
48
label: string | undefined = undefined;
49
contextValue: string | undefined = undefined;
50
}
51
52
class TestCommentController implements ICommentController {
53
activeComment: { thread: CommentThread; comment?: Comment } | undefined;
54
id: string = 'test';
55
label: string = 'Test Comments';
56
owner: string = 'test';
57
features = {};
58
createCommentThreadTemplate(resource: UriComponents, range: IRange | undefined): Promise<void> {
59
throw new Error('Method not implemented.');
60
}
61
updateCommentThreadTemplate(threadHandle: number, range: IRange): Promise<void> {
62
throw new Error('Method not implemented.');
63
}
64
deleteCommentThreadMain(commentThreadId: string): void {
65
throw new Error('Method not implemented.');
66
}
67
toggleReaction(uri: URI, thread: CommentThread<IRange>, comment: Comment, reaction: CommentReaction, token: CancellationToken): Promise<void> {
68
throw new Error('Method not implemented.');
69
}
70
getDocumentComments(resource: URI, token: CancellationToken): Promise<ICommentInfo> {
71
throw new Error('Method not implemented.');
72
}
73
getNotebookComments(resource: URI, token: CancellationToken): Promise<INotebookCommentInfo> {
74
throw new Error('Method not implemented.');
75
}
76
setActiveCommentAndThread(commentInfo: { thread: CommentThread; comment: Comment } | undefined): Promise<void> {
77
throw new Error('Method not implemented.');
78
}
79
80
}
81
82
export class TestViewDescriptorService implements Partial<IViewDescriptorService> {
83
getViewLocationById(id: string): ViewContainerLocation | null {
84
return ViewContainerLocation.Panel;
85
}
86
readonly onDidChangeLocation: Event<{ views: IViewDescriptor[]; from: ViewContainerLocation; to: ViewContainerLocation }> = new Emitter<{ views: IViewDescriptor[]; from: ViewContainerLocation; to: ViewContainerLocation }>().event;
87
getViewDescriptorById(id: string): IViewDescriptor | null {
88
return null;
89
}
90
getViewContainerByViewId(id: string): ViewContainer | null {
91
return {
92
id: 'comments',
93
title: { value: 'Comments', original: 'Comments' },
94
ctorDescriptor: {} as SyncDescriptor<IViewPaneContainer>
95
};
96
}
97
getViewContainerModel(viewContainer: ViewContainer): IViewContainerModel {
98
const partialViewContainerModel: Partial<IViewContainerModel> = {
99
onDidChangeContainerInfo: new Emitter<{ title?: boolean; icon?: boolean; keybindingId?: boolean }>().event
100
};
101
return partialViewContainerModel as IViewContainerModel;
102
}
103
getDefaultContainerById(id: string): ViewContainer | null {
104
return null;
105
}
106
}
107
108
suite('Comments View', function () {
109
teardown(() => {
110
instantiationService.dispose();
111
commentService.dispose();
112
disposables.dispose();
113
});
114
115
ensureNoDisposablesAreLeakedInTestSuite();
116
117
let disposables: DisposableStore;
118
let instantiationService: TestInstantiationService;
119
let commentService: CommentService;
120
121
setup(() => {
122
disposables = new DisposableStore();
123
instantiationService = workbenchInstantiationService({}, disposables);
124
instantiationService.stub(IConfigurationService, new TestConfigurationService());
125
instantiationService.stub(IHoverService, NullHoverService);
126
instantiationService.stub(IContextViewService, {});
127
instantiationService.stub(IViewDescriptorService, new TestViewDescriptorService());
128
commentService = instantiationService.createInstance(CommentService);
129
instantiationService.stub(ICommentService, commentService);
130
commentService.registerCommentController('test', new TestCommentController());
131
});
132
133
134
135
test('collapse all', async function () {
136
const view = instantiationService.createInstance(CommentsPanel, { id: 'comments', title: 'Comments' });
137
view.render();
138
commentService.setWorkspaceComments('test', [
139
new TestCommentThread(1, 1, '1', 'test1', new Range(1, 1, 1, 1), [{ body: 'test', uniqueIdInThread: 1, userName: 'alex' }]),
140
new TestCommentThread(2, 1, '1', 'test2', new Range(1, 1, 1, 1), [{ body: 'test', uniqueIdInThread: 1, userName: 'alex' }]),
141
]);
142
assert.strictEqual(view.getFilterStats().total, 2);
143
assert.strictEqual(view.areAllCommentsExpanded(), true);
144
view.collapseAll();
145
assert.strictEqual(view.isSomeCommentsExpanded(), false);
146
view.dispose();
147
});
148
149
test('expand all', async function () {
150
const view = instantiationService.createInstance(CommentsPanel, { id: 'comments', title: 'Comments' });
151
view.render();
152
commentService.setWorkspaceComments('test', [
153
new TestCommentThread(1, 1, '1', 'test1', new Range(1, 1, 1, 1), [{ body: 'test', uniqueIdInThread: 1, userName: 'alex' }]),
154
new TestCommentThread(2, 1, '1', 'test2', new Range(1, 1, 1, 1), [{ body: 'test', uniqueIdInThread: 1, userName: 'alex' }]),
155
]);
156
assert.strictEqual(view.getFilterStats().total, 2);
157
view.collapseAll();
158
assert.strictEqual(view.isSomeCommentsExpanded(), false);
159
view.expandAll();
160
assert.strictEqual(view.areAllCommentsExpanded(), true);
161
view.dispose();
162
});
163
164
test('filter by text', async function () {
165
const view = instantiationService.createInstance(CommentsPanel, { id: 'comments', title: 'Comments' });
166
view.setVisible(true);
167
view.render();
168
commentService.setWorkspaceComments('test', [
169
new TestCommentThread(1, 1, '1', 'test1', new Range(1, 1, 1, 1), [{ body: 'This comment is a cat.', uniqueIdInThread: 1, userName: 'alex' }]),
170
new TestCommentThread(2, 1, '1', 'test2', new Range(1, 1, 1, 1), [{ body: 'This comment is a dog.', uniqueIdInThread: 1, userName: 'alex' }]),
171
]);
172
assert.strictEqual(view.getFilterStats().total, 2);
173
assert.strictEqual(view.getFilterStats().filtered, 2);
174
view.getFilterWidget().setFilterText('cat');
175
// Setting showResolved causes the filter to trigger for the purposes of this test.
176
view.filters.showResolved = false;
177
178
assert.strictEqual(view.getFilterStats().total, 2);
179
assert.strictEqual(view.getFilterStats().filtered, 1);
180
view.clearFilterText();
181
// Setting showResolved causes the filter to trigger for the purposes of this test.
182
view.filters.showResolved = true;
183
assert.strictEqual(view.getFilterStats().total, 2);
184
assert.strictEqual(view.getFilterStats().filtered, 2);
185
view.dispose();
186
});
187
});
188
189