notebook.test.ts 40.3 KB
Newer Older
R
rebornix 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  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';
M
Matt Bierner 已提交
7
import 'mocha';
8
import { TextDecoder } from 'util';
M
Matt Bierner 已提交
9 10
import * as vscode from 'vscode';
import { asPromise, assertNoRpc, closeAllEditors, createRandomFile, disposeAll, revertAllDirty, saveAllEditors } from '../utils';
R
rebornix 已提交
11

R
Rob Lourens 已提交
12 13 14 15
async function createRandomNotebookFile() {
	return createRandomFile('', undefined, '.vsctestnb');
}

16 17
async function openRandomNotebookDocument() {
	const uri = await createRandomNotebookFile();
18
	return vscode.workspace.openNotebookDocument(uri);
19 20
}

21 22
async function saveAllFilesAndCloseAll() {
	await saveAllEditors();
R
rebornix 已提交
23
	await closeAllEditors();
24 25
}

R
rebornix 已提交
26
async function withEvent<T>(event: vscode.Event<T>, callback: (e: Promise<T>) => Promise<void>) {
27
	const e = asPromise<T>(event);
R
rebornix 已提交
28 29 30
	await callback(e);
}

31

32
class Kernel {
33

34 35
	readonly controller: vscode.NotebookController;

36 37
	readonly associatedNotebooks = new Set<string>();

38
	constructor(id: string, label: string) {
J
Johannes Rieken 已提交
39
		this.controller = vscode.notebooks.createNotebookController(id, 'notebookCoreTest', label);
40
		this.controller.executeHandler = this._execute.bind(this);
J
Johannes Rieken 已提交
41
		this.controller.supportsExecutionOrder = true;
42
		this.controller.supportedLanguages = ['typescript', 'javascript'];
43
		this.controller.onDidChangeSelectedNotebooks(e => {
44 45 46 47 48 49
			if (e.selected) {
				this.associatedNotebooks.add(e.notebook.uri.toString());
			} else {
				this.associatedNotebooks.delete(e.notebook.uri.toString());
			}
		});
R
Rob Lourens 已提交
50 51
	}

52 53
	protected async _execute(cells: vscode.NotebookCell[]): Promise<void> {
		for (let cell of cells) {
J
Johannes Rieken 已提交
54
			await this._runCell(cell);
R
Rob Lourens 已提交
55
		}
56
	}
R
Rob Lourens 已提交
57

J
Johannes Rieken 已提交
58
	protected async _runCell(cell: vscode.NotebookCell) {
59 60
		// create a single output with exec order 1 and output is plain/text
		// of either the cell itself or (iff empty) the cell's document's uri
61
		const task = this.controller.createNotebookCellExecution(cell);
R
Rob Lourens 已提交
62 63 64
		task.start();
		task.executionOrder = 1;
		await task.replaceOutput([new vscode.NotebookCellOutput([
65
			vscode.NotebookCellOutputItem.text(cell.document.getText() || cell.document.uri.toString(), 'text/plain')
66
		])]);
67
		task.end(true);
R
Rob Lourens 已提交
68
	}
69
}
R
Rob Lourens 已提交
70

71

R
rebornix 已提交
72 73 74 75
function getFocusedCell(editor?: vscode.NotebookEditor) {
	return editor ? editor.document.cellAt(editor.selections[0].start) : undefined;
}

76
async function assertKernel(kernel: Kernel, notebook: vscode.NotebookDocument): Promise<void> {
77 78
	const success = await vscode.commands.executeCommand('notebook.selectKernel', {
		extension: 'vscode.vscode-api-tests',
79
		id: kernel.controller.id
80
	});
81 82
	assert.ok(success, `expected selected kernel to be ${kernel.controller.id}`);
	assert.ok(kernel.associatedNotebooks.has(notebook.uri.toString()));
83 84
}

R
rebornix 已提交
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
const apiTestContentProvider: vscode.NotebookContentProvider = {
	openNotebook: async (resource: vscode.Uri): Promise<vscode.NotebookData> => {
		if (/.*empty\-.*\.vsctestnb$/.test(resource.path)) {
			return {
				metadata: {},
				cells: []
			};
		}

		const dto: vscode.NotebookData = {
			metadata: { custom: { testMetadata: false } },
			cells: [
				{
					value: 'test',
					languageId: 'typescript',
					kind: vscode.NotebookCellKind.Code,
					outputs: [],
					metadata: { custom: { testCellMetadata: 123 } },
					executionSummary: { timing: { startTime: 10, endTime: 20 } }
				},
				{
					value: 'test2',
					languageId: 'typescript',
					kind: vscode.NotebookCellKind.Code,
					outputs: [
						new vscode.NotebookCellOutput([
							vscode.NotebookCellOutputItem.text('Hello World', 'text/plain')
						],
							{
								testOutputMetadata: true,
								['text/plain']: { testOutputItemMetadata: true }
							})
					],
					executionSummary: { executionOrder: 5, success: true },
					metadata: { custom: { testCellMetadata: 456 } }
				}
			]
		};
		return dto;
	},
	saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => {
		return;
	},
	saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => {
		return;
	},
	backupNotebook: async (_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) => {
		return {
			id: '1',
			delete: () => { }
		};
	}
};

