Path: blob/main/src/vs/workbench/api/test/browser/extHostNotebook.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 * as vscode from 'vscode';7import { ExtHostDocumentsAndEditors } from '../../common/extHostDocumentsAndEditors.js';8import { TestRPCProtocol } from '../common/testRPCProtocol.js';9import { DisposableStore } from '../../../../base/common/lifecycle.js';10import { NullLogService } from '../../../../platform/log/common/log.js';11import { mock } from '../../../../base/test/common/mock.js';12import { IModelAddedData, MainContext, MainThreadCommandsShape, MainThreadNotebookShape, NotebookCellsChangedEventDto, NotebookOutputItemDto } from '../../common/extHost.protocol.js';13import { ExtHostNotebookController } from '../../common/extHostNotebook.js';14import { ExtHostNotebookDocument } from '../../common/extHostNotebookDocument.js';15import { CellKind, CellUri, NotebookCellsChangeType } from '../../../contrib/notebook/common/notebookCommon.js';16import { URI } from '../../../../base/common/uri.js';17import { ExtHostDocuments } from '../../common/extHostDocuments.js';18import { ExtHostCommands } from '../../common/extHostCommands.js';19import { nullExtensionDescription } from '../../../services/extensions/common/extensions.js';20import { isEqual } from '../../../../base/common/resources.js';21import { Event } from '../../../../base/common/event.js';22import { ExtHostNotebookDocuments } from '../../common/extHostNotebookDocuments.js';23import { SerializableObjectWithBuffers } from '../../../services/extensions/common/proxyIdentifier.js';24import { VSBuffer } from '../../../../base/common/buffer.js';25import { IExtHostTelemetry } from '../../common/extHostTelemetry.js';26import { ExtHostConsumerFileSystem } from '../../common/extHostFileSystemConsumer.js';27import { ExtHostFileSystemInfo } from '../../common/extHostFileSystemInfo.js';28import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';29import { ExtHostSearch } from '../../common/extHostSearch.js';30import { URITransformerService } from '../../common/extHostUriTransformerService.js';3132suite('NotebookCell#Document', function () {33let rpcProtocol: TestRPCProtocol;34let notebook: ExtHostNotebookDocument;35let extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;36let extHostDocuments: ExtHostDocuments;37let extHostNotebooks: ExtHostNotebookController;38let extHostNotebookDocuments: ExtHostNotebookDocuments;39let extHostConsumerFileSystem: ExtHostConsumerFileSystem;40let extHostSearch: ExtHostSearch;4142const notebookUri = URI.parse('test:///notebook.file');43const disposables = new DisposableStore();4445teardown(function () {46disposables.clear();47});4849ensureNoDisposablesAreLeakedInTestSuite();5051setup(async function () {52rpcProtocol = new TestRPCProtocol();53rpcProtocol.set(MainContext.MainThreadCommands, new class extends mock<MainThreadCommandsShape>() {54override $registerCommand() { }55});56rpcProtocol.set(MainContext.MainThreadNotebook, new class extends mock<MainThreadNotebookShape>() {57override async $registerNotebookSerializer() { }58override async $unregisterNotebookSerializer() { }59});60extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());61extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);62extHostConsumerFileSystem = new ExtHostConsumerFileSystem(rpcProtocol, new ExtHostFileSystemInfo());63extHostSearch = new ExtHostSearch(rpcProtocol, new URITransformerService(null), new NullLogService());64extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService(), new class extends mock<IExtHostTelemetry>() {65override onExtensionError(): boolean {66return true;67}68}), extHostDocumentsAndEditors, extHostDocuments, extHostConsumerFileSystem, extHostSearch, new NullLogService());69extHostNotebookDocuments = new ExtHostNotebookDocuments(extHostNotebooks);7071const reg = extHostNotebooks.registerNotebookSerializer(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookSerializer>() { });72extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({73addedDocuments: [{74uri: notebookUri,75viewType: 'test',76versionId: 0,77cells: [{78handle: 0,79uri: CellUri.generate(notebookUri, 0),80source: ['### Heading'],81eol: '\n',82language: 'markdown',83cellKind: CellKind.Markup,84outputs: [],85}, {86handle: 1,87uri: CellUri.generate(notebookUri, 1),88source: ['console.log("aaa")', 'console.log("bbb")'],89eol: '\n',90language: 'javascript',91cellKind: CellKind.Code,92outputs: [],93}],94}],95addedEditors: [{96documentUri: notebookUri,97id: '_notebook_editor_0',98selections: [{ start: 0, end: 1 }],99visibleRanges: [],100viewType: 'test'101}]102}));103extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: '_notebook_editor_0' }));104105notebook = extHostNotebooks.notebookDocuments[0]!;106107disposables.add(reg);108disposables.add(notebook);109disposables.add(extHostDocuments);110});111112113test('cell document is vscode.TextDocument', async function () {114115assert.strictEqual(notebook.apiNotebook.cellCount, 2);116117const [c1, c2] = notebook.apiNotebook.getCells();118const d1 = extHostDocuments.getDocument(c1.document.uri);119120assert.ok(d1);121assert.strictEqual(d1.languageId, c1.document.languageId);122assert.strictEqual(d1.version, 1);123124const d2 = extHostDocuments.getDocument(c2.document.uri);125assert.ok(d2);126assert.strictEqual(d2.languageId, c2.document.languageId);127assert.strictEqual(d2.version, 1);128});129130test('cell document goes when notebook closes', async function () {131const cellUris: string[] = [];132for (const cell of notebook.apiNotebook.getCells()) {133assert.ok(extHostDocuments.getDocument(cell.document.uri));134cellUris.push(cell.document.uri.toString());135}136137const removedCellUris: string[] = [];138const reg = extHostDocuments.onDidRemoveDocument(doc => {139removedCellUris.push(doc.uri.toString());140});141142extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ removedDocuments: [notebook.uri] }));143reg.dispose();144145assert.strictEqual(removedCellUris.length, 2);146assert.deepStrictEqual(removedCellUris.sort(), cellUris.sort());147});148149test('cell document is vscode.TextDocument after changing it', async function () {150151const p = new Promise<void>((resolve, reject) => {152153disposables.add(extHostNotebookDocuments.onDidChangeNotebookDocument(e => {154try {155assert.strictEqual(e.contentChanges.length, 1);156assert.strictEqual(e.contentChanges[0].addedCells.length, 2);157158const [first, second] = e.contentChanges[0].addedCells;159160const doc1 = extHostDocuments.getAllDocumentData().find(data => isEqual(data.document.uri, first.document.uri));161assert.ok(doc1);162assert.strictEqual(doc1?.document === first.document, true);163164const doc2 = extHostDocuments.getAllDocumentData().find(data => isEqual(data.document.uri, second.document.uri));165assert.ok(doc2);166assert.strictEqual(doc2?.document === second.document, true);167168resolve();169170} catch (err) {171reject(err);172}173}));174175});176177extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({178versionId: notebook.apiNotebook.version + 1,179rawEvents: [180{181kind: NotebookCellsChangeType.ModelChange,182changes: [[0, 0, [{183handle: 2,184uri: CellUri.generate(notebookUri, 2),185source: ['Hello', 'World', 'Hello World!'],186eol: '\n',187language: 'test',188cellKind: CellKind.Code,189outputs: [],190}, {191handle: 3,192uri: CellUri.generate(notebookUri, 3),193source: ['Hallo', 'Welt', 'Hallo Welt!'],194eol: '\n',195language: 'test',196cellKind: CellKind.Code,197outputs: [],198}]]]199}200]201}), false);202203await p;204205});206207test('cell document stays open when notebook is still open', async function () {208209const docs: vscode.TextDocument[] = [];210const addData: IModelAddedData[] = [];211for (const cell of notebook.apiNotebook.getCells()) {212const doc = extHostDocuments.getDocument(cell.document.uri);213assert.ok(doc);214assert.strictEqual(extHostDocuments.getDocument(cell.document.uri).isClosed, false);215docs.push(doc);216addData.push({217EOL: '\n',218isDirty: doc.isDirty,219lines: doc.getText().split('\n'),220languageId: doc.languageId,221uri: doc.uri,222versionId: doc.version,223encoding: 'utf8'224});225}226227// this call happens when opening a document on the main side228extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ addedDocuments: addData });229230// this call happens when closing a document from the main side231extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ removedDocuments: docs.map(d => d.uri) });232233// notebook is still open -> cell documents stay open234for (const cell of notebook.apiNotebook.getCells()) {235assert.ok(extHostDocuments.getDocument(cell.document.uri));236assert.strictEqual(extHostDocuments.getDocument(cell.document.uri).isClosed, false);237}238239// close notebook -> docs are closed240extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ removedDocuments: [notebook.uri] }));241for (const cell of notebook.apiNotebook.getCells()) {242assert.throws(() => extHostDocuments.getDocument(cell.document.uri));243}244for (const doc of docs) {245assert.strictEqual(doc.isClosed, true);246}247});248249test('cell document goes when cell is removed', async function () {250251assert.strictEqual(notebook.apiNotebook.cellCount, 2);252const [cell1, cell2] = notebook.apiNotebook.getCells();253254extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({255versionId: 2,256rawEvents: [257{258kind: NotebookCellsChangeType.ModelChange,259changes: [[0, 1, []]]260}261]262}), false);263264assert.strictEqual(notebook.apiNotebook.cellCount, 1);265assert.strictEqual(cell1.document.isClosed, true); // ref still alive!266assert.strictEqual(cell2.document.isClosed, false);267268assert.throws(() => extHostDocuments.getDocument(cell1.document.uri));269});270271test('cell#index', function () {272273assert.strictEqual(notebook.apiNotebook.cellCount, 2);274const [first, second] = notebook.apiNotebook.getCells();275assert.strictEqual(first.index, 0);276assert.strictEqual(second.index, 1);277278// remove first cell279extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({280versionId: notebook.apiNotebook.version + 1,281rawEvents: [{282kind: NotebookCellsChangeType.ModelChange,283changes: [[0, 1, []]]284}]285}), false);286287assert.strictEqual(notebook.apiNotebook.cellCount, 1);288assert.strictEqual(second.index, 0);289290extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({291versionId: notebook.apiNotebook.version + 1,292rawEvents: [{293kind: NotebookCellsChangeType.ModelChange,294changes: [[0, 0, [{295handle: 2,296uri: CellUri.generate(notebookUri, 2),297source: ['Hello', 'World', 'Hello World!'],298eol: '\n',299language: 'test',300cellKind: CellKind.Code,301outputs: [],302}, {303handle: 3,304uri: CellUri.generate(notebookUri, 3),305source: ['Hallo', 'Welt', 'Hallo Welt!'],306eol: '\n',307language: 'test',308cellKind: CellKind.Code,309outputs: [],310}]]]311}]312}), false);313314assert.strictEqual(notebook.apiNotebook.cellCount, 3);315assert.strictEqual(second.index, 2);316});317318test('ERR MISSING extHostDocument for notebook cell: #116711', async function () {319320const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);321322// DON'T call this, make sure the cell-documents have not been created yet323// assert.strictEqual(notebook.notebookDocument.cellCount, 2);324325extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({326versionId: 100,327rawEvents: [{328kind: NotebookCellsChangeType.ModelChange,329changes: [[0, 2, [{330handle: 3,331uri: CellUri.generate(notebookUri, 3),332source: ['### Heading'],333eol: '\n',334language: 'markdown',335cellKind: CellKind.Markup,336outputs: [],337}, {338handle: 4,339uri: CellUri.generate(notebookUri, 4),340source: ['console.log("aaa")', 'console.log("bbb")'],341eol: '\n',342language: 'javascript',343cellKind: CellKind.Code,344outputs: [],345}]]]346}]347}), false);348349assert.strictEqual(notebook.apiNotebook.cellCount, 2);350351const event = await p;352353assert.strictEqual(event.notebook === notebook.apiNotebook, true);354assert.strictEqual(event.contentChanges.length, 1);355assert.strictEqual(event.contentChanges[0].range.end - event.contentChanges[0].range.start, 2);356assert.strictEqual(event.contentChanges[0].removedCells[0].document.isClosed, true);357assert.strictEqual(event.contentChanges[0].removedCells[1].document.isClosed, true);358assert.strictEqual(event.contentChanges[0].addedCells.length, 2);359assert.strictEqual(event.contentChanges[0].addedCells[0].document.isClosed, false);360assert.strictEqual(event.contentChanges[0].addedCells[1].document.isClosed, false);361});362363364test('Opening a notebook results in VS Code firing the event onDidChangeActiveNotebookEditor twice #118470', function () {365let count = 0;366disposables.add(extHostNotebooks.onDidChangeActiveNotebookEditor(() => count += 1));367368extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({369addedEditors: [{370documentUri: notebookUri,371id: '_notebook_editor_2',372selections: [{ start: 0, end: 1 }],373visibleRanges: [],374viewType: 'test'375}]376}));377378extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({379newActiveEditor: '_notebook_editor_2'380}));381382assert.strictEqual(count, 1);383});384385test('unset active notebook editor', function () {386387const editor = extHostNotebooks.activeNotebookEditor;388assert.ok(editor !== undefined);389390extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: undefined }));391assert.ok(extHostNotebooks.activeNotebookEditor === editor);392393extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({}));394assert.ok(extHostNotebooks.activeNotebookEditor === editor);395396extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: null }));397assert.ok(extHostNotebooks.activeNotebookEditor === undefined);398});399400test('change cell language triggers onDidChange events', async function () {401402const first = notebook.apiNotebook.cellAt(0);403404assert.strictEqual(first.document.languageId, 'markdown');405406const removed = Event.toPromise(extHostDocuments.onDidRemoveDocument);407const added = Event.toPromise(extHostDocuments.onDidAddDocument);408409extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({410versionId: 12, rawEvents: [{411kind: NotebookCellsChangeType.ChangeCellLanguage,412index: 0,413language: 'fooLang'414}]415}), false);416417const removedDoc = await removed;418const addedDoc = await added;419420assert.strictEqual(first.document.languageId, 'fooLang');421assert.ok(removedDoc === addedDoc);422});423424test('onDidChangeNotebook-event, cell changes', async function () {425426const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);427428extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({429versionId: 12, rawEvents: [{430kind: NotebookCellsChangeType.ChangeCellMetadata,431index: 0,432metadata: { foo: 1 }433}, {434kind: NotebookCellsChangeType.ChangeCellMetadata,435index: 1,436metadata: { foo: 2 },437}, {438kind: NotebookCellsChangeType.Output,439index: 1,440outputs: [441{442items: [{443valueBytes: VSBuffer.fromByteArray([0, 2, 3]),444mime: 'text/plain'445}],446outputId: '1'447}448]449}]450}), false, undefined);451452453const event = await p;454455assert.strictEqual(event.notebook === notebook.apiNotebook, true);456assert.strictEqual(event.contentChanges.length, 0);457assert.strictEqual(event.cellChanges.length, 2);458459const [first, second] = event.cellChanges;460assert.deepStrictEqual(first.metadata, first.cell.metadata);461assert.deepStrictEqual(first.executionSummary, undefined);462assert.deepStrictEqual(first.outputs, undefined);463assert.deepStrictEqual(first.document, undefined);464465assert.deepStrictEqual(second.outputs, second.cell.outputs);466assert.deepStrictEqual(second.metadata, second.cell.metadata);467assert.deepStrictEqual(second.executionSummary, undefined);468assert.deepStrictEqual(second.document, undefined);469});470471test('onDidChangeNotebook-event, notebook metadata', async function () {472473const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);474475extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({ versionId: 12, rawEvents: [] }), false, { foo: 2 });476477const event = await p;478479assert.strictEqual(event.notebook === notebook.apiNotebook, true);480assert.strictEqual(event.contentChanges.length, 0);481assert.strictEqual(event.cellChanges.length, 0);482assert.deepStrictEqual(event.metadata, { foo: 2 });483});484485test('onDidChangeNotebook-event, froozen data', async function () {486487const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);488489extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({ versionId: 12, rawEvents: [] }), false, { foo: 2 });490491const event = await p;492493assert.ok(Object.isFrozen(event));494assert.ok(Object.isFrozen(event.cellChanges));495assert.ok(Object.isFrozen(event.contentChanges));496assert.ok(Object.isFrozen(event.notebook));497assert.ok(!Object.isFrozen(event.metadata));498});499500test('change cell language and onDidChangeNotebookDocument', async function () {501502const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);503504const first = notebook.apiNotebook.cellAt(0);505assert.strictEqual(first.document.languageId, 'markdown');506507extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({508versionId: 12,509rawEvents: [{510kind: NotebookCellsChangeType.ChangeCellLanguage,511index: 0,512language: 'fooLang'513}]514}), false);515516const event = await p;517518assert.strictEqual(event.notebook === notebook.apiNotebook, true);519assert.strictEqual(event.contentChanges.length, 0);520assert.strictEqual(event.cellChanges.length, 1);521522const [cellChange] = event.cellChanges;523524assert.strictEqual(cellChange.cell === first, true);525assert.ok(cellChange.document === first.document);526assert.ok(cellChange.executionSummary === undefined);527assert.ok(cellChange.metadata === undefined);528assert.ok(cellChange.outputs === undefined);529});530531test('change notebook cell document and onDidChangeNotebookDocument', async function () {532533const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);534535const first = notebook.apiNotebook.cellAt(0);536537extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({538versionId: 12,539rawEvents: [{540kind: NotebookCellsChangeType.ChangeCellContent,541index: 0542}]543}), false);544545const event = await p;546547assert.strictEqual(event.notebook === notebook.apiNotebook, true);548assert.strictEqual(event.contentChanges.length, 0);549assert.strictEqual(event.cellChanges.length, 1);550551const [cellChange] = event.cellChanges;552553assert.strictEqual(cellChange.cell === first, true);554assert.ok(cellChange.document === first.document);555assert.ok(cellChange.executionSummary === undefined);556assert.ok(cellChange.metadata === undefined);557assert.ok(cellChange.outputs === undefined);558});559560async function replaceOutputs(cellIndex: number, outputId: string, outputItems: NotebookOutputItemDto[]) {561const changeEvent = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);562extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers<NotebookCellsChangedEventDto>({563versionId: notebook.apiNotebook.version + 1,564rawEvents: [{565kind: NotebookCellsChangeType.Output,566index: cellIndex,567outputs: [{ outputId, items: outputItems }]568}]569}), false);570await changeEvent;571}572async function appendOutputItem(cellIndex: number, outputId: string, outputItems: NotebookOutputItemDto[]) {573const changeEvent = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);574extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers<NotebookCellsChangedEventDto>({575versionId: notebook.apiNotebook.version + 1,576rawEvents: [{577kind: NotebookCellsChangeType.OutputItem,578index: cellIndex,579append: true,580outputId,581outputItems582}]583}), false);584await changeEvent;585}586test('Append multiple text/plain output items', async function () {587await replaceOutputs(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('foo') }]);588await appendOutputItem(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('bar') }]);589await appendOutputItem(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('baz') }]);590591592assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);593assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 3);594assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'text/plain');595assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foo');596assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[1].mime, 'text/plain');597assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[1].data).toString(), 'bar');598assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[2].mime, 'text/plain');599assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[2].data).toString(), 'baz');600});601test('Append multiple stdout stream output items to an output with another mime', async function () {602await replaceOutputs(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('foo') }]);603await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('bar') }]);604await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('baz') }]);605606assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);607assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 3);608assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'text/plain');609assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[1].mime, 'application/vnd.code.notebook.stdout');610assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[2].mime, 'application/vnd.code.notebook.stdout');611});612test('Compress multiple stdout stream output items', async function () {613await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('foo') }]);614await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('bar') }]);615await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('baz') }]);616617assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);618assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1);619assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout');620assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foobarbaz');621});622test('Compress multiple stdout stream output items (with support for terminal escape code -> \u001b[A)', async function () {623await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('\nfoo') }]);624await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString(`${String.fromCharCode(27)}[Abar`) }]);625626assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);627assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1);628assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout');629assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'bar');630});631test('Compress multiple stdout stream output items (with support for terminal escape code -> \r character)', async function () {632await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('foo') }]);633await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString(`\rbar`) }]);634635assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);636assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1);637assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout');638assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'bar');639});640test('Compress multiple stderr stream output items', async function () {641await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('foo') }]);642await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('bar') }]);643await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('baz') }]);644645assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);646assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1);647assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stderr');648assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foobarbaz');649});650});651652653