diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts index e447db1326c..51b82032c77 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts @@ -251,44 +251,6 @@ const apiTestContentProvider: vscode.NotebookContentProvider = { }); }); -(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('statusbar', () => { - const emitter = new vscode.EventEmitter(); - const onDidCallProvide = emitter.event; - const suiteDisposables: vscode.Disposable[] = []; - suiteTeardown(async function () { - assertNoRpc(); - - await revertAllDirty(); - await closeAllEditors(); - - disposeAll(suiteDisposables); - suiteDisposables.length = 0; - }); - - suiteSetup(() => { - suiteDisposables.push(vscode.notebooks.registerNotebookCellStatusBarItemProvider('notebookCoreTest', { - async provideCellStatusBarItems(cell: vscode.NotebookCell, _token: vscode.CancellationToken): Promise { - emitter.fire(cell); - return []; - } - })); - - suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider)); - }); - - test('provideCellStatusBarItems called on metadata change', async function () { - const provideCalled = asPromise(onDidCallProvide); - const notebook = await openRandomNotebookDocument(); - await vscode.window.showNotebookDocument(notebook); - await provideCalled; - - const edit = new vscode.WorkspaceEdit(); - edit.set(notebook.uri, [vscode.NotebookEdit.updateCellMetadata(0, { inputCollapsed: true })]); - await vscode.workspace.applyEdit(edit); - await provideCalled; - }); -}); - suite('Notebook & LiveShare', function () { const suiteDisposables: vscode.Disposable[] = []; diff --git a/src/vs/workbench/contrib/notebook/test/browser/contrib/contributedStatusBarItemController.test.ts b/src/vs/workbench/contrib/notebook/test/browser/contrib/contributedStatusBarItemController.test.ts new file mode 100644 index 00000000000..b37d157699b --- /dev/null +++ b/src/vs/workbench/contrib/notebook/test/browser/contrib/contributedStatusBarItemController.test.ts @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { ContributedStatusBarItemController } from 'vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/contributedStatusBarItemController'; +import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; +import { CellKind, INotebookCellStatusBarItemProvider } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { withTestNotebook } from 'vs/workbench/contrib/notebook/test/browser/testNotebookEditor'; + +suite('Notebook Statusbar', () => { + const testDisposables = new DisposableStore(); + + teardown(() => { + testDisposables.clear(); + }); + + test('Calls item provider', async function () { + await withTestNotebook( + [ + ['var b = 1;', 'javascript', CellKind.Code, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], + ], + async (editor, viewModel, accessor) => { + const cellStatusbarSvc = accessor.get(INotebookCellStatusBarService); + testDisposables.add(accessor.createInstance(ContributedStatusBarItemController, editor)); + + const provider = testDisposables.add(new class extends Disposable implements INotebookCellStatusBarItemProvider { + private provideCalls = 0; + + private _onProvideCalled = this._register(new Emitter()); + public onProvideCalled = this._onProvideCalled.event; + + public _onDidChangeStatusBarItems = this._register(new Emitter()); + public onDidChangeStatusBarItems = this._onDidChangeStatusBarItems.event; + + async provideCellStatusBarItems(_uri: URI, index: number, _token: CancellationToken) { + if (index === 0) { + this.provideCalls++; + this._onProvideCalled.fire(this.provideCalls); + } + + return { items: [] }; + } + + viewType = editor.textModel.viewType; + }); + const providePromise1 = asPromise(provider.onProvideCalled); + testDisposables.add(cellStatusbarSvc.registerCellStatusBarItemProvider(provider)); + assert.strictEqual(await providePromise1, 1, 'should call provider on registration'); + + const providePromise2 = asPromise(provider.onProvideCalled); + const cell0 = editor.textModel.cells[0]; + cell0.metadata = { ...cell0.metadata, ...{ newMetadata: true } }; + assert.strictEqual(await providePromise2, 2, 'should call provider on registration'); + + const providePromise3 = asPromise(provider.onProvideCalled); + cell0.language = 'newlanguage'; + assert.strictEqual(await providePromise3, 3, 'should call provider on registration'); + + const providePromise4 = asPromise(provider.onProvideCalled); + provider._onDidChangeStatusBarItems.fire(); + assert.strictEqual(await providePromise4, 4, 'should call provider on registration'); + }); + }); +}); + +async function asPromise(event: Event, timeout = 5000): Promise { + const error = new Error('asPromise TIMEOUT reached'); + return new Promise((resolve, reject) => { + const handle = setTimeout(() => { + sub.dispose(); + reject(error); + }, timeout); + + const sub = event(e => { + clearTimeout(handle); + sub.dispose(); + resolve(e); + }); + }); +} diff --git a/src/vs/workbench/contrib/notebook/test/browser/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/browser/testNotebookEditor.ts index e3deb9f4592..718588d06fe 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/testNotebookEditor.ts @@ -9,22 +9,26 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { NotImplementedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { ResourceMap } from 'vs/base/common/map'; import { Mimes } from 'vs/base/common/mime'; import { URI } from 'vs/base/common/uri'; import { mock } from 'vs/base/test/common/mock'; -import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; import { ILanguageService } from 'vs/editor/common/languages/language'; +import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; import { LanguageService } from 'vs/editor/common/services/languageService'; import { IModelService } from 'vs/editor/common/services/model'; import { ModelService } from 'vs/editor/common/services/modelService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { TestClipboardService } from 'vs/platform/clipboard/test/common/testClipboardService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IListService, ListService } from 'vs/platform/list/browser/listService'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; @@ -37,25 +41,23 @@ import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/work import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { CellFindMatchWithIndex, IActiveNotebookEditorDelegate, IBaseCellEditorOptions, ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { NotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/browser/services/notebookCellStatusBarServiceImpl'; import { ListViewInfoAccessor, NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList'; import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl'; import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; +import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; import { CellKind, CellUri, INotebookDiffEditorModel, INotebookEditorModel, INotebookSearchOptions, IOutputDto, IResolvedNotebookEditorModel, NotebookCellExecutionState, NotebookCellMetadata, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellExecuteUpdate, ICellExecutionComplete, ICellExecutionStateChangedEvent, INotebookCellExecution, INotebookExecutionStateService, INotebookFailStateChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions'; import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; +import { IWorkingCopySaveEvent } from 'vs/workbench/services/workingCopy/common/workingCopy'; import { TestWorkspaceTrustRequestService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; import { TestLayoutService } from 'vs/workbench/test/browser/workbenchTestServices'; import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; -import { ResourceMap } from 'vs/base/common/map'; -import { TestClipboardService } from 'vs/platform/clipboard/test/common/testClipboardService'; -import { IWorkingCopySaveEvent } from 'vs/workbench/services/workingCopy/common/workingCopy'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; export class TestCell extends NotebookCellTextModel { constructor( @@ -176,6 +178,7 @@ export function setupInstantiationService(disposables = new DisposableStore()) { instantiationService.stub(IWorkspaceTrustRequestService, new TestWorkspaceTrustRequestService(true)); instantiationService.stub(INotebookExecutionStateService, new TestNotebookExecutionStateService()); instantiationService.stub(IKeybindingService, new MockKeybindingService()); + instantiationService.stub(INotebookCellStatusBarService, new NotebookCellStatusBarService()); return instantiationService; } @@ -260,6 +263,7 @@ function _createTestNotebookEditor(instantiationService: TestInstantiationServic override cellAt(index: number) { return viewModel.cellAt(index)!; } override getCellIndex(cell: ICellViewModel) { return viewModel.getCellIndex(cell); } override getCellsInRange(range?: ICellRange) { return viewModel.getCellsInRange(range); } + override getCellByHandle(handle: number) { return viewModel.getCellByHandle(handle); } override getNextVisibleCellIndex(index: number) { return viewModel.getNextVisibleCellIndex(index); } getControl() { return this; } override get onDidChangeSelection() { return viewModel.onDidChangeSelection as Event; } @@ -270,6 +274,8 @@ function _createTestNotebookEditor(instantiationService: TestInstantiationServic return findMatches; } override deltaCellDecorations() { return []; } + override onDidChangeVisibleRanges = Event.None; + override visibleRanges: ICellRange[] = [{ start: 0, end: 100 }]; }; return { editor: notebookEditor, viewModel };