notebook.test.ts 63.3 KB
Newer Older
R
rebornix 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import 'mocha';
import * as assert from 'assert';
import * as vscode from 'vscode';
R
rebornix 已提交
9
import { createRandomFile } from './utils';
R
rebornix 已提交
10

R
rebornix 已提交
11 12 13 14 15 16 17 18
export function timeoutAsync(n: number): Promise<void> {
	return new Promise(resolve => {
		setTimeout(() => {
			resolve();
		}, n);
	});
}

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
export function once<T>(event: vscode.Event<T>): vscode.Event<T> {
	return (listener: any, thisArgs = null, disposables?: any) => {
		// we need this, in case the event fires during the listener call
		let didFire = false;
		let result: vscode.Disposable;
		result = event(e => {
			if (didFire) {
				return;
			} else if (result) {
				result.dispose();
			} else {
				didFire = true;
			}

			return listener.call(thisArgs, e);
		}, null, disposables);

		if (didFire) {
			result.dispose();
		}

		return result;
	};
}
R
rebornix 已提交
43

44 45 46
async function getEventOncePromise<T>(event: vscode.Event<T>): Promise<T> {
	return new Promise<T>((resolve, _reject) => {
		once(event)((result: T) => resolve(result));
R
rebornix 已提交
47 48 49
	});
}

50 51 52 53 54 55 56 57 58
// Since `workbench.action.splitEditor` command does await properly
// Notebook editor/document events are not guaranteed to be sent to the ext host when promise resolves
// The workaround here is waiting for the first visible notebook editor change event.
async function splitEditor() {
	const once = getEventOncePromise(vscode.notebook.onDidChangeVisibleNotebookEditors);
	await vscode.commands.executeCommand('workbench.action.splitEditor');
	await once;
}

59 60 61 62 63 64 65 66 67 68 69 70 71 72
async function saveFileAndCloseAll(resource: vscode.Uri) {
	const documentClosed = new Promise((resolve, _reject) => {
		const d = vscode.notebook.onDidCloseNotebookDocument(e => {
			if (e.uri.toString() === resource.toString()) {
				d.dispose();
				resolve();
			}
		});
	});
	await vscode.commands.executeCommand('workbench.action.files.save');
	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	await documentClosed;
}

73
async function saveAllFilesAndCloseAll(resource: vscode.Uri | undefined) {
74
	const documentClosed = new Promise((resolve, _reject) => {
75 76 77
		if (!resource) {
			return resolve();
		}
78 79 80 81 82 83 84 85 86 87 88 89 90
		const d = vscode.notebook.onDidCloseNotebookDocument(e => {
			if (e.uri.toString() === resource.toString()) {
				d.dispose();
				resolve();
			}
		});
	});
	await vscode.commands.executeCommand('workbench.action.files.saveAll');
	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	await documentClosed;
}

function assertInitalState() {
R
rebornix 已提交
91
	// no-op unless we figure out why some documents are opened after the editor is closed
92

R
rebornix 已提交
93 94 95
	// assert.equal(vscode.notebook.activeNotebookEditor, undefined);
	// assert.equal(vscode.notebook.notebookDocuments.length, 0);
	// assert.equal(vscode.notebook.visibleNotebookEditors.length, 0);
96 97
}