139
suite.skip('Notebook API tests', function () {
140

R
Rob Lourens 已提交
141 142
	const testDisposables: vscode.Disposable[] = [];
	const suiteDisposables: vscode.Disposable[] = [];
143 144

	suiteTeardown(async function () {
145 146 147

		assertNoRpc();

148
		await revertAllDirty();
149
		await closeAllEditors();
150

R
Rob Lourens 已提交
151 152
		disposeAll(suiteDisposables);
		suiteDisposables.length = 0;
153 154 155
	});

	suiteSetup(function () {
R
rebornix 已提交
156
		suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider));
R
Rob Lourens 已提交
157
	});
158

159
	let defaultKernel: Kernel;
160

161
	setup(async function () {
162
		// there should be ONE default kernel in this suite
163
		defaultKernel = new Kernel('mainKernel', 'Notebook Default Kernel');
164
		testDisposables.push(defaultKernel.controller);
165
		await saveAllFilesAndCloseAll();
R
Rob Lourens 已提交
166 167
	});

168
	teardown(async function () {
R
Rob Lourens 已提交
169 170
		disposeAll(testDisposables);
		testDisposables.length = 0;
171
		await saveAllFilesAndCloseAll();
172 173
	});

R
rebornix 已提交
174
	test.skip('correct cell selection on undo/redo of cell creation', async function () {
R
rebornix 已提交
175 176
		const notebook = await openRandomNotebookDocument();
		await vscode.window.showNotebookDocument(notebook);
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
		await vscode.commands.executeCommand('undo');
		const selectionUndo = [...vscode.window.activeNotebookEditor!.selections];
		await vscode.commands.executeCommand('redo');
		const selectionRedo = vscode.window.activeNotebookEditor!.selections;

		// On undo, the selected cell must be the upper cell, ie the first one
		assert.strictEqual(selectionUndo.length, 1);
		assert.strictEqual(selectionUndo[0].start, 0);
		assert.strictEqual(selectionUndo[0].end, 1);
		// On redo, the selected cell must be the new cell, ie the second one
		assert.strictEqual(selectionRedo.length, 1);
		assert.strictEqual(selectionRedo[0].start, 1);
		assert.strictEqual(selectionRedo[0].end, 2);
	});

R
rebornix 已提交
193
	test('editor editing event', async function () {
194 195
		const notebook = await openRandomNotebookDocument();
		const editor = await vscode.window.showNotebookDocument(notebook);
196

197
		const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebooks.onDidChangeNotebookCells);
198 199
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
		const cellChangeEventRet = await cellsChangeEvent;
200
		assert.strictEqual(cellChangeEventRet.document, editor.document);
J
Johannes Rieken 已提交
201 202
		assert.strictEqual(cellChangeEventRet.changes.length, 1);
		assert.deepStrictEqual(cellChangeEventRet.changes[0], {
203 204
			start: 1,
			deletedCount: 0,
R
:guard:  
rebornix 已提交
205
			deletedItems: [],
206
			items: [
207
				editor.document.cellAt(1)
208 209 210
			]
		});

211
		const moveCellEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebooks.onDidChangeNotebookCells);
212
		await vscode.commands.executeCommand('notebook.cell.moveUp');
R
rebornix 已提交
213
		await moveCellEvent;
214

215
		const cellOutputChange = asPromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs);
216 217
		await vscode.commands.executeCommand('notebook.cell.execute');
		const cellOutputsAddedRet = await cellOutputChange;
J
Johannes Rieken 已提交
218
		assert.deepStrictEqual(cellOutputsAddedRet, {
219 220
			document: editor.document,
			cells: [editor.document.cellAt(0)]
221
		});
R
rebornix 已提交
222
		assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 1);
223

224
		const cellOutputClear = asPromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs);
225 226
		await vscode.commands.executeCommand('notebook.cell.clearOutputs');
		const cellOutputsCleardRet = await cellOutputClear;
J
Johannes Rieken 已提交
227
		assert.deepStrictEqual(cellOutputsCleardRet, {
228 229
			document: editor.document,
			cells: [editor.document.cellAt(0)]
230
		});
R
rebornix 已提交
231
		assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 0);
232

233
		// const cellChangeLanguage = getEventOncePromise<vscode.NotebookCellLanguageChangeEvent>(vscode.notebooks.onDidChangeCellLanguage);
234 235
		// await vscode.commands.executeCommand('notebook.cell.changeToMarkdown');
		// const cellChangeLanguageRet = await cellChangeLanguage;
J
Johannes Rieken 已提交
236
		// assert.deepStrictEqual(cellChangeLanguageRet, {
R
rebornix 已提交
237
		// 	document: vscode.window.activeNotebookEditor!.document,
238
		// 	cells: vscode.window.activeNotebookEditor!.document.cellAt(0),
239 240 241
		// 	language: 'markdown'
		// });
	});
R
rebornix 已提交
242

D
Oops  
Don Jayamanne 已提交
243
	test('edit API batch edits', async function () {
244 245
		const notebook = await openRandomNotebookDocument();
		const editor = await vscode.window.showNotebookDocument(notebook);
R
rebornix 已提交
246

247 248
		const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebooks.onDidChangeNotebookCells);
		const cellMetadataChangeEvent = asPromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebooks.onDidChangeCellMetadata);
249 250
		const version = editor.document.version;
		await editor.edit(editBuilder => {
251
			editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]);
252
			editBuilder.replaceCellMetadata(0, { inputCollapsed: false });
R
rebornix 已提交
253 254 255 256
		});

		await cellsChangeEvent;
		await cellMetadataChangeEvent;
257
		assert.strictEqual(version + 1, editor.document.version);
