Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/test/browser/extHostNotebook.test.ts
3296 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 * as vscode from 'vscode';
8
import { ExtHostDocumentsAndEditors } from '../../common/extHostDocumentsAndEditors.js';
9
import { TestRPCProtocol } from '../common/testRPCProtocol.js';
10
import { DisposableStore } from '../../../../base/common/lifecycle.js';
11
import { NullLogService } from '../../../../platform/log/common/log.js';
12
import { mock } from '../../../../base/test/common/mock.js';
13
import { IModelAddedData, MainContext, MainThreadCommandsShape, MainThreadNotebookShape, NotebookCellsChangedEventDto, NotebookOutputItemDto } from '../../common/extHost.protocol.js';
14
import { ExtHostNotebookController } from '../../common/extHostNotebook.js';
15
import { ExtHostNotebookDocument } from '../../common/extHostNotebookDocument.js';
16
import { CellKind, CellUri, NotebookCellsChangeType } from '../../../contrib/notebook/common/notebookCommon.js';
17
import { URI } from '../../../../base/common/uri.js';
18
import { ExtHostDocuments } from '../../common/extHostDocuments.js';
19
import { ExtHostCommands } from '../../common/extHostCommands.js';
20
import { nullExtensionDescription } from '../../../services/extensions/common/extensions.js';
21
import { isEqual } from '../../../../base/common/resources.js';
22
import { Event } from '../../../../base/common/event.js';
23
import { ExtHostNotebookDocuments } from '../../common/extHostNotebookDocuments.js';
24
import { SerializableObjectWithBuffers } from '../../../services/extensions/common/proxyIdentifier.js';
25
import { VSBuffer } from '../../../../base/common/buffer.js';
26
import { IExtHostTelemetry } from '../../common/extHostTelemetry.js';
27
import { ExtHostConsumerFileSystem } from '../../common/extHostFileSystemConsumer.js';
28
import { ExtHostFileSystemInfo } from '../../common/extHostFileSystemInfo.js';
29
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
30
import { ExtHostSearch } from '../../common/extHostSearch.js';
31
import { URITransformerService } from '../../common/extHostUriTransformerService.js';
32
33
suite('NotebookCell#Document', function () {
34
let rpcProtocol: TestRPCProtocol;
35
let notebook: ExtHostNotebookDocument;
36
let extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;
37
let extHostDocuments: ExtHostDocuments;
38
let extHostNotebooks: ExtHostNotebookController;
39
let extHostNotebookDocuments: ExtHostNotebookDocuments;
40
let extHostConsumerFileSystem: ExtHostConsumerFileSystem;
41
let extHostSearch: ExtHostSearch;
42
43
const notebookUri = URI.parse('test:///notebook.file');
44
const disposables = new DisposableStore();
45
46
teardown(function () {
47
disposables.clear();
48
});
49
50
ensureNoDisposablesAreLeakedInTestSuite();
51
52
setup(async function () {
53
rpcProtocol = new TestRPCProtocol();
54
rpcProtocol.set(MainContext.MainThreadCommands, new class extends mock<MainThreadCommandsShape>() {
55
override $registerCommand() { }
56
});
57
rpcProtocol.set(MainContext.MainThreadNotebook, new class extends mock<MainThreadNotebookShape>() {
58
override async $registerNotebookSerializer() { }
59
override async $unregisterNotebookSerializer() { }
60
});
61
extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());
62
extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
63
extHostConsumerFileSystem = new ExtHostConsumerFileSystem(rpcProtocol, new ExtHostFileSystemInfo());
64
extHostSearch = new ExtHostSearch(rpcProtocol, new URITransformerService(null), new NullLogService());
65
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService(), new class extends mock<IExtHostTelemetry>() {
66
override onExtensionError(): boolean {
67
return true;
68
}
69
}), extHostDocumentsAndEditors, extHostDocuments, extHostConsumerFileSystem, extHostSearch, new NullLogService());
70
extHostNotebookDocuments = new ExtHostNotebookDocuments(extHostNotebooks);
71
72
const reg = extHostNotebooks.registerNotebookSerializer(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookSerializer>() { });
73
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({
74
addedDocuments: [{
75
uri: notebookUri,
76
viewType: 'test',
77
versionId: 0,
78
cells: [{
79
handle: 0,
80
uri: CellUri.generate(notebookUri, 0),
81
source: ['### Heading'],
82
eol: '\n',
83
language: 'markdown',
84
cellKind: CellKind.Markup,
85
outputs: [],
86
}, {
87
handle: 1,
88
uri: CellUri.generate(notebookUri, 1),
89
source: ['console.log("aaa")', 'console.log("bbb")'],
90
eol: '\n',
91
language: 'javascript',
92
cellKind: CellKind.Code,
93
outputs: [],
94
}],
95
}],
96
addedEditors: [{
97
documentUri: notebookUri,
98
id: '_notebook_editor_0',
99
selections: [{ start: 0, end: 1 }],
100
visibleRanges: [],
101
viewType: 'test'
102
}]
103
}));
104
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: '_notebook_editor_0' }));
105
106
notebook = extHostNotebooks.notebookDocuments[0]!;
107
108
disposables.add(reg);
109
disposables.add(notebook);
110
disposables.add(extHostDocuments);
111
});
112
113
114
test('cell document is vscode.TextDocument', async function () {
115
116
assert.strictEqual(notebook.apiNotebook.cellCount, 2);
117
118
const [c1, c2] = notebook.apiNotebook.getCells();
119
const d1 = extHostDocuments.getDocument(c1.document.uri);
120
121
assert.ok(d1);
122
assert.strictEqual(d1.languageId, c1.document.languageId);
123
assert.strictEqual(d1.version, 1);
124
125
const d2 = extHostDocuments.getDocument(c2.document.uri);
126
assert.ok(d2);
127
assert.strictEqual(d2.languageId, c2.document.languageId);
128
assert.strictEqual(d2.version, 1);
129
});
130
131
test('cell document goes when notebook closes', async function () {
132
const cellUris: string[] = [];
133
for (const cell of notebook.apiNotebook.getCells()) {
134
assert.ok(extHostDocuments.getDocument(cell.document.uri));
135
cellUris.push(cell.document.uri.toString());
136
}
137
138
const removedCellUris: string[] = [];
139
const reg = extHostDocuments.onDidRemoveDocument(doc => {
140
removedCellUris.push(doc.uri.toString());
141
});
142
143
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ removedDocuments: [notebook.uri] }));
144
reg.dispose();
145
146
assert.strictEqual(removedCellUris.length, 2);
147
assert.deepStrictEqual(removedCellUris.sort(), cellUris.sort());
148
});
149
150
test('cell document is vscode.TextDocument after changing it', async function () {
151
152
const p = new Promise<void>((resolve, reject) => {
153
154
disposables.add(extHostNotebookDocuments.onDidChangeNotebookDocument(e => {
155
try {
156
assert.strictEqual(e.contentChanges.length, 1);
157
assert.strictEqual(e.contentChanges[0].addedCells.length, 2);
158
159
const [first, second] = e.contentChanges[0].addedCells;
160
161
const doc1 = extHostDocuments.getAllDocumentData().find(data => isEqual(data.document.uri, first.document.uri));
162
assert.ok(doc1);
163
assert.strictEqual(doc1?.document === first.document, true);
164
165
const doc2 = extHostDocuments.getAllDocumentData().find(data => isEqual(data.document.uri, second.document.uri));
166
assert.ok(doc2);
167
assert.strictEqual(doc2?.document === second.document, true);
168
169
resolve();
170
171
} catch (err) {
172
reject(err);
173
}
174
}));
175
176
});
177
178
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
179
versionId: notebook.apiNotebook.version + 1,
180
rawEvents: [
181
{
182
kind: NotebookCellsChangeType.ModelChange,
183
changes: [[0, 0, [{
184
handle: 2,
185
uri: CellUri.generate(notebookUri, 2),
186
source: ['Hello', 'World', 'Hello World!'],
187
eol: '\n',
188
language: 'test',
189
cellKind: CellKind.Code,
190
outputs: [],
191
}, {
192
handle: 3,
193
uri: CellUri.generate(notebookUri, 3),
194
source: ['Hallo', 'Welt', 'Hallo Welt!'],
195
eol: '\n',
196
language: 'test',
197
cellKind: CellKind.Code,
198
outputs: [],
199
}]]]
200
}
201
]
202
}), false);
203
204
await p;
205
206
});
207
208
test('cell document stays open when notebook is still open', async function () {
209
210
const docs: vscode.TextDocument[] = [];
211
const addData: IModelAddedData[] = [];
212
for (const cell of notebook.apiNotebook.getCells()) {
213
const doc = extHostDocuments.getDocument(cell.document.uri);
214
assert.ok(doc);
215
assert.strictEqual(extHostDocuments.getDocument(cell.document.uri).isClosed, false);
216
docs.push(doc);
217
addData.push({
218
EOL: '\n',
219
isDirty: doc.isDirty,
220
lines: doc.getText().split('\n'),
221
languageId: doc.languageId,
222
uri: doc.uri,
223
versionId: doc.version,
224
encoding: 'utf8'
225
});
226
}
227
228
// this call happens when opening a document on the main side
229
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ addedDocuments: addData });
230
231
// this call happens when closing a document from the main side
232
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ removedDocuments: docs.map(d => d.uri) });
233
234
// notebook is still open -> cell documents stay open
235
for (const cell of notebook.apiNotebook.getCells()) {
236
assert.ok(extHostDocuments.getDocument(cell.document.uri));
237
assert.strictEqual(extHostDocuments.getDocument(cell.document.uri).isClosed, false);
238
}
239
240
// close notebook -> docs are closed
241
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ removedDocuments: [notebook.uri] }));
242
for (const cell of notebook.apiNotebook.getCells()) {
243
assert.throws(() => extHostDocuments.getDocument(cell.document.uri));
244
}
245
for (const doc of docs) {
246
assert.strictEqual(doc.isClosed, true);
247
}
248
});
249
250
test('cell document goes when cell is removed', async function () {
251
252
assert.strictEqual(notebook.apiNotebook.cellCount, 2);
253
const [cell1, cell2] = notebook.apiNotebook.getCells();
254
255
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
256
versionId: 2,
257
rawEvents: [
258
{
259
kind: NotebookCellsChangeType.ModelChange,
260
changes: [[0, 1, []]]
261
}
262
]
263
}), false);
264
265
assert.strictEqual(notebook.apiNotebook.cellCount, 1);
266
assert.strictEqual(cell1.document.isClosed, true); // ref still alive!
267
assert.strictEqual(cell2.document.isClosed, false);
268
269
assert.throws(() => extHostDocuments.getDocument(cell1.document.uri));
270
});
271
272
test('cell#index', function () {
273
274
assert.strictEqual(notebook.apiNotebook.cellCount, 2);
275
const [first, second] = notebook.apiNotebook.getCells();
276
assert.strictEqual(first.index, 0);
277
assert.strictEqual(second.index, 1);
278
279
// remove first cell
280
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
281
versionId: notebook.apiNotebook.version + 1,
282
rawEvents: [{
283
kind: NotebookCellsChangeType.ModelChange,
284
changes: [[0, 1, []]]
285
}]
286
}), false);
287
288
assert.strictEqual(notebook.apiNotebook.cellCount, 1);
289
assert.strictEqual(second.index, 0);
290
291
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
292
versionId: notebook.apiNotebook.version + 1,
293
rawEvents: [{
294
kind: NotebookCellsChangeType.ModelChange,
295
changes: [[0, 0, [{
296
handle: 2,
297
uri: CellUri.generate(notebookUri, 2),
298
source: ['Hello', 'World', 'Hello World!'],
299
eol: '\n',
300
language: 'test',
301
cellKind: CellKind.Code,
302
outputs: [],
303
}, {
304
handle: 3,
305
uri: CellUri.generate(notebookUri, 3),
306
source: ['Hallo', 'Welt', 'Hallo Welt!'],
307
eol: '\n',
308
language: 'test',
309
cellKind: CellKind.Code,
310
outputs: [],
311
}]]]
312
}]
313
}), false);
314
315
assert.strictEqual(notebook.apiNotebook.cellCount, 3);
316
assert.strictEqual(second.index, 2);
317
});
318
319
test('ERR MISSING extHostDocument for notebook cell: #116711', async function () {
320
321
const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);
322
323
// DON'T call this, make sure the cell-documents have not been created yet
324
// assert.strictEqual(notebook.notebookDocument.cellCount, 2);
325
326
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
327
versionId: 100,
328
rawEvents: [{
329
kind: NotebookCellsChangeType.ModelChange,
330
changes: [[0, 2, [{
331
handle: 3,
332
uri: CellUri.generate(notebookUri, 3),
333
source: ['### Heading'],
334
eol: '\n',
335
language: 'markdown',
336
cellKind: CellKind.Markup,
337
outputs: [],
338
}, {
339
handle: 4,
340
uri: CellUri.generate(notebookUri, 4),
341
source: ['console.log("aaa")', 'console.log("bbb")'],
342
eol: '\n',
343
language: 'javascript',
344
cellKind: CellKind.Code,
345
outputs: [],
346
}]]]
347
}]
348
}), false);
349
350
assert.strictEqual(notebook.apiNotebook.cellCount, 2);
351
352
const event = await p;
353
354
assert.strictEqual(event.notebook === notebook.apiNotebook, true);
355
assert.strictEqual(event.contentChanges.length, 1);
356
assert.strictEqual(event.contentChanges[0].range.end - event.contentChanges[0].range.start, 2);
357
assert.strictEqual(event.contentChanges[0].removedCells[0].document.isClosed, true);
358
assert.strictEqual(event.contentChanges[0].removedCells[1].document.isClosed, true);
359
assert.strictEqual(event.contentChanges[0].addedCells.length, 2);
360
assert.strictEqual(event.contentChanges[0].addedCells[0].document.isClosed, false);
361
assert.strictEqual(event.contentChanges[0].addedCells[1].document.isClosed, false);
362
});
363
364
365
test('Opening a notebook results in VS Code firing the event onDidChangeActiveNotebookEditor twice #118470', function () {
366
let count = 0;
367
disposables.add(extHostNotebooks.onDidChangeActiveNotebookEditor(() => count += 1));
368
369
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({
370
addedEditors: [{
371
documentUri: notebookUri,
372
id: '_notebook_editor_2',
373
selections: [{ start: 0, end: 1 }],
374
visibleRanges: [],
375
viewType: 'test'
376
}]
377
}));
378
379
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({
380
newActiveEditor: '_notebook_editor_2'
381
}));
382
383
assert.strictEqual(count, 1);
384
});
385
386
test('unset active notebook editor', function () {
387
388
const editor = extHostNotebooks.activeNotebookEditor;
389
assert.ok(editor !== undefined);
390
391
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: undefined }));
392
assert.ok(extHostNotebooks.activeNotebookEditor === editor);
393
394
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({}));
395
assert.ok(extHostNotebooks.activeNotebookEditor === editor);
396
397
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: null }));
398
assert.ok(extHostNotebooks.activeNotebookEditor === undefined);
399
});
400
401
test('change cell language triggers onDidChange events', async function () {
402
403
const first = notebook.apiNotebook.cellAt(0);
404
405
assert.strictEqual(first.document.languageId, 'markdown');
406
407
const removed = Event.toPromise(extHostDocuments.onDidRemoveDocument);
408
const added = Event.toPromise(extHostDocuments.onDidAddDocument);
409
410
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
411
versionId: 12, rawEvents: [{
412
kind: NotebookCellsChangeType.ChangeCellLanguage,
413
index: 0,
414
language: 'fooLang'
415
}]
416
}), false);
417
418
const removedDoc = await removed;
419
const addedDoc = await added;
420
421
assert.strictEqual(first.document.languageId, 'fooLang');
422
assert.ok(removedDoc === addedDoc);
423
});
424
425
test('onDidChangeNotebook-event, cell changes', async function () {
426
427
const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);
428
429
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
430
versionId: 12, rawEvents: [{
431
kind: NotebookCellsChangeType.ChangeCellMetadata,
432
index: 0,
433
metadata: { foo: 1 }
434
}, {
435
kind: NotebookCellsChangeType.ChangeCellMetadata,
436
index: 1,
437
metadata: { foo: 2 },
438
}, {
439
kind: NotebookCellsChangeType.Output,
440
index: 1,
441
outputs: [
442
{
443
items: [{
444
valueBytes: VSBuffer.fromByteArray([0, 2, 3]),
445
mime: 'text/plain'
446
}],
447
outputId: '1'
448
}
449
]
450
}]
451
}), false, undefined);
452
453
454
const event = await p;
455
456
assert.strictEqual(event.notebook === notebook.apiNotebook, true);
457
assert.strictEqual(event.contentChanges.length, 0);
458
assert.strictEqual(event.cellChanges.length, 2);
459
460
const [first, second] = event.cellChanges;
461
assert.deepStrictEqual(first.metadata, first.cell.metadata);
462
assert.deepStrictEqual(first.executionSummary, undefined);
463
assert.deepStrictEqual(first.outputs, undefined);
464
assert.deepStrictEqual(first.document, undefined);
465
466
assert.deepStrictEqual(second.outputs, second.cell.outputs);
467
assert.deepStrictEqual(second.metadata, second.cell.metadata);
468
assert.deepStrictEqual(second.executionSummary, undefined);
469
assert.deepStrictEqual(second.document, undefined);
470
});
471
472
test('onDidChangeNotebook-event, notebook metadata', async function () {
473
474
const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);
475
476
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({ versionId: 12, rawEvents: [] }), false, { foo: 2 });
477
478
const event = await p;
479
480
assert.strictEqual(event.notebook === notebook.apiNotebook, true);
481
assert.strictEqual(event.contentChanges.length, 0);
482
assert.strictEqual(event.cellChanges.length, 0);
483
assert.deepStrictEqual(event.metadata, { foo: 2 });
484
});
485
486
test('onDidChangeNotebook-event, froozen data', async function () {
487
488
const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);
489
490
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({ versionId: 12, rawEvents: [] }), false, { foo: 2 });
491
492
const event = await p;
493
494
assert.ok(Object.isFrozen(event));
495
assert.ok(Object.isFrozen(event.cellChanges));
496
assert.ok(Object.isFrozen(event.contentChanges));
497
assert.ok(Object.isFrozen(event.notebook));
498
assert.ok(!Object.isFrozen(event.metadata));
499
});
500
501
test('change cell language and onDidChangeNotebookDocument', async function () {
502
503
const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);
504
505
const first = notebook.apiNotebook.cellAt(0);
506
assert.strictEqual(first.document.languageId, 'markdown');
507
508
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
509
versionId: 12,
510
rawEvents: [{
511
kind: NotebookCellsChangeType.ChangeCellLanguage,
512
index: 0,
513
language: 'fooLang'
514
}]
515
}), false);
516
517
const event = await p;
518
519
assert.strictEqual(event.notebook === notebook.apiNotebook, true);
520
assert.strictEqual(event.contentChanges.length, 0);
521
assert.strictEqual(event.cellChanges.length, 1);
522
523
const [cellChange] = event.cellChanges;
524
525
assert.strictEqual(cellChange.cell === first, true);
526
assert.ok(cellChange.document === first.document);
527
assert.ok(cellChange.executionSummary === undefined);
528
assert.ok(cellChange.metadata === undefined);
529
assert.ok(cellChange.outputs === undefined);
530
});
531
532
test('change notebook cell document and onDidChangeNotebookDocument', async function () {
533
534
const p = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);
535
536
const first = notebook.apiNotebook.cellAt(0);
537
538
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
539
versionId: 12,
540
rawEvents: [{
541
kind: NotebookCellsChangeType.ChangeCellContent,
542
index: 0
543
}]
544
}), false);
545
546
const event = await p;
547
548
assert.strictEqual(event.notebook === notebook.apiNotebook, true);
549
assert.strictEqual(event.contentChanges.length, 0);
550
assert.strictEqual(event.cellChanges.length, 1);
551
552
const [cellChange] = event.cellChanges;
553
554
assert.strictEqual(cellChange.cell === first, true);
555
assert.ok(cellChange.document === first.document);
556
assert.ok(cellChange.executionSummary === undefined);
557
assert.ok(cellChange.metadata === undefined);
558
assert.ok(cellChange.outputs === undefined);
559
});
560
561
async function replaceOutputs(cellIndex: number, outputId: string, outputItems: NotebookOutputItemDto[]) {
562
const changeEvent = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);
563
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers<NotebookCellsChangedEventDto>({
564
versionId: notebook.apiNotebook.version + 1,
565
rawEvents: [{
566
kind: NotebookCellsChangeType.Output,
567
index: cellIndex,
568
outputs: [{ outputId, items: outputItems }]
569
}]
570
}), false);
571
await changeEvent;
572
}
573
async function appendOutputItem(cellIndex: number, outputId: string, outputItems: NotebookOutputItemDto[]) {
574
const changeEvent = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument);
575
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers<NotebookCellsChangedEventDto>({
576
versionId: notebook.apiNotebook.version + 1,
577
rawEvents: [{
578
kind: NotebookCellsChangeType.OutputItem,
579
index: cellIndex,
580
append: true,
581
outputId,
582
outputItems
583
}]
584
}), false);
585
await changeEvent;
586
}
587
test('Append multiple text/plain output items', async function () {
588
await replaceOutputs(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('foo') }]);
589
await appendOutputItem(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('bar') }]);
590
await appendOutputItem(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('baz') }]);
591
592
593
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);
594
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 3);
595
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'text/plain');
596
assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foo');
597
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[1].mime, 'text/plain');
598
assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[1].data).toString(), 'bar');
599
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[2].mime, 'text/plain');
600
assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[2].data).toString(), 'baz');
601
});
602
test('Append multiple stdout stream output items to an output with another mime', async function () {
603
await replaceOutputs(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('foo') }]);
604
await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('bar') }]);
605
await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('baz') }]);
606
607
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);
608
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 3);
609
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'text/plain');
610
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[1].mime, 'application/vnd.code.notebook.stdout');
611
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[2].mime, 'application/vnd.code.notebook.stdout');
612
});
613
test('Compress multiple stdout stream output items', async function () {
614
await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('foo') }]);
615
await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('bar') }]);
616
await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('baz') }]);
617
618
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);
619
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1);
620
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout');
621
assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foobarbaz');
622
});
623
test('Compress multiple stdout stream output items (with support for terminal escape code -> \u001b[A)', async function () {
624
await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('\nfoo') }]);
625
await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString(`${String.fromCharCode(27)}[Abar`) }]);
626
627
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);
628
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1);
629
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout');
630
assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'bar');
631
});
632
test('Compress multiple stdout stream output items (with support for terminal escape code -> \r character)', async function () {
633
await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('foo') }]);
634
await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString(`\rbar`) }]);
635
636
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);
637
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1);
638
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout');
639
assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'bar');
640
});
641
test('Compress multiple stderr stream output items', async function () {
642
await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('foo') }]);
643
await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('bar') }]);
644
await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('baz') }]);
645
646
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1);
647
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1);
648
assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stderr');
649
assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foobarbaz');
650
});
651
});
652
653