Path: blob/main/src/vs/workbench/contrib/notebook/test/browser/cellOutput.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 { VSBuffer } from '../../../../../base/common/buffer.js';7import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';8import { CellOutputContainer } from '../../browser/view/cellParts/cellOutput.js';9import { CodeCellRenderTemplate } from '../../browser/view/notebookRenderingCommon.js';10import { CodeCellViewModel } from '../../browser/viewModel/codeCellViewModel.js';11import { CellKind, INotebookRendererInfo, IOutputDto } from '../../common/notebookCommon.js';12import { setupInstantiationService, withTestNotebook } from './testNotebookEditor.js';13import { FastDomNode } from '../../../../../base/browser/fastDomNode.js';14import { DisposableStore } from '../../../../../base/common/lifecycle.js';15import { INotebookService } from '../../common/notebookService.js';16import { mock } from '../../../../../base/test/common/mock.js';17import { IMenu, IMenuService } from '../../../../../platform/actions/common/actions.js';18import { Event } from '../../../../../base/common/event.js';19import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';20import { getAllOutputsText } from '../../browser/viewModel/cellOutputTextHelper.js';2122suite('CellOutput', () => {23const store = ensureNoDisposablesAreLeakedInTestSuite();24let instantiationService: TestInstantiationService;25let outputMenus: IMenu[] = [];2627setup(() => {28outputMenus = [];29instantiationService = setupInstantiationService(store);30instantiationService.stub(INotebookService, new class extends mock<INotebookService>() {31override getOutputMimeTypeInfo(_textModel: any, _kernelProvides: readonly string[] | undefined, output: IOutputDto) {32return [{33rendererId: 'plainTextRendererId',34mimeType: 'text/plain',35isTrusted: true36}, {37rendererId: 'htmlRendererId',38mimeType: 'text/html',39isTrusted: true40}, {41rendererId: 'errorRendererId',42mimeType: 'application/vnd.code.notebook.error',43isTrusted: true44}, {45rendererId: 'stderrRendererId',46mimeType: 'application/vnd.code.notebook.stderr',47isTrusted: true48}, {49rendererId: 'stdoutRendererId',50mimeType: 'application/vnd.code.notebook.stdout',51isTrusted: true52}]53.filter(info => output.outputs.some(output => output.mime === info.mimeType));54}55override getRendererInfo(): INotebookRendererInfo {56return {57id: 'rendererId',58displayName: 'Stubbed Renderer',59extensionId: { _lower: 'id', value: 'id' },60} as INotebookRendererInfo;61}62});63instantiationService.stub(IMenuService, new class extends mock<IMenuService>() {64override createMenu() {65const menu = new class extends mock<IMenu>() {66override onDidChange = Event.None;67override getActions() { return []; }68override dispose() { outputMenus = outputMenus.filter(item => item !== menu); }69};70outputMenus.push(menu);71return menu;72}73});74});7576test('Render cell output items with multiple mime types', async function () {77const outputItem = { data: VSBuffer.fromString('output content'), mime: 'text/plain' };78const htmlOutputItem = { data: VSBuffer.fromString('output content'), mime: 'text/html' };79const output1: IOutputDto = { outputId: 'abc', outputs: [outputItem, htmlOutputItem] };80const output2: IOutputDto = { outputId: 'def', outputs: [outputItem, htmlOutputItem] };8182await withTestNotebook(83[84['print(output content)', 'python', CellKind.Code, [output1, output2], {}],85],86(editor, viewModel, disposables, accessor) => {8788const cell = viewModel.viewCells[0] as CodeCellViewModel;89const cellTemplate = createCellTemplate(disposables);90const output = disposables.add(accessor.createInstance(CellOutputContainer, editor, cell, cellTemplate, { limit: 100 }));91output.render();92cell.outputsViewModels[0].setVisible(true);93assert.strictEqual(outputMenus.length, 1, 'should have 1 output menus');94assert(cellTemplate.outputContainer.domNode.style.display !== 'none', 'output container should be visible');95cell.outputsViewModels[1].setVisible(true);96assert.strictEqual(outputMenus.length, 2, 'should have 2 output menus');97cell.outputsViewModels[1].setVisible(true);98assert.strictEqual(outputMenus.length, 2, 'should still have 2 output menus');99},100instantiationService101);102});103104test('One of many cell outputs becomes hidden', async function () {105const outputItem = { data: VSBuffer.fromString('output content'), mime: 'text/plain' };106const htmlOutputItem = { data: VSBuffer.fromString('output content'), mime: 'text/html' };107const output1: IOutputDto = { outputId: 'abc', outputs: [outputItem, htmlOutputItem] };108const output2: IOutputDto = { outputId: 'def', outputs: [outputItem, htmlOutputItem] };109const output3: IOutputDto = { outputId: 'ghi', outputs: [outputItem, htmlOutputItem] };110111await withTestNotebook(112[113['print(output content)', 'python', CellKind.Code, [output1, output2, output3], {}],114],115(editor, viewModel, disposables, accessor) => {116117const cell = viewModel.viewCells[0] as CodeCellViewModel;118const cellTemplate = createCellTemplate(disposables);119const output = disposables.add(accessor.createInstance(CellOutputContainer, editor, cell, cellTemplate, { limit: 100 }));120output.render();121cell.outputsViewModels[0].setVisible(true);122cell.outputsViewModels[1].setVisible(true);123cell.outputsViewModels[2].setVisible(true);124cell.outputsViewModels[1].setVisible(false);125assert(cellTemplate.outputContainer.domNode.style.display !== 'none', 'output container should be visible');126assert.strictEqual(outputMenus.length, 2, 'should have 2 output menus');127},128instantiationService129);130});131132test('get all adjacent stream outputs', async () => {133const stdout = { data: VSBuffer.fromString('stdout'), mime: 'application/vnd.code.notebook.stdout' };134const stderr = { data: VSBuffer.fromString('stderr'), mime: 'application/vnd.code.notebook.stderr' };135const output1: IOutputDto = { outputId: 'abc', outputs: [stdout] };136const output2: IOutputDto = { outputId: 'abc', outputs: [stderr] };137138await withTestNotebook(139[140['print(output content)', 'python', CellKind.Code, [output1, output2], {}],141],142(_editor, viewModel) => {143const cell = viewModel.viewCells[0];144const notebook = viewModel.notebookDocument;145const result = getAllOutputsText(notebook, cell);146147assert.strictEqual(result, 'stdoutstderr');148},149instantiationService150);151});152153test('get all mixed outputs of cell', async () => {154const stdout = { data: VSBuffer.fromString('stdout'), mime: 'application/vnd.code.notebook.stdout' };155const stderr = { data: VSBuffer.fromString('stderr'), mime: 'application/vnd.code.notebook.stderr' };156const plainText = { data: VSBuffer.fromString('output content'), mime: 'text/plain' };157const error = { data: VSBuffer.fromString(`{"name":"Error Name","message":"error message","stack":"error stack"}`), mime: 'application/vnd.code.notebook.error' };158const output1: IOutputDto = { outputId: 'abc', outputs: [stdout] };159const output2: IOutputDto = { outputId: 'abc', outputs: [stderr] };160const output3: IOutputDto = { outputId: 'abc', outputs: [plainText] };161const output4: IOutputDto = { outputId: 'abc', outputs: [error] };162163await withTestNotebook(164[165['print(output content)', 'python', CellKind.Code, [output1, output2, output3, output4], {}],166],167(_editor, viewModel) => {168const cell = viewModel.viewCells[0];169const notebook = viewModel.notebookDocument;170const result = getAllOutputsText(notebook, cell);171172assert.strictEqual(result,173'Cell output 1 of 3\n' +174'stdoutstderr\n' +175'Cell output 2 of 3\n' +176'output content\n' +177'Cell output 3 of 3\n' +178'error stack'179);180},181instantiationService182);183184});185186187});188189function createCellTemplate(disposables: DisposableStore) {190return {191outputContainer: new FastDomNode(document.createElement('div')),192outputShowMoreContainer: new FastDomNode(document.createElement('div')),193focusSinkElement: document.createElement('div'),194templateDisposables: disposables,195elementDisposables: disposables,196} as unknown as CodeCellRenderTemplate;197}198199200