R
rebornix 已提交
258 259
	});

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
	test('edit API batch edits undo/redo', async function () {
		const notebook = await openRandomNotebookDocument();
		const editor = await vscode.window.showNotebookDocument(notebook);

		const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebooks.onDidChangeNotebookCells);
		const cellMetadataChangeEvent = asPromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebooks.onDidChangeCellMetadata);
		const version = editor.document.version;
		await editor.edit(editBuilder => {
			editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]);
			editBuilder.replaceCellMetadata(0, { inputCollapsed: false });
		});

		await cellsChangeEvent;
		await cellMetadataChangeEvent;
		assert.strictEqual(editor.document.cellCount, 3);
		assert.strictEqual(editor.document.cellAt(0)?.metadata.inputCollapsed, false);
		assert.strictEqual(version + 1, editor.document.version);

		await vscode.commands.executeCommand('undo');
		assert.strictEqual(version + 2, editor.document.version);
		assert.strictEqual(editor.document.cellAt(0)?.metadata.inputCollapsed, undefined);
		assert.strictEqual(editor.document.cellCount, 2);
	});

284
	test('#98841, initialzation should not emit cell change events.', async function () {
285
		let count = 0;
286

287
		testDisposables.push(vscode.notebooks.onDidChangeNotebookCells(() => {
288 289 290
			count++;
		}));

R
rebornix 已提交
291 292
		const notebook = await openRandomNotebookDocument();
		await vscode.window.showNotebookDocument(notebook);
J
Johannes Rieken 已提交
293
		assert.strictEqual(count, 0);
294
	});
295

D
Oops  
Don Jayamanne 已提交
296
	test('notebook open', async function () {
297
		const notebook = await openRandomNotebookDocument();
R
rebornix 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310
		const editor = await vscode.window.showNotebookDocument(notebook);
		assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first');
		assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test');
		assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');

		const secondCell = editor.document.cellAt(1);
		assert.strictEqual(secondCell.outputs.length, 1);
		assert.deepStrictEqual(secondCell.outputs[0].metadata, { testOutputMetadata: true, ['text/plain']: { testOutputItemMetadata: true } });
		assert.strictEqual(secondCell.outputs[0].items.length, 1);
		assert.strictEqual(secondCell.outputs[0].items[0].mime, 'text/plain');
		assert.strictEqual(new TextDecoder().decode(secondCell.outputs[0].items[0].data), 'Hello World');
		assert.strictEqual(secondCell.executionSummary?.executionOrder, 5);
		assert.strictEqual(secondCell.executionSummary?.success, true);
R
rebornix 已提交
311 312
	});

D
Oops  
Don Jayamanne 已提交
313
	test('notebook cell actions', async function () {
314
		const notebook = await openRandomNotebookDocument();
315
		const editor = await vscode.window.showNotebookDocument(notebook);
J
Johannes Rieken 已提交
316
		assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
317 318 319
		assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first');
		assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test');
		assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
R
rebornix 已提交
320 321

		// ---- insert cell below and focus ---- //
R
Rob Lourens 已提交
322
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
323
		assert.strictEqual(getFocusedCell(editor)?.document.getText(), '');
R
rebornix 已提交
324 325

		// ---- insert cell above and focus ---- //
R
Rob Lourens 已提交
326
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
327 328
		let activeCell = getFocusedCell(editor);
		assert.notStrictEqual(getFocusedCell(editor), undefined);
J
Johannes Rieken 已提交
329
		assert.strictEqual(activeCell!.document.getText(), '');
330 331
		assert.strictEqual(editor.document.cellCount, 4);
		assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
R
rebornix 已提交
332 333

		// ---- focus bottom ---- //
R
Rob Lourens 已提交
334
		await vscode.commands.executeCommand('notebook.focusBottom');
335 336
		activeCell = getFocusedCell(editor);
		assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 3);
R
rebornix 已提交
337 338

		// ---- focus top and then copy down ---- //
R
Rob Lourens 已提交
339
		await vscode.commands.executeCommand('notebook.focusTop');
340 341
		activeCell = getFocusedCell(editor);
		assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 0);
R
rebornix 已提交
342

R
Rob Lourens 已提交
343
		await vscode.commands.executeCommand('notebook.cell.copyDown');
344 345
		activeCell = getFocusedCell(editor);
		assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
J
Johannes Rieken 已提交
346
		assert.strictEqual(activeCell?.document.getText(), 'test');
R
rebornix 已提交
347

348
		{
349
			const focusedCell = getFocusedCell(editor);
350 351 352 353 354 355 356
			assert.strictEqual(focusedCell !== undefined, true);
			// delete focused cell
			const edit = new vscode.WorkspaceEdit();
			edit.replaceNotebookCells(focusedCell!.notebook.uri, new vscode.NotebookRange(focusedCell!.index, focusedCell!.index + 1), []);
			await vscode.workspace.applyEdit(edit);
		}

357 358
		activeCell = getFocusedCell(editor);
		assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
J
Johannes Rieken 已提交
359
		assert.strictEqual(activeCell?.document.getText(), '');
R
rebornix 已提交
360 361

		// ---- focus top and then copy up ---- //
R
Rob Lourens 已提交
362 363
		await vscode.commands.executeCommand('notebook.focusTop');
		await vscode.commands.executeCommand('notebook.cell.copyUp');
364 365 366 367 368 369 370
		assert.strictEqual(editor.document.cellCount, 5);
		assert.strictEqual(editor.document.cellAt(0).document.getText(), 'test');
		assert.strictEqual(editor.document.cellAt(1).document.getText(), 'test');
		assert.strictEqual(editor.document.cellAt(2).document.getText(), '');
		assert.strictEqual(editor.document.cellAt(3).document.getText(), '');
		activeCell = getFocusedCell(editor);
		assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 0);
