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