R
rebornix 已提交
98
suite('Notebook API tests', () => {
R
rebornix 已提交
99 100 101 102 103 104 105 106 107 108 109 110
	// test.only('crash', async function () {
	// 	for (let i = 0; i < 200; i++) {
	// 		let resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
	// 		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 		await vscode.commands.executeCommand('workbench.action.revertAndCloseActiveEditor');

	// 		resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './empty.vsctestnb'));
	// 		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 		await vscode.commands.executeCommand('workbench.action.revertAndCloseActiveEditor');
	// 	}
	// });

R
rebornix 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123
	// test.only('crash', async function () {
	// 	for (let i = 0; i < 200; i++) {
	// 		let resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
	// 		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 		await vscode.commands.executeCommand('workbench.action.files.save');
	// 		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	// 		resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './empty.vsctestnb'));
	// 		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 		await vscode.commands.executeCommand('workbench.action.files.save');
	// 		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	// 	}
	// });

124
	test('document open/close event', async function () {
R
rebornix 已提交
125 126 127
		assertInitalState();

		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
128 129 130 131 132 133 134 135 136
		const firstDocumentOpen = getEventOncePromise(vscode.notebook.onDidOpenNotebookDocument);
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await firstDocumentOpen;

		const firstDocumentClose = getEventOncePromise(vscode.notebook.onDidCloseNotebookDocument);
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
		await firstDocumentClose;
	});

137
	test('notebook open/close, all cell-documents are ready', async function () {
J
Johannes Rieken 已提交
138
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
139

J
Johannes Rieken 已提交
140 141 142 143 144 145 146 147 148
		const p = getEventOncePromise(vscode.notebook.onDidOpenNotebookDocument).then(notebook => {
			for (let cell of notebook.cells) {
				const doc = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === cell.uri.toString());
				assert.ok(doc);
				assert.strictEqual(doc === cell.document, true);
				assert.strictEqual(doc?.languageId, cell.language);
				assert.strictEqual(doc?.isDirty, false);
				assert.strictEqual(doc?.isClosed, false);
			}
149 150 151 152 153 154 155
		});

		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await p;
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	});

156
	test('notebook open/close, notebook ready when cell-document open event is fired', async function () {
J
Johannes Rieken 已提交
157
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
		let didHappen = false;
		const p = getEventOncePromise(vscode.workspace.onDidOpenTextDocument).then(doc => {
			if (doc.uri.scheme !== 'vscode-notebook-cell') {
				return;
			}
			const notebook = vscode.notebook.notebookDocuments.find(notebook => {
				const cell = notebook.cells.find(cell => cell.document === doc);
				return Boolean(cell);
			});
			assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`);
			didHappen = true;
		});

		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await p;
		assert.strictEqual(didHappen, true);
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	});

177
	test('shared document in notebook editors', async function () {
R
rebornix 已提交
178 179 180
		assertInitalState();

		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
181 182 183 184 185 186 187 188 189 190 191
		let counter = 0;
		const disposables: vscode.Disposable[] = [];
		disposables.push(vscode.notebook.onDidOpenNotebookDocument(() => {
			counter++;
		}));
		disposables.push(vscode.notebook.onDidCloseNotebookDocument(() => {
			counter--;
		}));
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(counter, 1);

192
		await splitEditor();
193 194 195 196 197 198 199 200
		assert.equal(counter, 1);
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
		assert.equal(counter, 0);

		disposables.forEach(d => d.dispose());
	});

	test('editor open/close event', async function () {
R
rebornix 已提交
201 202 203
		assertInitalState();

		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
204 205 206 207 208 209 210 211 212
		const firstEditorOpen = getEventOncePromise(vscode.notebook.onDidChangeVisibleNotebookEditors);
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await firstEditorOpen;

		const firstEditorClose = getEventOncePromise(vscode.notebook.onDidChangeVisibleNotebookEditors);
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
		await firstEditorClose;
	});

213
	test('editor open/close event 2', async function () {
R
rebornix 已提交
214 215 216
		assertInitalState();

		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
217 218 219 220 221 222 223 224 225
		let count = 0;
		const disposables: vscode.Disposable[] = [];
		disposables.push(vscode.notebook.onDidChangeVisibleNotebookEditors(() => {
			count = vscode.notebook.visibleNotebookEditors.length;
		}));

		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(count, 1);

R
rebornix 已提交
226
		await splitEditor();
227 228 229 230 231 232
		assert.equal(count, 2);

		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
		assert.equal(count, 0);
	});

R
rebornix 已提交
233
	test('editor editing event 2', async function () {
R
rebornix 已提交
234 235 236
		assertInitalState();

		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
237 238 239 240 241 242 243 244 245 246
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const cellsChangeEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
		const cellChangeEventRet = await cellsChangeEvent;
		assert.equal(cellChangeEventRet.document, vscode.notebook.activeNotebookEditor?.document);
		assert.equal(cellChangeEventRet.changes.length, 1);
		assert.deepEqual(cellChangeEventRet.changes[0], {
			start: 1,
			deletedCount: 0,
R
:guard:  
rebornix 已提交
247
			deletedItems: [],
248 249 250 251 252
			items: [
				vscode.notebook.activeNotebookEditor!.document.cells[1]
			]
		});

R
:guard:  
rebornix 已提交
253 254
		const secondCell = vscode.notebook.activeNotebookEditor!.document.cells[1];

R
rebornix 已提交
255
		const moveCellEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
256 257 258 259
		await vscode.commands.executeCommand('notebook.cell.moveUp');
		const moveCellEventRet = await moveCellEvent;
		assert.deepEqual(moveCellEventRet, {
			document: vscode.notebook.activeNotebookEditor!.document,
260 261 262 263
			changes: [
				{
					start: 1,
					deletedCount: 1,
R
:guard:  
rebornix 已提交
264
					deletedItems: [secondCell],
265 266 267 268 269
					items: []
				},
				{
					start: 0,
					deletedCount: 0,
R
:guard:  
rebornix 已提交
270
					deletedItems: [],
271 272 273
					items: [vscode.notebook.activeNotebookEditor?.document.cells[0]]
				}
			]
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
		});

		const cellOutputChange = getEventOncePromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs);
		await vscode.commands.executeCommand('notebook.cell.execute');
		const cellOutputsAddedRet = await cellOutputChange;
		assert.deepEqual(cellOutputsAddedRet, {
			document: vscode.notebook.activeNotebookEditor!.document,
			cells: [vscode.notebook.activeNotebookEditor!.document.cells[0]]
		});
		assert.equal(cellOutputsAddedRet.cells[0].outputs.length, 1);

		const cellOutputClear = getEventOncePromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs);
		await vscode.commands.executeCommand('notebook.cell.clearOutputs');
		const cellOutputsCleardRet = await cellOutputClear;
		assert.deepEqual(cellOutputsCleardRet, {
			document: vscode.notebook.activeNotebookEditor!.document,
			cells: [vscode.notebook.activeNotebookEditor!.document.cells[0]]
		});
		assert.equal(cellOutputsAddedRet.cells[0].outputs.length, 0);

		// const cellChangeLanguage = getEventOncePromise<vscode.NotebookCellLanguageChangeEvent>(vscode.notebook.onDidChangeCellLanguage);
		// await vscode.commands.executeCommand('notebook.cell.changeToMarkdown');
		// const cellChangeLanguageRet = await cellChangeLanguage;
		// assert.deepEqual(cellChangeLanguageRet, {
		// 	document: vscode.notebook.activeNotebookEditor!.document,
		// 	cells: vscode.notebook.activeNotebookEditor!.document.cells[0],
		// 	language: 'markdown'
		// });

		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	});
R
rebornix 已提交
306

307
	test('editor move cell event', async function () {
R
rebornix 已提交
308 309
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
		await vscode.commands.executeCommand('notebook.focusTop');

		const activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);
		const moveChange = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells);
		await vscode.commands.executeCommand('notebook.cell.moveDown');
		const ret = await moveChange;
		assert.deepEqual(ret, {
			document: vscode.notebook.activeNotebookEditor?.document,
			changes: [
				{
					start: 0,
					deletedCount: 1,
R
:guard:  
rebornix 已提交
326
					deletedItems: [activeCell],
327 328 329 330 331
					items: []
				},
				{
					start: 1,
					deletedCount: 0,
R
:guard:  
rebornix 已提交
332
					deletedItems: [],
333 334 335 336
					items: [activeCell]
				}
			]
		});
337 338 339

		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
340 341 342 343 344 345 346

		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		const firstEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(firstEditor?.document.cells.length, 1);

		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
347 348
	});

349
	test('notebook editor active/visible', async function () {
R
rebornix 已提交
350 351
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
352 353 354
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		const firstEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(firstEditor?.active, true);
R
rebornix 已提交
355
		assert.equal(firstEditor?.visible, true);
R
rebornix 已提交
356

357
		await splitEditor();
R
rebornix 已提交
358 359
		const secondEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(secondEditor?.active, true);
R
rebornix 已提交
360
		assert.equal(secondEditor?.visible, true);
R
rebornix 已提交
361 362
		assert.equal(firstEditor?.active, false);

R
rebornix 已提交
363 364
		assert.equal(vscode.notebook.visibleNotebookEditors.length, 2);

365
		const untitledEditorChange = getEventOncePromise(vscode.notebook.onDidChangeActiveNotebookEditor);
R
rebornix 已提交
366
		await vscode.commands.executeCommand('workbench.action.files.newUntitledFile');
367
		await untitledEditorChange;
R
rebornix 已提交
368 369 370 371 372 373
		assert.equal(firstEditor?.visible, true);
		assert.equal(firstEditor?.active, false);
		assert.equal(secondEditor?.visible, false);
		assert.equal(secondEditor?.active, false);
		assert.equal(vscode.notebook.visibleNotebookEditors.length, 1);

374
		const activeEditorClose = getEventOncePromise(vscode.notebook.onDidChangeActiveNotebookEditor);
R
rebornix 已提交
375
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
376
		await activeEditorClose;
R
rebornix 已提交
377 378 379 380
		assert.equal(secondEditor?.active, true);
		assert.equal(secondEditor?.visible, true);
		assert.equal(vscode.notebook.visibleNotebookEditors.length, 2);

R
rebornix 已提交
381 382 383
		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	});
R
rebornix 已提交
384 385

	test('notebook active editor change', async function () {
R
rebornix 已提交
386 387
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
388 389 390 391 392 393 394 395
		const firstEditorOpen = getEventOncePromise(vscode.notebook.onDidChangeActiveNotebookEditor);
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await firstEditorOpen;

		const firstEditorDeactivate = getEventOncePromise(vscode.notebook.onDidChangeActiveNotebookEditor);
		await vscode.commands.executeCommand('workbench.action.splitEditor');
		await firstEditorDeactivate;

396
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
397
	});
398

399
	test('edit API (replaceCells)', async function () {
R
rebornix 已提交
400 401
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
402 403 404 405
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const cellsChangeEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
		await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
406
			editBuilder.replaceCells(1, 0, [{ cellKind: vscode.CellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]);
407 408 409
		});

		const cellChangeEventRet = await cellsChangeEvent;
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
		assert.strictEqual(cellChangeEventRet.document === vscode.notebook.activeNotebookEditor?.document, true);
		assert.strictEqual(cellChangeEventRet.document.isDirty, true);
		assert.strictEqual(cellChangeEventRet.changes.length, 1);
		assert.strictEqual(cellChangeEventRet.changes[0].start, 1);
		assert.strictEqual(cellChangeEventRet.changes[0].deletedCount, 0);
		assert.strictEqual(cellChangeEventRet.changes[0].items[0] === vscode.notebook.activeNotebookEditor!.document.cells[1], true);

		await saveAllFilesAndCloseAll(resource);
	});

	test('edit API (replaceOutput)', async function () {
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
426
			editBuilder.replaceCellOutput(0, [{ outputKind: vscode.CellOutputKind.Rich, data: { foo: 'bar' } }]);
427 428 429
		});

		const document = vscode.notebook.activeNotebookEditor?.document!;
430
		assert.strictEqual(document.isDirty, true);
431 432 433 434 435 436 437 438 439 440 441 442 443 444
		assert.strictEqual(document.cells.length, 1);
		assert.strictEqual(document.cells[0].outputs.length, 1);
		assert.strictEqual(document.cells[0].outputs[0].outputKind, vscode.CellOutputKind.Rich);

		await saveAllFilesAndCloseAll(undefined);
	});

	test('edit API (replaceOutput, event)', async function () {
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const outputChangeEvent = getEventOncePromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs);
		await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
445
			editBuilder.replaceCellOutput(0, [{ outputKind: vscode.CellOutputKind.Rich, data: { foo: 'bar' } }]);
446 447 448 449
		});

		const value = await outputChangeEvent;
		assert.strictEqual(value.document === vscode.notebook.activeNotebookEditor?.document, true);
450
		assert.strictEqual(value.document.isDirty, true);
451 452 453 454 455 456 457 458 459 460 461 462 463 464
		assert.strictEqual(value.cells.length, 1);
		assert.strictEqual(value.cells[0].outputs.length, 1);
		assert.strictEqual(value.cells[0].outputs[0].outputKind, vscode.CellOutputKind.Rich);

		await saveAllFilesAndCloseAll(undefined);
	});

	test('edit API (replaceMetadata)', async function () {

		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
465
			editBuilder.replaceCellMetadata(0, { inputCollapsed: true, executionOrder: 17 });
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
		});

		const document = vscode.notebook.activeNotebookEditor?.document!;
		assert.strictEqual(document.cells.length, 1);
		assert.strictEqual(document.cells[0].metadata.executionOrder, 17);
		assert.strictEqual(document.cells[0].metadata.inputCollapsed, true);

		assert.strictEqual(document.isDirty, true);
		await saveFileAndCloseAll(resource);
	});

	test('edit API (replaceMetadata, event)', async function () {

		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const event = getEventOncePromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebook.onDidChangeCellMetadata);

		await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
486
			editBuilder.replaceCellMetadata(0, { inputCollapsed: true, executionOrder: 17 });
487 488 489 490 491 492
		});

		const data = await event;
		assert.strictEqual(data.document, vscode.notebook.activeNotebookEditor?.document);
		assert.strictEqual(data.cell.metadata.executionOrder, 17);
		assert.strictEqual(data.cell.metadata.inputCollapsed, true);
493

494
		assert.strictEqual(data.document.isDirty, true);
R
rebornix 已提交
495
		await saveFileAndCloseAll(resource);
496
	});
497

498 499 500 501 502 503 504 505 506 507 508 509
	test('workspace edit API (replaceCells)', async function () {

		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const { document } = vscode.notebook.activeNotebookEditor!;
		assert.strictEqual(document.cells.length, 1);

		// inserting two new cells
		{
			const edit = new vscode.WorkspaceEdit();
510
			edit.replaceNotebookCells(document.uri, 0, 0, [{
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
				cellKind: vscode.CellKind.Markdown,
				language: 'markdown',
				metadata: undefined,
				outputs: [],
				source: 'new_markdown'
			}, {
				cellKind: vscode.CellKind.Code,
				language: 'fooLang',
				metadata: undefined,
				outputs: [],
				source: 'new_code'
			}]);

			const success = await vscode.workspace.applyEdit(edit);
			assert.strictEqual(success, true);
		}

		assert.strictEqual(document.cells.length, 3);
		assert.strictEqual(document.cells[0].document.getText(), 'new_markdown');
		assert.strictEqual(document.cells[1].document.getText(), 'new_code');

		// deleting cell 1 and 3
		{
			const edit = new vscode.WorkspaceEdit();
535 536
			edit.replaceNotebookCells(document.uri, 0, 1, []);
			edit.replaceNotebookCells(document.uri, 2, 3, []);
537 538 539 540 541 542 543 544 545 546
			const success = await vscode.workspace.applyEdit(edit);
			assert.strictEqual(success, true);
		}

		assert.strictEqual(document.cells.length, 1);
		assert.strictEqual(document.cells[0].document.getText(), 'new_code');

		// replacing all cells
		{
			const edit = new vscode.WorkspaceEdit();
547
			edit.replaceNotebookCells(document.uri, 0, 1, [{
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
				cellKind: vscode.CellKind.Markdown,
				language: 'markdown',
				metadata: undefined,
				outputs: [],
				source: 'new2_markdown'
			}, {
				cellKind: vscode.CellKind.Code,
				language: 'fooLang',
				metadata: undefined,
				outputs: [],
				source: 'new2_code'
			}]);
			const success = await vscode.workspace.applyEdit(edit);
			assert.strictEqual(success, true);
		}
		assert.strictEqual(document.cells.length, 2);
		assert.strictEqual(document.cells[0].document.getText(), 'new2_markdown');
		assert.strictEqual(document.cells[1].document.getText(), 'new2_code');

		// remove all cells
		{
			const edit = new vscode.WorkspaceEdit();
570
			edit.replaceNotebookCells(document.uri, 0, document.cells.length, []);
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
			const success = await vscode.workspace.applyEdit(edit);
			assert.strictEqual(success, true);
		}
		assert.strictEqual(document.cells.length, 0);

		await saveFileAndCloseAll(resource);
	});

	test('workspace edit API (replaceCells, event)', async function () {

		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const { document } = vscode.notebook.activeNotebookEditor!;
		assert.strictEqual(document.cells.length, 1);

		const edit = new vscode.WorkspaceEdit();
589
		edit.replaceNotebookCells(document.uri, 0, 0, [{
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
			cellKind: vscode.CellKind.Markdown,
			language: 'markdown',
			metadata: undefined,
			outputs: [],
			source: 'new_markdown'
		}, {
			cellKind: vscode.CellKind.Code,
			language: 'fooLang',
			metadata: undefined,
			outputs: [],
			source: 'new_code'
		}]);

		const event = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);

		const success = await vscode.workspace.applyEdit(edit);
		assert.strictEqual(success, true);

		const data = await event;

		// check document
		assert.strictEqual(document.cells.length, 3);
		assert.strictEqual(document.cells[0].document.getText(), 'new_markdown');
		assert.strictEqual(document.cells[1].document.getText(), 'new_code');

		// check event data
		assert.strictEqual(data.document === document, true);
		assert.strictEqual(data.changes.length, 1);
		assert.strictEqual(data.changes[0].deletedCount, 0);
		assert.strictEqual(data.changes[0].deletedItems.length, 0);
		assert.strictEqual(data.changes[0].items.length, 2);
		assert.strictEqual(data.changes[0].items[0], document.cells[0]);
		assert.strictEqual(data.changes[0].items[1], document.cells[1]);
		await saveFileAndCloseAll(resource);
	});

R
rebornix 已提交
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
	test('edit API batch edits', async function () {
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const cellsChangeEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
		const cellMetadataChangeEvent = getEventOncePromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebook.onDidChangeCellMetadata);
		const version = vscode.notebook.activeNotebookEditor!.document.version;
		await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
			editBuilder.replaceCells(1, 0, [{ cellKind: vscode.CellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]);
			editBuilder.replaceCellMetadata(0, { runnable: false });
		});

		await cellsChangeEvent;
		await cellMetadataChangeEvent;
		assert.strictEqual(version + 1, vscode.notebook.activeNotebookEditor!.document.version);
		await saveAllFilesAndCloseAll(resource);
	});

	test('edit API batch edits undo/redo', async function () {
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const cellsChangeEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
		const cellMetadataChangeEvent = getEventOncePromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebook.onDidChangeCellMetadata);
		const version = vscode.notebook.activeNotebookEditor!.document.version;
		await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
			editBuilder.replaceCells(1, 0, [{ cellKind: vscode.CellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]);
			editBuilder.replaceCellMetadata(0, { runnable: false });
		});

		await cellsChangeEvent;
		await cellMetadataChangeEvent;
		assert.strictEqual(vscode.notebook.activeNotebookEditor!.document.cells.length, 2);
		assert.strictEqual(vscode.notebook.activeNotebookEditor!.document.cells[0]?.metadata?.runnable, false);
		assert.strictEqual(version + 1, vscode.notebook.activeNotebookEditor!.document.version);

		await vscode.commands.executeCommand('undo');
		assert.strictEqual(version + 2, vscode.notebook.activeNotebookEditor!.document.version);
		assert.strictEqual(vscode.notebook.activeNotebookEditor!.document.cells[0]?.metadata?.runnable, undefined);
		assert.strictEqual(vscode.notebook.activeNotebookEditor!.document.cells.length, 1);

		await saveAllFilesAndCloseAll(resource);
	});

672
	test('initialzation should not emit cell change events.', async function () {
R
rebornix 已提交
673 674
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
675 676 677 678 679 680 681 682 683 684 685

		let count = 0;
		const disposables: vscode.Disposable[] = [];
		disposables.push(vscode.notebook.onDidChangeNotebookCells(() => {
			count++;
		}));

		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(count, 0);

		disposables.forEach(d => d.dispose());
R
rebornix 已提交
686 687

		await saveFileAndCloseAll(resource);
688
	});
689 690
});

R
rebornix 已提交
691 692
suite('notebook workflow', () => {
	test('notebook open', async function () {
R
rebornix 已提交
693 694
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
695
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
R
rebornix 已提交
696
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
697
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
R
rebornix 已提交
698 699
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

R
Rob Lourens 已提交
700
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
701
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
R
rebornix 已提交
702

R
Rob Lourens 已提交
703
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
704 705
		const activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.notEqual(vscode.notebook.activeNotebookEditor!.selection, undefined);
J
Johannes Rieken 已提交
706
		assert.equal(activeCell!.document.getText(), '');
R
rebornix 已提交
707 708 709 710 711 712 713 714
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 3);
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);

		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});

	test('notebook cell actions', async function () {
R
rebornix 已提交
715 716
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
717
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
R
rebornix 已提交
718
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
719
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
R
rebornix 已提交
720 721 722
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

		// ---- insert cell below and focus ---- //
R
Rob Lourens 已提交
723
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
724
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
R
rebornix 已提交
725 726

		// ---- insert cell above and focus ---- //
R
Rob Lourens 已提交
727
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
728 729
		let activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.notEqual(vscode.notebook.activeNotebookEditor!.selection, undefined);
J
Johannes Rieken 已提交
730
		assert.equal(activeCell!.document.getText(), '');
R
rebornix 已提交
731 732 733 734
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 3);
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);

		// ---- focus bottom ---- //
R
Rob Lourens 已提交
735
		await vscode.commands.executeCommand('notebook.focusBottom');
R
rebornix 已提交
736 737 738 739
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 2);

		// ---- focus top and then copy down ---- //
R
Rob Lourens 已提交
740
		await vscode.commands.executeCommand('notebook.focusTop');
R
rebornix 已提交
741 742 743
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);

R
Rob Lourens 已提交
744
		await vscode.commands.executeCommand('notebook.cell.copyDown');
R
rebornix 已提交
745 746
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
J
Johannes Rieken 已提交
747
		assert.equal(activeCell?.document.getText(), 'test');
R
rebornix 已提交
748

R
Rob Lourens 已提交
749
		await vscode.commands.executeCommand('notebook.cell.delete');
R
rebornix 已提交
750 751
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
J
Johannes Rieken 已提交
752
		assert.equal(activeCell?.document.getText(), '');
R
rebornix 已提交
753 754

		// ---- focus top and then copy up ---- //
R
Rob Lourens 已提交
755 756
		await vscode.commands.executeCommand('notebook.focusTop');
		await vscode.commands.executeCommand('notebook.cell.copyUp');
R
rebornix 已提交
757
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 4);
J
Johannes Rieken 已提交
758 759 760 761
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells[0].document.getText(), 'test');
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells[1].document.getText(), 'test');
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells[2].document.getText(), '');
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells[3].document.getText(), '');
R
rebornix 已提交
762 763 764 765 766 767
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);


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

R
Rob Lourens 已提交
768
		await vscode.commands.executeCommand('notebook.cell.moveDown');
769
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(vscode.notebook.activeNotebookEditor!.selection!), 1,
J
Johannes Rieken 已提交
770
			`first move down, active cell ${vscode.notebook.activeNotebookEditor!.selection!.uri.toString()}, ${vscode.notebook.activeNotebookEditor!.selection!.document.getText()}`);
771

R
rebornix 已提交
772 773 774 775
		// await vscode.commands.executeCommand('notebook.cell.moveDown');
		// activeCell = vscode.notebook.activeNotebookEditor!.selection;

		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 2,
J
Johannes Rieken 已提交
776 777 778 779 780
		// 	`second move down, active cell ${vscode.notebook.activeNotebookEditor!.selection!.uri.toString()}, ${vscode.notebook.activeNotebookEditor!.selection!.document.getText()}`);
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells[0].document.getText(), 'test');
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells[1].document.getText(), '');
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells[2].document.getText(), 'test');
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells[3].document.getText(), '');
R
rebornix 已提交
781 782 783

		// ---- ---- //

784
		await vscode.commands.executeCommand('workbench.action.files.save');
R
rebornix 已提交
785 786
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});
R
Rob Lourens 已提交
787

R
rebornix 已提交
788
	test('notebook join cells', async function () {
R
rebornix 已提交
789 790
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
791 792 793 794 795 796 797
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
R
rebornix 已提交
798 799 800
		const edit = new vscode.WorkspaceEdit();
		edit.insert(vscode.notebook.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;');
		await vscode.workspace.applyEdit(edit);
R
rebornix 已提交
801 802 803 804 805

		const cellsChangeEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
		await vscode.commands.executeCommand('notebook.cell.joinAbove');
		await cellsChangeEvent;

R
rebornix 已提交
806
		assert.deepEqual(vscode.notebook.activeNotebookEditor!.selection?.document.getText().split(/\r\n|\r|\n/), ['test', 'var abc = 0;']);
R
rebornix 已提交
807 808 809 810 811

		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});

812
	test('move cells will not recreate cells in ExtHost', async function () {
R
rebornix 已提交
813 814
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
815 816 817 818 819 820 821 822 823 824 825 826
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
		await vscode.commands.executeCommand('notebook.focusTop');

		const activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);
		await vscode.commands.executeCommand('notebook.cell.moveDown');
		await vscode.commands.executeCommand('notebook.cell.moveDown');

		const newActiveCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.deepEqual(activeCell, newActiveCell);
R
rebornix 已提交
827

R
rebornix 已提交
828
		await saveFileAndCloseAll(resource);
829 830
		// TODO@rebornix, there are still some events order issue.
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(newActiveCell!), 2);
831 832
	});

R
Rob Lourens 已提交
833
	// test.only('document metadata is respected', async function () {
R
rebornix 已提交
834
	// 	const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
Rob Lourens 已提交
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

	// 	assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
	// 	const editor = vscode.notebook.activeNotebookEditor!;

	// 	assert.equal(editor.document.cells.length, 1);
	// 	editor.document.metadata.editable = false;
	// 	await editor.edit(builder => builder.delete(0));
	// 	assert.equal(editor.document.cells.length, 1, 'should not delete cell'); // Not editable, no effect
	// 	await editor.edit(builder => builder.insert(0, 'test', 'python', vscode.CellKind.Code, [], undefined));
	// 	assert.equal(editor.document.cells.length, 1, 'should not insert cell'); // Not editable, no effect

	// 	editor.document.metadata.editable = true;
	// 	await editor.edit(builder => builder.delete(0));
	// 	assert.equal(editor.document.cells.length, 0, 'should delete cell'); // Editable, it worked
	// 	await editor.edit(builder => builder.insert(0, 'test', 'python', vscode.CellKind.Code, [], undefined));
	// 	assert.equal(editor.document.cells.length, 1, 'should insert cell'); // Editable, it worked

	// 	// await vscode.commands.executeCommand('workbench.action.files.save');
	// 	await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	// });

	test('cell runnable metadata is respected', async () => {
R
rebornix 已提交
858 859
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
Rob Lourens 已提交
860 861 862 863 864 865 866
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
		const editor = vscode.notebook.activeNotebookEditor!;

		await vscode.commands.executeCommand('notebook.focusTop');
		const cell = editor.document.cells[0];
		assert.equal(cell.outputs.length, 0);
R
rebornix 已提交
867 868

		let metadataChangeEvent = getEventOncePromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebook.onDidChangeCellMetadata);
R
Rob Lourens 已提交
869
		cell.metadata.runnable = false;
R
rebornix 已提交
870 871
		await metadataChangeEvent;

R
Rob Lourens 已提交
872 873 874
		await vscode.commands.executeCommand('notebook.cell.execute');
		assert.equal(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work

R
rebornix 已提交
875
		metadataChangeEvent = getEventOncePromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebook.onDidChangeCellMetadata);
R
Rob Lourens 已提交
876
		cell.metadata.runnable = true;
R
rebornix 已提交
877 878
		await metadataChangeEvent;

R
Rob Lourens 已提交
879 880 881
		await vscode.commands.executeCommand('notebook.cell.execute');
		assert.equal(cell.outputs.length, 1, 'should execute'); // runnable, it worked

882
		await vscode.commands.executeCommand('workbench.action.files.save');
R
Rob Lourens 已提交
883 884 885 886
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});

	test('document runnable metadata is respected', async () => {
R
rebornix 已提交
887 888
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
Rob Lourens 已提交
889 890 891 892 893 894
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
		const editor = vscode.notebook.activeNotebookEditor!;

		const cell = editor.document.cells[0];
		assert.equal(cell.outputs.length, 0);
895
		let metadataChangeEvent = getEventOncePromise<vscode.NotebookDocumentMetadataChangeEvent>(vscode.notebook.onDidChangeNotebookDocumentMetadata);
R
Rob Lourens 已提交
896
		editor.document.metadata.runnable = false;
897 898
		await metadataChangeEvent;

R
Rob Lourens 已提交
899 900 901
		await vscode.commands.executeCommand('notebook.execute');
		assert.equal(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work

902
		metadataChangeEvent = getEventOncePromise<vscode.NotebookDocumentMetadataChangeEvent>(vscode.notebook.onDidChangeNotebookDocumentMetadata);
R
Rob Lourens 已提交
903
		editor.document.metadata.runnable = true;
904 905
		await metadataChangeEvent;

R
Rob Lourens 已提交
906 907 908
		await vscode.commands.executeCommand('notebook.execute');
		assert.equal(cell.outputs.length, 1, 'should execute'); // runnable, it worked

909
		await vscode.commands.executeCommand('workbench.action.files.save');
R
Rob Lourens 已提交
910 911
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});
R
rebornix 已提交
912
});
R
rebornix 已提交
913 914 915

suite('notebook dirty state', () => {
	test('notebook open', async function () {
R
rebornix 已提交
916 917
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
918 919
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
920
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
R
rebornix 已提交
921 922 923
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
924
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
R
rebornix 已提交
925 926 927 928

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
		const activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.notEqual(vscode.notebook.activeNotebookEditor!.selection, undefined);
J
Johannes Rieken 已提交
929
		assert.equal(activeCell!.document.getText(), '');
R
rebornix 已提交
930 931 932
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 3);
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);

R
rebornix 已提交
933 934 935
		const edit = new vscode.WorkspaceEdit();
		edit.insert(activeCell!.uri, new vscode.Position(0, 0), 'var abc = 0;');
		await vscode.workspace.applyEdit(edit);
R
rebornix 已提交
936 937 938
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true);
		assert.equal(vscode.notebook.activeNotebookEditor?.selection !== undefined, true);
		assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells[1], vscode.notebook.activeNotebookEditor?.selection);
J
Johannes Rieken 已提交
939
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
R
rebornix 已提交
940

941
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
942 943 944 945
	});
});

suite('notebook undo redo', () => {
946
	test('notebook open', async function () {
R
rebornix 已提交
947 948
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
949 950
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
951
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
R
rebornix 已提交
952 953 954
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
955
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
R
rebornix 已提交
956 957 958 959

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
		const activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.notEqual(vscode.notebook.activeNotebookEditor!.selection, undefined);
J
Johannes Rieken 已提交
960
		assert.equal(activeCell!.document.getText(), '');
R
rebornix 已提交
961 962 963 964 965
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 3);
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);


		// modify the second cell, delete it
R
rebornix 已提交
966 967 968
		const edit = new vscode.WorkspaceEdit();
		edit.insert(vscode.notebook.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;');
		await vscode.workspace.applyEdit(edit);
R
rebornix 已提交
969 970 971 972 973 974
		await vscode.commands.executeCommand('notebook.cell.delete');
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 2);
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(vscode.notebook.activeNotebookEditor!.selection!), 1);


		// undo should bring back the deleted cell, and revert to previous content and selection
R
rebornix 已提交
975
		await vscode.commands.executeCommand('undo');
R
rebornix 已提交
976 977
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 3);
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(vscode.notebook.activeNotebookEditor!.selection!), 1);
J
Johannes Rieken 已提交
978
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
R
rebornix 已提交
979 980 981 982 983

		// redo
		// await vscode.commands.executeCommand('notebook.redo');
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 2);
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(vscode.notebook.activeNotebookEditor!.selection!), 1);
J
Johannes Rieken 已提交
984
		// assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'test');
R
rebornix 已提交
985

986
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
987
	});
988

R
rebornix 已提交
989
	test.skip('execute and then undo redo', async function () {
R
rebornix 已提交
990 991
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const cellsChangeEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
		const cellChangeEventRet = await cellsChangeEvent;
		assert.equal(cellChangeEventRet.document, vscode.notebook.activeNotebookEditor?.document);
		assert.equal(cellChangeEventRet.changes.length, 1);
		assert.deepEqual(cellChangeEventRet.changes[0], {
			start: 1,
			deletedCount: 0,
			deletedItems: [],
			items: [
				vscode.notebook.activeNotebookEditor!.document.cells[1]
			]
		});

		const secondCell = vscode.notebook.activeNotebookEditor!.document.cells[1];

		const moveCellEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
		await vscode.commands.executeCommand('notebook.cell.moveUp');
		const moveCellEventRet = await moveCellEvent;
		assert.deepEqual(moveCellEventRet, {
			document: vscode.notebook.activeNotebookEditor!.document,
			changes: [
				{
					start: 1,
					deletedCount: 1,
					deletedItems: [secondCell],
					items: []
				},
				{
					start: 0,
					deletedCount: 0,
					deletedItems: [],
					items: [vscode.notebook.activeNotebookEditor?.document.cells[0]]
				}
			]
		});

		const cellOutputChange = getEventOncePromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs);
		await vscode.commands.executeCommand('notebook.cell.execute');
		const cellOutputsAddedRet = await cellOutputChange;
		assert.deepEqual(cellOutputsAddedRet, {
			document: vscode.notebook.activeNotebookEditor!.document,
			cells: [vscode.notebook.activeNotebookEditor!.document.cells[0]]
		});
		assert.equal(cellOutputsAddedRet.cells[0].outputs.length, 1);

		const cellOutputClear = getEventOncePromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs);
R
rebornix 已提交
1041
		await vscode.commands.executeCommand('undo');
1042 1043 1044 1045 1046 1047 1048
		const cellOutputsCleardRet = await cellOutputClear;
		assert.deepEqual(cellOutputsCleardRet, {
			document: vscode.notebook.activeNotebookEditor!.document,
			cells: [vscode.notebook.activeNotebookEditor!.document.cells[0]]
		});
		assert.equal(cellOutputsAddedRet.cells[0].outputs.length, 0);

1049
		await saveFileAndCloseAll(resource);
1050 1051
	});

R
rebornix 已提交
1052
});
1053 1054

suite('notebook working copy', () => {
R
rebornix 已提交
1055
	// test('notebook revert on close', async function () {
R
rebornix 已提交
1056
	// 	const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
1057 1058 1059
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 	await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
	// 	assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
1060

R
rebornix 已提交
1061 1062
	// 	await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
	// 	await vscode.commands.executeCommand('default:type', { text: 'var abc = 0;' });
1063

R
rebornix 已提交
1064 1065 1066 1067 1068 1069 1070
	// 	// close active editor from command will revert the file
	// 	await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 	assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true);
	// 	assert.equal(vscode.notebook.activeNotebookEditor?.selection !== undefined, true);
	// 	assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells[0], vscode.notebook.activeNotebookEditor?.selection);
	// 	assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'test');
1071

R
rebornix 已提交
1072 1073 1074
	// 	await vscode.commands.executeCommand('workbench.action.files.save');
	// 	await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	// });
1075

R
rebornix 已提交
1076
	// test('notebook revert', async function () {
R
rebornix 已提交
1077
	// 	const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
1078 1079 1080
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 	await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
	// 	assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
1081

R
rebornix 已提交
1082 1083 1084
	// 	await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
	// 	await vscode.commands.executeCommand('default:type', { text: 'var abc = 0;' });
	// 	await vscode.commands.executeCommand('workbench.action.files.revert');
1085

R
rebornix 已提交
1086 1087 1088 1089 1090
	// 	assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true);
	// 	assert.equal(vscode.notebook.activeNotebookEditor?.selection !== undefined, true);
	// 	assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells[0], vscode.notebook.activeNotebookEditor?.selection);
	// 	assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells.length, 1);
	// 	assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'test');
1091

R
rebornix 已提交
1092 1093 1094
	// 	await vscode.commands.executeCommand('workbench.action.files.saveAll');
	// 	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	// });
1095 1096

	test('multiple tabs: dirty + clean', async function () {
R
rebornix 已提交
1097 1098
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
1099 1100
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
1101
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
1102 1103

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
1104 1105 1106
		const edit = new vscode.WorkspaceEdit();
		edit.insert(vscode.notebook.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;');
		await vscode.workspace.applyEdit(edit);
1107

R
rebornix 已提交
1108
		const secondResource = await createRandomFile('', undefined, 'second', '.vsctestnb');
1109 1110 1111 1112 1113 1114 1115 1116
		await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
		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
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true);
		assert.equal(vscode.notebook.activeNotebookEditor?.selection !== undefined, true);
		assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells[1], vscode.notebook.activeNotebookEditor?.selection);
		assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells.length, 3);
J
Johannes Rieken 已提交
1117
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
1118

1119
		await saveFileAndCloseAll(resource);
1120 1121 1122
	});

	test('multiple tabs: two dirty tabs and switching', async function () {
R
rebornix 已提交
1123 1124
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
1125 1126
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
1127
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
1128 1129

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
1130 1131 1132
		const edit = new vscode.WorkspaceEdit();
		edit.insert(vscode.notebook.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;');
		await vscode.workspace.applyEdit(edit);
1133

R
rebornix 已提交
1134
		const secondResource = await createRandomFile('', undefined, 'second', '.vsctestnb');
1135 1136
		await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
1137
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
1138 1139 1140 1141 1142 1143 1144

		// switch to the first editor
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true);
		assert.equal(vscode.notebook.activeNotebookEditor?.selection !== undefined, true);
		assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells[1], vscode.notebook.activeNotebookEditor?.selection);
		assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells.length, 3);
J
Johannes Rieken 已提交
1145
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
1146 1147 1148 1149 1150 1151 1152

		// switch to the second editor
		await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true);
		assert.equal(vscode.notebook.activeNotebookEditor?.selection !== undefined, true);
		assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells[1], vscode.notebook.activeNotebookEditor?.selection);
		assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells.length, 2);
J
Johannes Rieken 已提交
1153
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), '');
1154

1155 1156 1157
		await saveAllFilesAndCloseAll(secondResource);
		// await vscode.commands.executeCommand('workbench.action.files.saveAll');
		// await vscode.commands.executeCommand('workbench.action.closeAllEditors');
1158 1159 1160
	});

	test('multiple tabs: different editors with same document', async function () {
R
rebornix 已提交
1161
		assertInitalState();
1162

R
rebornix 已提交
1163
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
1164 1165 1166
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		const firstNotebookEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(firstNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
1167
		assert.equal(firstNotebookEditor!.selection?.document.getText(), 'test');
1168 1169
		assert.equal(firstNotebookEditor!.selection?.language, 'typescript');

1170
		await splitEditor();
1171 1172
		const secondNotebookEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(secondNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
1173
		assert.equal(secondNotebookEditor!.selection?.document.getText(), 'test');
1174 1175 1176 1177
		assert.equal(secondNotebookEditor!.selection?.language, 'typescript');

		assert.notEqual(firstNotebookEditor, secondNotebookEditor);
		assert.equal(firstNotebookEditor?.document, secondNotebookEditor?.document, 'split notebook editors share the same document');
R
rebornix 已提交
1178
		assert.notEqual(firstNotebookEditor?.asWebviewUri(vscode.Uri.file('./hello.png')), secondNotebookEditor?.asWebviewUri(vscode.Uri.file('./hello.png')));
1179

1180 1181 1182 1183
		await saveAllFilesAndCloseAll(resource);

		// await vscode.commands.executeCommand('workbench.action.files.saveAll');
		// await vscode.commands.executeCommand('workbench.action.closeAllEditors');
1184
	});
1185
});
1186

R
rebornix 已提交
1187 1188
suite('metadata', () => {
	test('custom metadata should be supported', async function () {
R
rebornix 已提交
1189 1190
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
1191 1192
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
1193
		assert.equal(vscode.notebook.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false);
R
rebornix 已提交
1194
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.metadata.custom!['testCellMetadata'] as number, 123);
R
rebornix 已提交
1195
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');
1196

1197
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
1198
	});
1199

1200

R
rebornix 已提交
1201
	// TODO@rebornix skip as it crashes the process all the time
1202
	test.skip('custom metadata should be supported 2', async function () {
R
rebornix 已提交
1203 1204
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
1205 1206 1207 1208 1209 1210
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
		assert.equal(vscode.notebook.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false);
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.metadata.custom!['testCellMetadata'] as number, 123);
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

1211 1212 1213 1214 1215
		// TODO see #101462
		// await vscode.commands.executeCommand('notebook.cell.copyDown');
		// const activeCell = vscode.notebook.activeNotebookEditor!.selection;
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
		// assert.equal(activeCell?.metadata.custom!['testCellMetadata'] as number, 123);
1216

1217
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
1218
	});
R
rebornix 已提交
1219 1220
});

1221
suite('regression', () => {
R
rebornix 已提交
1222 1223 1224 1225 1226 1227 1228 1229
	// test('microsoft/vscode-github-issue-notebooks#26. Insert template cell in the new empty document', async function () {
	// 	assertInitalState();
	// 	await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { "viewType": "notebookCoreTest" });
	// 	assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
	// 	assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
	// 	assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');
	// 	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	// });
1230

1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
	test('#106657. Opening a notebook from markers view is broken ', async function () {
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const document = vscode.notebook.activeNotebookEditor?.document!;
		const [cell] = document.cells;

		await saveAllFilesAndCloseAll(document.uri);
		assert.strictEqual(vscode.notebook.activeNotebookEditor, undefined);

		// opening a cell-uri opens a notebook editor
1243
		await vscode.commands.executeCommand('vscode.open', cell.uri, vscode.ViewColumn.Active);
1244 1245

		assert.strictEqual(!!vscode.notebook.activeNotebookEditor, true);
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
		assert.strictEqual(vscode.notebook.activeNotebookEditor?.document.uri.toString(), resource.toString());
	});

	test('Cannot open notebook from cell-uri with vscode.open-command', async function () {
		this.skip();
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const document = vscode.notebook.activeNotebookEditor?.document!;
		const [cell] = document.cells;

		await saveAllFilesAndCloseAll(document.uri);
		assert.strictEqual(vscode.notebook.activeNotebookEditor, undefined);

		// 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...
		await vscode.commands.executeCommand('vscode.open', cell.uri);

		assert.strictEqual(vscode.notebook.activeNotebookEditor?.document.uri.toString(), resource.toString());
1266 1267
	});

1268
	test('#97830, #97764. Support switch to other editor types', async function () {
R
rebornix 已提交
1269 1270
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'empty', '.vsctestnb');
1271 1272
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
R
rebornix 已提交
1273 1274 1275
		const edit = new vscode.WorkspaceEdit();
		edit.insert(vscode.notebook.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;');
		await vscode.workspace.applyEdit(edit);
1276 1277

		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
1278
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'var abc = 0;');
1279 1280 1281 1282 1283 1284 1285
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

		await vscode.commands.executeCommand('vscode.openWith', resource, 'default');
		assert.equal(vscode.window.activeTextEditor?.document.uri.path, resource.path);

		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	});
1286 1287 1288

	// open text editor, pin, and then open a notebook
	test('#96105 - dirty editors', async function () {
R
rebornix 已提交
1289 1290
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'empty', '.vsctestnb');
1291
		await vscode.commands.executeCommand('vscode.openWith', resource, 'default');
R
rebornix 已提交
1292
		const edit = new vscode.WorkspaceEdit();
R
rebornix 已提交
1293
		edit.insert(resource, new vscode.Position(0, 0), 'var abc = 0;');
R
rebornix 已提交
1294
		await vscode.workspace.applyEdit(edit);
1295 1296 1297 1298

		// now it's dirty, open the resource with notebook editor should open a new one
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.notEqual(vscode.notebook.activeNotebookEditor, undefined, 'notebook first');
R
rebornix 已提交
1299
		// assert.notEqual(vscode.window.activeTextEditor, undefined);
1300 1301 1302 1303

		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	});

R
rebornix 已提交
1304
	test('#102411 - untitled notebook creation failed', async function () {
R
rebornix 已提交
1305
		assertInitalState();
J
Johannes Rieken 已提交
1306
		await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: 'notebookCoreTest' });
R
rebornix 已提交
1307
		assert.notEqual(vscode.notebook.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined');
1308 1309

		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
R
rebornix 已提交
1310
	});
R
rebornix 已提交
1311 1312

	test('#102423 - copy/paste shares the same text buffer', async function () {
R
rebornix 已提交
1313 1314
		assertInitalState();
		const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
R
rebornix 已提交
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		let activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(activeCell?.document.getText(), 'test');

		await vscode.commands.executeCommand('notebook.cell.copyDown');
		await vscode.commands.executeCommand('notebook.cell.edit');
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
		assert.equal(activeCell?.document.getText(), 'test');

R
rebornix 已提交
1326 1327 1328
		const edit = new vscode.WorkspaceEdit();
		edit.insert(vscode.notebook.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;');
		await vscode.workspace.applyEdit(edit);
R
rebornix 已提交
1329 1330

		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 2);
J
Johannes Rieken 已提交
1331
		assert.notEqual(vscode.notebook.activeNotebookEditor!.document.cells[0].document.getText(), vscode.notebook.activeNotebookEditor!.document.cells[1].document.getText());
1332 1333

		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
R
rebornix 已提交
1334
	});
1335
});
R
rebornix 已提交
1336

R
rebornix 已提交
1337
suite('webview', () => {
R
rebornix 已提交
1338
	// for web, `asWebUri` gets `https`?
1339 1340 1341 1342
	// test('asWebviewUri', async function () {
	// 	if (vscode.env.uiKind === vscode.UIKind.Web) {
	// 		return;
	// 	}
R
rebornix 已提交
1343

R
rebornix 已提交
1344
	// 	const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
1345 1346 1347
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 	assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
	// 	const uri = vscode.notebook.activeNotebookEditor!.asWebviewUri(vscode.Uri.file('./hello.png'));
1348
	// 	assert.equal(uri.scheme, 'vscode-webview-resource');
1349 1350
	// 	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	// });
R
rebornix 已提交
1351

R
rebornix 已提交
1352 1353

	// 404 on web
1354 1355 1356 1357
	// test('custom renderer message', async function () {
	// 	if (vscode.env.uiKind === vscode.UIKind.Web) {
	// 		return;
	// 	}
R
rebornix 已提交
1358

1359 1360
	// 	const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './customRenderer.vsctestnb'));
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
R
rebornix 已提交
1361

1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
	// 	const editor = vscode.notebook.activeNotebookEditor;
	// 	const promise = new Promise(resolve => {
	// 		const messageEmitter = editor?.onDidReceiveMessage(e => {
	// 			if (e.type === 'custom_renderer_initialize') {
	// 				resolve();
	// 				messageEmitter?.dispose();
	// 			}
	// 		});
	// 	});

	// 	await vscode.commands.executeCommand('notebook.cell.execute');
	// 	await promise;
	// 	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	// });
R
rebornix 已提交
1376
});