R
rebornix 已提交
371 372 373 374


		// ---- move up and down ---- //

R
Rob Lourens 已提交
375
		await vscode.commands.executeCommand('notebook.cell.moveDown');
376 377
		assert.strictEqual(editor.document.getCells().indexOf(getFocusedCell(editor)!), 1,
			`first move down, active cell ${getFocusedCell(editor)!.document.uri.toString()}, ${getFocusedCell(editor)!.document.getText()}`);
378

R
rebornix 已提交
379 380 381 382
		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});

R
rebornix 已提交
383
	test('editor move command - event and move cells will not recreate cells in ExtHost (#98126)', async function () {
384
		const notebook = await openRandomNotebookDocument();
R
rebornix 已提交
385
		const editor = await vscode.window.showNotebookDocument(notebook);
386

R
rebornix 已提交
387 388 389
		const activeCell = getFocusedCell(editor);
		assert.strictEqual(activeCell?.index, 0);
		const moveChange = asPromise(vscode.notebooks.onDidChangeNotebookCells);
390
		await vscode.commands.executeCommand('notebook.cell.moveDown');
R
rebornix 已提交
391
		assert.ok(await moveChange);
392

R
rebornix 已提交
393 394
		const newActiveCell = getFocusedCell(editor);
		assert.strictEqual(newActiveCell?.index, 1);
J
Johannes Rieken 已提交
395
		assert.deepStrictEqual(activeCell, newActiveCell);
396 397
	});

398
	// test('document runnable based on kernel count', async () => {
R
Rob Lourens 已提交
399
	// 	const resource = await createRandomNotebookFile();
400 401 402
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 	assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
	// 	const editor = vscode.window.activeNotebookEditor!;
R
Rob Lourens 已提交
403

404 405
	// 	const cell = editor.document.cellAt(0);
	// 	assert.strictEqual(cell.outputs.length, 0);
R
rebornix 已提交
406

407 408 409
	// 	currentKernelProvider.setHasKernels(false);
	// 	await vscode.commands.executeCommand('notebook.execute');
	// 	assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work
R
Rob Lourens 已提交
410

411
	// 	currentKernelProvider.setHasKernels(true);
412

413
	// 	await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs, async (event) => {
414 415 416 417
	// 		await vscode.commands.executeCommand('notebook.execute');
	// 		await event;
	// 		assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
	// 	});
R
Rob Lourens 已提交
418

419 420
	// 	await saveAllFilesAndCloseAll(undefined);
	// });
R
rebornix 已提交
421

R
rebornix 已提交
422 423 424

	// TODO@rebornix this is wrong, `await vscode.commands.executeCommand('notebook.execute');` doesn't wait until the workspace edit is applied
	test.skip('cell execute command takes arguments', async () => {
R
Rob Lourens 已提交
425
		const resource = await createRandomNotebookFile();
R
rebornix 已提交
426
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
J
Johannes Rieken 已提交
427
		assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
R
rebornix 已提交
428
		const editor = vscode.window.activeNotebookEditor!;
429
		const cell = editor.document.cellAt(0);
R
rebornix 已提交
430 431

		await vscode.commands.executeCommand('notebook.execute');
R
rebornix 已提交
432
		assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work
R
rebornix 已提交
433
	});
R
rebornix 已提交
434

D
Oops  
Don Jayamanne 已提交
435
	test('cell execute command takes arguments 2', async () => {
R
Rob Lourens 已提交
436
		const resource = await createRandomNotebookFile();
R
rebornix 已提交
437
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
J
Johannes Rieken 已提交
438
		assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
R
rebornix 已提交
439
		const editor = vscode.window.activeNotebookEditor!;
440
		const cell = editor.document.cellAt(0);
R
rebornix 已提交
441

442
		await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => {
R
rebornix 已提交
443 444
			await vscode.commands.executeCommand('notebook.execute');
			await event;
R
rebornix 已提交
445
			assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
R
rebornix 已提交
446 447
		});

448
		await withEvent(vscode.notebooks.onDidChangeCellOutputs, async event => {
R
rebornix 已提交
449 450
			await vscode.commands.executeCommand('notebook.cell.clearOutputs');
			await event;
R
rebornix 已提交
451
			assert.strictEqual(cell.outputs.length, 0, 'should clear');
R
rebornix 已提交
452
		});
R
rebornix 已提交
453

R
Rob Lourens 已提交
454
		const secondResource = await createRandomNotebookFile();
R
rebornix 已提交
455
		await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
R
rebornix 已提交
456

457
		await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs, async (event) => {
R
rebornix 已提交
458 459
			await vscode.commands.executeCommand('notebook.cell.execute', { start: 0, end: 1 }, resource);
			await event;
R
rebornix 已提交
460
			assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
J
Johannes Rieken 已提交
461
			assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath);
R
rebornix 已提交
462
		});
R
rebornix 已提交
463
	});
R
rebornix 已提交
464 465 466 467 468 469 470 471 472 473

	test('cell execute command takes arguments ICellRange[]', async () => {
		const resource = await createRandomNotebookFile();
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		vscode.commands.executeCommand('notebook.cell.execute', { ranges: [{ start: 0, end: 1 }, { start: 1, end: 2 }] });
		let firstCellExecuted = false;
		let secondCellExecuted = false;
		let resolve: () => void;
		const p = new Promise<void>(r => resolve = r);
474
		const listener = vscode.notebooks.onDidChangeCellOutputs(e => {
R
rebornix 已提交
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
			e.cells.forEach(cell => {
				if (cell.index === 0) {
					firstCellExecuted = true;
				}

				if (cell.index === 1) {
					secondCellExecuted = true;
				}
			});

			if (firstCellExecuted && secondCellExecuted) {
				resolve();
			}
		});

		await p;
		listener.dispose();
R
rebornix 已提交
492
		await saveAllFilesAndCloseAll();
R
rebornix 已提交
493
	});
R
rebornix 已提交
494

D
Oops  
Don Jayamanne 已提交
495
	test('document execute command takes arguments', async () => {
R
Rob Lourens 已提交
496
		const resource = await createRandomNotebookFile();
R
rebornix 已提交
497
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
J
Johannes Rieken 已提交
498
		assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
R
rebornix 已提交
499
		const editor = vscode.window.activeNotebookEditor!;
500
		const cell = editor.document.cellAt(0);
R
rebornix 已提交
501

502
		await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs, async (event) => {
R
rebornix 已提交
503 504
			await vscode.commands.executeCommand('notebook.execute');
			await event;
R
rebornix 已提交
505
			assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
R
rebornix 已提交
506
		});
R
rebornix 已提交
507

508
		const clearChangeEvent = asPromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs);
R
rebornix 已提交
509 510
		await vscode.commands.executeCommand('notebook.cell.clearOutputs');
		await clearChangeEvent;
R
rebornix 已提交
511
		assert.strictEqual(cell.outputs.length, 0, 'should clear');
R
rebornix 已提交
512

R
Rob Lourens 已提交
513
		const secondResource = await createRandomNotebookFile();
R
rebornix 已提交
514
		await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
R
rebornix 已提交
515

516
		await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs, async (event) => {
R
rebornix 已提交
517 518
			await vscode.commands.executeCommand('notebook.execute', resource);
			await event;
R
rebornix 已提交
519
			assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
J
Johannes Rieken 已提交
520
			assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath);
R
rebornix 已提交
521
		});
R
rebornix 已提交
522 523
	});

524
	test('cell execute and select kernel', async function () {
525 526 527 528
		const notebook = await openRandomNotebookDocument();
		const editor = await vscode.window.showNotebookDocument(notebook);
		assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first');

529
		const cell = editor.document.cellAt(0);
R
rebornix 已提交
530

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
		const alternativeKernel = new class extends Kernel {
			constructor() {
				super('secondaryKernel', 'Notebook Secondary Test Kernel');
				this.controller.supportsExecutionOrder = false;
			}

			override async _runCell(cell: vscode.NotebookCell) {
				const task = this.controller.createNotebookCellExecution(cell);
				task.start();
				await task.replaceOutput([new vscode.NotebookCellOutput([
					vscode.NotebookCellOutputItem.text('my second output', 'text/plain')
				])]);
				task.end(true);
			}
		};
		testDisposables.push(alternativeKernel.controller);

548
		await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs, async (event) => {
549
			await assertKernel(defaultKernel, notebook);
J
Johannes Rieken 已提交
550
			await vscode.commands.executeCommand('notebook.cell.execute');
R
Rob Lourens 已提交
551 552
			await event;
			assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
553 554
			assert.strictEqual(cell.outputs[0].items.length, 1);
			assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain');
555
			assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), cell.document.getText());
R
Rob Lourens 已提交
556
		});
R
rebornix 已提交
557

558
		await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebooks.onDidChangeCellOutputs, async (event) => {
559
			await assertKernel(alternativeKernel, notebook);
J
Johannes Rieken 已提交
560
			await vscode.commands.executeCommand('notebook.cell.execute');
R
Rob Lourens 已提交
561 562
			await event;
			assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
563 564 565
			assert.strictEqual(cell.outputs[0].items.length, 1);
			assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain');
			assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), 'my second output');
R
Rob Lourens 已提交
566
		});
R
rebornix 已提交
567
	});
R
Rob Lourens 已提交
568 569

	test('onDidChangeCellExecutionState is fired', async () => {
R
Rob Lourens 已提交
570
		const resource = await createRandomNotebookFile();
R
Rob Lourens 已提交
571 572
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		const editor = vscode.window.activeNotebookEditor!;
573
		const cell = editor.document.cellAt(0);
R
Rob Lourens 已提交
574 575 576 577 578

		vscode.commands.executeCommand('notebook.cell.execute');
		let eventCount = 0;
		let resolve: () => void;
		const p = new Promise<void>(r => resolve = r);
579
		const listener = vscode.notebooks.onDidChangeNotebookCellExecutionState(e => {
R
Rob Lourens 已提交
580
			if (eventCount === 0) {
581
				assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Pending, 'should be set to Pending');
R
Rob Lourens 已提交
582
			} else if (eventCount === 1) {
583
				assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Executing, 'should be set to Executing');
R
Rob Lourens 已提交
584 585
				assert.strictEqual(cell.outputs.length, 0, 'no outputs yet: ' + JSON.stringify(cell.outputs[0]));
			} else if (eventCount === 2) {
586
				assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Idle, 'should be set to Idle');
R
Rob Lourens 已提交
587 588 589 590 591 592 593 594 595 596
				assert.strictEqual(cell.outputs.length, 1, 'should have an output');
				resolve();
			}

			eventCount++;
		});

		await p;
		listener.dispose();
	});
R
rebornix 已提交
597

598
	test('notebook cell document workspace edit', async function () {
R
rebornix 已提交
599 600 601 602 603
		const notebook = await openRandomNotebookDocument();
		const editor = await vscode.window.showNotebookDocument(notebook);
		assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first');
		assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test');
		assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
R
rebornix 已提交
604 605

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
R
rebornix 已提交
606
		assert.strictEqual(getFocusedCell(editor)?.document.getText(), '');
R
rebornix 已提交
607 608

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
609 610
		const activeCell = getFocusedCell(editor);
		assert.notStrictEqual(getFocusedCell(editor), undefined);
J
Johannes Rieken 已提交
611
		assert.strictEqual(activeCell!.document.getText(), '');
R
rebornix 已提交
612 613
		assert.strictEqual(editor.document.cellCount, 4);
		assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
R
rebornix 已提交
614

R
rebornix 已提交
615 616
		await withEvent(vscode.workspace.onDidChangeTextDocument, async event => {
			const edit = new vscode.WorkspaceEdit();
J
Johannes Rieken 已提交
617
			edit.insert(activeCell!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
R
rebornix 已提交
618 619
			await vscode.workspace.applyEdit(edit);
			await event;
R
rebornix 已提交
620 621 622
			assert.strictEqual(vscode.window.activeNotebookEditor === editor, true);
			assert.deepStrictEqual(editor.document.cellAt(1), getFocusedCell(editor));
			assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'var abc = 0;');
R
rebornix 已提交
623
		});
R
rebornix 已提交
624 625
	});

D
Oops  
Don Jayamanne 已提交
626
	test('multiple tabs: dirty + clean', async function () {
R
rebornix 已提交
627 628
		const notebook = await openRandomNotebookDocument();
		await vscode.window.showNotebookDocument(notebook);
629
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
R
rebornix 已提交
630
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
631 632

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
633
		const edit = new vscode.WorkspaceEdit();
R
rebornix 已提交
634
		edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
R
rebornix 已提交
635
		await vscode.workspace.applyEdit(edit);
636

R
rebornix 已提交
637 638
		const secondNotebook = await openRandomNotebookDocument();
		await vscode.window.showNotebookDocument(secondNotebook);
639 640 641
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');

		// make sure that the previous dirty editor is still restored in the extension host and no data loss
J
Johannes Rieken 已提交
642
		assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
R
rebornix 已提交
643
		assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
644
		assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4);
R
rebornix 已提交
645
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;');
646 647 648

	});

R
rebornix 已提交
649
	test.skip('multiple tabs: two dirty tabs and switching', async function () {
R
rebornix 已提交
650 651
		const notebook = await openRandomNotebookDocument();
		await vscode.window.showNotebookDocument(notebook);
652
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
R
rebornix 已提交
653
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
654 655

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
656
		const edit = new vscode.WorkspaceEdit();
R
rebornix 已提交
657
		edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
R
rebornix 已提交
658
		await vscode.workspace.applyEdit(edit);
659

R
rebornix 已提交
660 661
		const secondNotebook = await openRandomNotebookDocument();
		await vscode.window.showNotebookDocument(secondNotebook);
662
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
R
rebornix 已提交
663
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
664 665

		// switch to the first editor
R
rebornix 已提交
666
		await vscode.window.showNotebookDocument(notebook);
J
Johannes Rieken 已提交
667
		assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
R
rebornix 已提交
668
		assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
669
		assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4);
R
rebornix 已提交
670
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;');
671 672

		// switch to the second editor
R
rebornix 已提交
673
		await vscode.window.showNotebookDocument(secondNotebook);
J
Johannes Rieken 已提交
674
		assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
R
rebornix 已提交
675
		assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
676
		assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 3);
R
rebornix 已提交
677
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
678

679 680
	});

M
Matt Bierner 已提交
681
	test('multiple tabs: different editors with same document', async function () {
682 683 684 685 686

		const notebook = await openRandomNotebookDocument();
		const firstNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.One });
		assert.ok(firstNotebookEditor === vscode.window.activeNotebookEditor);

J
Johannes Rieken 已提交
687
		assert.strictEqual(firstNotebookEditor !== undefined, true, 'notebook first');
R
rebornix 已提交
688 689
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.getText(), 'test');
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript');
690

M
Matt Bierner 已提交
691
		const secondNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Beside });
J
Johannes Rieken 已提交
692
		assert.strictEqual(secondNotebookEditor !== undefined, true, 'notebook first');
R
rebornix 已提交
693 694
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.getText(), 'test');
		assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript');
695

L
Logan Ramos 已提交
696
		assert.notStrictEqual(firstNotebookEditor, secondNotebookEditor);
J
Johannes Rieken 已提交
697
		assert.strictEqual(firstNotebookEditor?.document, secondNotebookEditor?.document, 'split notebook editors share the same document');
698

699
	});
700

701
	test.skip('#106657. Opening a notebook from markers view is broken ', async function () {
702

703
		const document = await openRandomNotebookDocument();
704
		const [cell] = document.getCells();
705

R
rebornix 已提交
706
		assert.strictEqual(vscode.window.activeNotebookEditor, undefined);
707 708

		// opening a cell-uri opens a notebook editor
709 710
		await vscode.window.showTextDocument(cell.document, { viewColumn: vscode.ViewColumn.Active });
		// await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active);
711

R
rebornix 已提交
712
		assert.strictEqual(!!vscode.window.activeNotebookEditor, true);
713
		assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString());
714 715
	});

L
Logan Ramos 已提交
716
	test('Cannot open notebook from cell-uri with vscode.open-command', async function () {
717

718
		const document = await openRandomNotebookDocument();
719
		const [cell] = document.getCells();
720

721
		await saveAllFilesAndCloseAll();
R
rebornix 已提交
722
		assert.strictEqual(vscode.window.activeNotebookEditor, undefined);
723 724 725

		// BUG is that the editor opener (https://github.com/microsoft/vscode/blob/8e7877bdc442f1e83a7fec51920d82b696139129/src/vs/editor/browser/services/openerService.ts#L69)
		// removes the fragment if it matches something numeric. For notebooks that's not wanted...
J
Johannes Rieken 已提交
726
		await vscode.commands.executeCommand('vscode.open', cell.document.uri);
727

728
		assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString());
729 730
	});

D
Oops  
Don Jayamanne 已提交
731
	test('#97830, #97764. Support switch to other editor types', async function () {
R
rebornix 已提交
732 733
		const notebook = await openRandomNotebookDocument();
		const editor = await vscode.window.showNotebookDocument(notebook);
734
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
R
rebornix 已提交
735
		const edit = new vscode.WorkspaceEdit();
R
rebornix 已提交
736
		edit.insert(getFocusedCell(editor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
R
rebornix 已提交
737
		await vscode.workspace.applyEdit(edit);
738

R
rebornix 已提交
739
		assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'var abc = 0;');
740 741

		// no kernel -> no default language
R
rebornix 已提交
742
		// assert.strictEqual(vscode.window.activeNotebookEditor!.kernel, undefined);
R
rebornix 已提交
743
		assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
744

R
rebornix 已提交
745 746
		await vscode.commands.executeCommand('vscode.openWith', notebook.uri, 'default');
		assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, notebook.uri.path);
747
	});
748 749

	// open text editor, pin, and then open a notebook
D
Oops  
Don Jayamanne 已提交
750
	test('#96105 - dirty editors', async function () {
R
Rob Lourens 已提交
751
		const resource = await createRandomNotebookFile();
752
		await vscode.commands.executeCommand('vscode.openWith', resource, 'default');
R
rebornix 已提交
753
		const edit = new vscode.WorkspaceEdit();
R
rebornix 已提交
754
		edit.insert(resource, new vscode.Position(0, 0), 'var abc = 0;');
R
rebornix 已提交
755
		await vscode.workspace.applyEdit(edit);
756 757 758

		// now it's dirty, open the resource with notebook editor should open a new one
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
L
Logan Ramos 已提交
759 760
		assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'notebook first');
		// assert.notStrictEqual(vscode.window.activeTextEditor, undefined);
761 762 763

	});

D
Oops  
Don Jayamanne 已提交
764
	test('#102411 - untitled notebook creation failed', async function () {
J
Johannes Rieken 已提交
765
		await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: 'notebookCoreTest' });
L
Logan Ramos 已提交
766
		assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined');
767

R
rebornix 已提交
768
		await closeAllEditors();
R
rebornix 已提交
769
	});
R
rebornix 已提交
770

D
Oops  
Don Jayamanne 已提交
771
	test('#102423 - copy/paste shares the same text buffer', async function () {
R
Rob Lourens 已提交
772
		const resource = await createRandomNotebookFile();
R
rebornix 已提交
773 774
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

R
rebornix 已提交
775
		let activeCell = getFocusedCell(vscode.window.activeNotebookEditor);
J
Johannes Rieken 已提交
776
		assert.strictEqual(activeCell?.document.getText(), 'test');
R
rebornix 已提交
777 778 779

		await vscode.commands.executeCommand('notebook.cell.copyDown');
		await vscode.commands.executeCommand('notebook.cell.edit');
R
rebornix 已提交
780
		activeCell = getFocusedCell(vscode.window.activeNotebookEditor);
781
		assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
J
Johannes Rieken 已提交
782
		assert.strictEqual(activeCell?.document.getText(), 'test');
R
rebornix 已提交
783

R
rebornix 已提交
784
		const edit = new vscode.WorkspaceEdit();
R
rebornix 已提交
785
		edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
R
rebornix 已提交
786
		await vscode.workspace.applyEdit(edit);
R
rebornix 已提交
787

788
		assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().length, 3);
L
Logan Ramos 已提交
789
		assert.notStrictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.document.cellAt(1).document.getText());
790

R
rebornix 已提交
791
		await closeAllEditors();
R
rebornix 已提交
792
	});
793

D
Oops  
Don Jayamanne 已提交
794
	test('#115855 onDidSaveNotebookDocument', async function () {
R
Rob Lourens 已提交
795
		const resource = await createRandomNotebookFile();
796
		const notebook = await vscode.workspace.openNotebookDocument(resource);
797
		const editor = await vscode.window.showNotebookDocument(notebook);
R
rebornix 已提交
798

799
		const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebooks.onDidChangeNotebookCells);
800
		await editor.edit(editBuilder => {
801
			editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]);
R
rebornix 已提交
802 803 804
		});

		const cellChangeEventRet = await cellsChangeEvent;
805
		assert.strictEqual(cellChangeEventRet.document === notebook, true);
R
rebornix 已提交
806 807
		assert.strictEqual(cellChangeEventRet.document.isDirty, true);

808
		const saveEvent = asPromise(vscode.notebooks.onDidSaveNotebookDocument);
809 810 811 812 813

		await notebook.save();

		await saveEvent;
		assert.strictEqual(notebook.isDirty, false);
R
rebornix 已提交
814 815
	});

816
	test('Output changes are applied once the promise resolves', async function () {
817 818 819

		let called = false;

820 821 822 823 824
		const verifyOutputSyncKernel = new class extends Kernel {

			constructor() {
				super('verifyOutputSyncKernel', '');
			}
R
Rob Lourens 已提交
825

826 827
			override async _execute(cells: vscode.NotebookCell[]) {
				const [cell] = cells;
828
				const task = this.controller.createNotebookCellExecution(cell);
R
Rob Lourens 已提交
829 830
				task.start();
				await task.replaceOutput([new vscode.NotebookCellOutput([
831
					vscode.NotebookCellOutputItem.text('Some output', 'text/plain')
R
Rob Lourens 已提交
832
				])]);
833
				assert.strictEqual(cell.notebook.cellAt(0).outputs.length, 1);
834
				assert.deepStrictEqual(new TextDecoder().decode(cell.notebook.cellAt(0).outputs[0].items[0].data), 'Some output');
835
				task.end(undefined);
836
				called = true;
R
Rob Lourens 已提交
837 838 839
			}
		};

840 841 842
		const notebook = await openRandomNotebookDocument();
		await vscode.window.showNotebookDocument(notebook);
		await assertKernel(verifyOutputSyncKernel, notebook);
R
Rob Lourens 已提交
843
		await vscode.commands.executeCommand('notebook.cell.execute');
844
		assert.strictEqual(called, true);
845
		verifyOutputSyncKernel.controller.dispose();
R
Rob Lourens 已提交
846 847
	});

848
	test('executionSummary', async () => {
R
Rob Lourens 已提交
849
		const resource = await createRandomNotebookFile();
R
Rob Lourens 已提交
850 851
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		const editor = vscode.window.activeNotebookEditor!;
852
		const cell = editor.document.cellAt(0);
853

854 855
		assert.strictEqual(cell.executionSummary?.success, undefined);
		assert.strictEqual(cell.executionSummary?.executionOrder, undefined);
R
Rob Lourens 已提交
856 857
		await vscode.commands.executeCommand('notebook.cell.execute');
		assert.strictEqual(cell.outputs.length, 1, 'should execute');
858 859 860
		assert.ok(cell.executionSummary);
		assert.strictEqual(cell.executionSummary!.success, true);
		assert.strictEqual(typeof cell.executionSummary!.executionOrder, 'number');
861
	});
862

863
	test('initialize executionSummary', async () => {
864 865 866

		const document = await openRandomNotebookDocument();
		const cell = document.cellAt(0);
R
Rob Lourens 已提交
867

868
		assert.strictEqual(cell.executionSummary?.success, undefined);
869 870
		assert.strictEqual(cell.executionSummary?.timing?.startTime, 10);
		assert.strictEqual(cell.executionSummary?.timing?.endTime, 20);
R
Rob Lourens 已提交
871 872

	});
R
rebornix 已提交
873
});
R
Rob Lourens 已提交
874

875
suite.skip('statusbar', () => {
R
rebornix 已提交
876 877
	const emitter = new vscode.EventEmitter<vscode.NotebookCell>();
	const onDidCallProvide = emitter.event;
R
rebornix 已提交
878 879 880 881 882 883 884 885 886 887 888
	const suiteDisposables: vscode.Disposable[] = [];
	suiteTeardown(async function () {
		assertNoRpc();

		await revertAllDirty();
		await closeAllEditors();

		disposeAll(suiteDisposables);
		suiteDisposables.length = 0;
	});

R
rebornix 已提交
889
	suiteSetup(() => {
R
rebornix 已提交
890
		suiteDisposables.push(vscode.notebooks.registerNotebookCellStatusBarItemProvider('notebookCoreTest', {
R
rebornix 已提交
891 892 893 894
			async provideCellStatusBarItems(cell: vscode.NotebookCell, _token: vscode.CancellationToken): Promise<vscode.NotebookCellStatusBarItem[]> {
				emitter.fire(cell);
				return [];
			}
R
rebornix 已提交
895 896 897
		}));

		suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider));
R
Rob Lourens 已提交
898 899
	});

R
rebornix 已提交
900 901 902 903 904
	test('provideCellStatusBarItems called on metadata change', async function () {
		const provideCalled = asPromise(onDidCallProvide);
		const resource = await createRandomNotebookFile();
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await provideCalled;
905

R
rebornix 已提交
906 907 908 909 910
		const edit = new vscode.WorkspaceEdit();
		edit.replaceNotebookCellMetadata(resource, 0, { inputCollapsed: true });
		vscode.workspace.applyEdit(edit);
		await provideCalled;
	});
R
rebornix 已提交
911
});
R
rebornix 已提交
912

913
suite.skip('Notebook API tests (metadata)', function () {
R
rebornix 已提交
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
	const testDisposables: vscode.Disposable[] = [];
	const suiteDisposables: vscode.Disposable[] = [];

	suiteTeardown(async function () {
		assertNoRpc();

		await revertAllDirty();
		await closeAllEditors();

		disposeAll(suiteDisposables);
		suiteDisposables.length = 0;
	});

	suiteSetup(function () {
		suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider));
	});

	setup(async function () {
		await saveAllFilesAndCloseAll();
	});

	teardown(async function () {
		disposeAll(testDisposables);
		testDisposables.length = 0;
		await saveAllFilesAndCloseAll();
	});

	test('custom metadata should be supported', async function () {
		const notebook = await openRandomNotebookDocument();
		const editor = await vscode.window.showNotebookDocument(notebook);

		assert.strictEqual(editor.document.metadata.custom?.testMetadata, false);
		assert.strictEqual(getFocusedCell(editor)?.metadata.custom?.testCellMetadata, 123);
		assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
	});
});