notebook.test.ts 50.1 KB
Newer Older
R
rebornix 已提交
1 2 3 4 5 6 7 8 9 10
/*---------------------------------------------------------------------------------------------
 *  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';
import { join } from 'path';

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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
async function saveAllFilesAndCloseAll(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.saveAll');
	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	await documentClosed;
}

function assertInitalState() {
	if (vscode.notebook.activeNotebookEditor !== undefined) {
		return false;
	}

	if (vscode.notebook.notebookDocuments.length !== 0) {
		return false;
	}

	if (vscode.notebook.visibleNotebookEditors.length !== 0) {
		return false;
	}

	return true;
}

R
rebornix 已提交
103
suite('Notebook API tests', () => {
R
rebornix 已提交
104 105 106 107 108 109 110 111 112 113 114 115
	// 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 已提交
116 117 118 119 120 121 122 123 124 125 126 127 128
	// 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');
	// 	}
	// });

129
	test('document open/close event', async function () {
130 131 132
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
133
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
134 135 136 137 138 139 140 141 142 143
		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;
	});

	test('shared document in notebook editors', async function () {
144 145 146
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
147
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
148 149 150 151 152 153 154 155 156 157 158
		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);

159
		await splitEditor();
160 161 162 163 164 165 166 167
		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 () {
168 169 170
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
171
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
172 173 174 175 176 177 178 179 180
		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;
	});

181
	test('editor open/close event 2', async function () {
182 183 184
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
185
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
186 187 188 189 190 191 192 193 194
		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 已提交
195
		await splitEditor();
196 197 198 199 200 201
		assert.equal(count, 2);

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

R
rebornix 已提交
202
	test('editor editing event 2', async function () {
203 204 205
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
206
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
207 208 209 210 211 212 213 214 215 216
		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 已提交
217
			deletedItems: [],
218 219 220 221 222
			items: [
				vscode.notebook.activeNotebookEditor!.document.cells[1]
			]
		});

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

R
rebornix 已提交
225
		const moveCellEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
226 227 228 229
		await vscode.commands.executeCommand('notebook.cell.moveUp');
		const moveCellEventRet = await moveCellEvent;
		assert.deepEqual(moveCellEventRet, {
			document: vscode.notebook.activeNotebookEditor!.document,
230 231 232 233
			changes: [
				{
					start: 1,
					deletedCount: 1,
R
:guard:  
rebornix 已提交
234
					deletedItems: [secondCell],
235 236 237 238 239
					items: []
				},
				{
					start: 0,
					deletedCount: 0,
R
:guard:  
rebornix 已提交
240
					deletedItems: [],
241 242 243
					items: [vscode.notebook.activeNotebookEditor?.document.cells[0]]
				}
			]
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
		});

		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 已提交
276

277
	test('editor move cell event', async function () {
278 279 280
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
281
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
		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 已提交
298
					deletedItems: [activeCell],
299 300 301 302 303
					items: []
				},
				{
					start: 1,
					deletedCount: 0,
R
:guard:  
rebornix 已提交
304
					deletedItems: [],
305 306 307 308
					items: [activeCell]
				}
			]
		});
309 310 311

		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
312 313 314 315 316 317 318

		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');
319 320
	});

321
	test('notebook editor active/visible', async function () {
322 323 324
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
325
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
rebornix 已提交
326 327 328
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		const firstEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(firstEditor?.active, true);
R
rebornix 已提交
329
		assert.equal(firstEditor?.visible, true);
R
rebornix 已提交
330

331
		await splitEditor();
R
rebornix 已提交
332 333
		const secondEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(secondEditor?.active, true);
R
rebornix 已提交
334
		assert.equal(secondEditor?.visible, true);
R
rebornix 已提交
335 336
		assert.equal(firstEditor?.active, false);

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

339
		const untitledEditorChange = getEventOncePromise(vscode.notebook.onDidChangeActiveNotebookEditor);
R
rebornix 已提交
340
		await vscode.commands.executeCommand('workbench.action.files.newUntitledFile');
341
		await untitledEditorChange;
R
rebornix 已提交
342 343 344 345 346 347
		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);

348
		const activeEditorClose = getEventOncePromise(vscode.notebook.onDidChangeActiveNotebookEditor);
R
rebornix 已提交
349
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
350
		await activeEditorClose;
R
rebornix 已提交
351 352 353 354
		assert.equal(secondEditor?.active, true);
		assert.equal(secondEditor?.visible, true);
		assert.equal(vscode.notebook.visibleNotebookEditors.length, 2);

R
rebornix 已提交
355 356 357
		await vscode.commands.executeCommand('workbench.action.files.save');
		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	});
R
rebornix 已提交
358 359

	test('notebook active editor change', async function () {
360 361 362
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
363
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
rebornix 已提交
364 365 366 367 368 369 370 371
		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;

372
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
373
	});
374 375

	test('edit API', async function () {
376 377 378
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
379
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
380 381 382 383 384 385 386 387 388 389 390 391 392 393
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');

		const cellsChangeEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
		await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
			editBuilder.insert(1, 'test 2', 'javascript', vscode.CellKind.Code, [], undefined);
		});

		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);
		assert.deepEqual(cellChangeEventRet.changes[0].deletedCount, 0);
		assert.equal(cellChangeEventRet.changes[0].items[0], vscode.notebook.activeNotebookEditor!.document.cells[1]);

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

	test('initialzation should not emit cell change events.', async function () {
398 399 400
		if (!assertInitalState()) {
			return;
		}
401 402 403 404 405 406 407 408 409 410 411 412
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));

		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 已提交
413 414

		await saveFileAndCloseAll(resource);
415
	});
416 417
});

R
rebornix 已提交
418 419
suite('notebook workflow', () => {
	test('notebook open', async function () {
420 421 422
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
423
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
rebornix 已提交
424
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
R
rebornix 已提交
425
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
426
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
R
rebornix 已提交
427 428
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

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

R
Rob Lourens 已提交
432
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
433 434
		const activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.notEqual(vscode.notebook.activeNotebookEditor!.selection, undefined);
J
Johannes Rieken 已提交
435
		assert.equal(activeCell!.document.getText(), '');
R
rebornix 已提交
436 437 438 439 440 441 442 443
		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 () {
444 445 446
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
447
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
rebornix 已提交
448
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
R
rebornix 已提交
449
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
450
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
R
rebornix 已提交
451 452 453
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

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

		// ---- insert cell above and focus ---- //
R
Rob Lourens 已提交
458
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
459 460
		let activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.notEqual(vscode.notebook.activeNotebookEditor!.selection, undefined);
J
Johannes Rieken 已提交
461
		assert.equal(activeCell!.document.getText(), '');
R
rebornix 已提交
462 463 464 465
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 3);
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);

		// ---- focus bottom ---- //
R
Rob Lourens 已提交
466
		await vscode.commands.executeCommand('notebook.focusBottom');
R
rebornix 已提交
467 468 469 470
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 2);

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

R
Rob Lourens 已提交
475
		await vscode.commands.executeCommand('notebook.cell.copyDown');
R
rebornix 已提交
476 477
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
J
Johannes Rieken 已提交
478
		assert.equal(activeCell?.document.getText(), 'test');
R
rebornix 已提交
479

R
Rob Lourens 已提交
480
		await vscode.commands.executeCommand('notebook.cell.delete');
R
rebornix 已提交
481 482
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
J
Johannes Rieken 已提交
483
		assert.equal(activeCell?.document.getText(), '');
R
rebornix 已提交
484 485

		// ---- focus top and then copy up ---- //
R
Rob Lourens 已提交
486 487
		await vscode.commands.executeCommand('notebook.focusTop');
		await vscode.commands.executeCommand('notebook.cell.copyUp');
R
rebornix 已提交
488
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 4);
J
Johannes Rieken 已提交
489 490 491 492
		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 已提交
493 494 495 496 497 498
		activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);


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

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

R
rebornix 已提交
503 504 505 506
		// 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 已提交
507 508 509 510 511
		// 	`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 已提交
512 513 514

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

515
		await vscode.commands.executeCommand('workbench.action.files.save');
R
rebornix 已提交
516 517
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});
R
Rob Lourens 已提交
518

R
rebornix 已提交
519
	test('notebook join cells', async function () {
520 521 522
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
523 524 525 526 527 528 529 530
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
		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 已提交
531 532 533
		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 已提交
534 535 536 537 538

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

R
rebornix 已提交
539
		assert.deepEqual(vscode.notebook.activeNotebookEditor!.selection?.document.getText().split(/\r\n|\r|\n/), ['test', 'var abc = 0;']);
R
rebornix 已提交
540 541 542 543 544

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

545
	test('move cells will not recreate cells in ExtHost', async function () {
546 547 548
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
549
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
550 551 552 553 554 555 556 557 558 559 560 561
		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 已提交
562

R
rebornix 已提交
563
		await saveFileAndCloseAll(resource);
564 565
		// TODO@rebornix, there are still some events order issue.
		// assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(newActiveCell!), 2);
566 567
	});

R
Rob Lourens 已提交
568
	// test.only('document metadata is respected', async function () {
R
rebornix 已提交
569
	// 	const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
Rob Lourens 已提交
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
	// 	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 () => {
593 594 595
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
596
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
Rob Lourens 已提交
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
		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);
		cell.metadata.runnable = false;
		await vscode.commands.executeCommand('notebook.cell.execute');
		assert.equal(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work

		cell.metadata.runnable = true;
		await vscode.commands.executeCommand('notebook.cell.execute');
		assert.equal(cell.outputs.length, 1, 'should execute'); // runnable, it worked

612
		await vscode.commands.executeCommand('workbench.action.files.save');
R
Rob Lourens 已提交
613 614 615 616
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});

	test('document runnable metadata is respected', async () => {
617 618 619
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
620
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
Rob Lourens 已提交
621 622 623 624 625 626 627 628 629 630 631 632 633 634
		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);
		editor.document.metadata.runnable = false;
		await vscode.commands.executeCommand('notebook.execute');
		assert.equal(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work

		editor.document.metadata.runnable = true;
		await vscode.commands.executeCommand('notebook.execute');
		assert.equal(cell.outputs.length, 1, 'should execute'); // runnable, it worked

635
		await vscode.commands.executeCommand('workbench.action.files.save');
R
Rob Lourens 已提交
636 637
		await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	});
R
rebornix 已提交
638
});
R
rebornix 已提交
639 640 641

suite('notebook dirty state', () => {
	test('notebook open', async function () {
642 643 644
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
645
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
rebornix 已提交
646 647
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
648
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
R
rebornix 已提交
649 650 651
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
652
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
R
rebornix 已提交
653 654 655 656

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

R
rebornix 已提交
661 662 663
		const edit = new vscode.WorkspaceEdit();
		edit.insert(activeCell!.uri, new vscode.Position(0, 0), 'var abc = 0;');
		await vscode.workspace.applyEdit(edit);
R
rebornix 已提交
664 665 666
		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 已提交
667
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
R
rebornix 已提交
668

669
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
670 671 672 673
	});
});

suite('notebook undo redo', () => {
674
	test('notebook open', async function () {
675 676 677
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
678
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
rebornix 已提交
679 680
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
681
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'test');
R
rebornix 已提交
682 683 684
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
685
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
R
rebornix 已提交
686 687 688 689

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
		const activeCell = vscode.notebook.activeNotebookEditor!.selection;
		assert.notEqual(vscode.notebook.activeNotebookEditor!.selection, undefined);
J
Johannes Rieken 已提交
690
		assert.equal(activeCell!.document.getText(), '');
R
rebornix 已提交
691 692 693 694 695
		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 已提交
696 697 698
		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 已提交
699 700 701 702 703 704 705 706 707
		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
		await vscode.commands.executeCommand('notebook.undo');
		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 已提交
708
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
R
rebornix 已提交
709 710 711 712 713

		// 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 已提交
714
		// assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'test');
R
rebornix 已提交
715

716
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
717
	});
718

R
rebornix 已提交
719
	test.skip('execute and then undo redo', async function () {
720 721 722
		if (!assertInitalState()) {
			return;
		}
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
		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);
		await vscode.commands.executeCommand('notebook.undo');
		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);

781
		await saveFileAndCloseAll(resource);
782 783
	});

R
rebornix 已提交
784
});
785 786

suite('notebook working copy', () => {
R
rebornix 已提交
787 788 789 790 791
	// test('notebook revert on close', async function () {
	// 	const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 	await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
	// 	assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
792

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

R
rebornix 已提交
796 797 798 799 800 801 802
	// 	// 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');
803

R
rebornix 已提交
804 805 806
	// 	await vscode.commands.executeCommand('workbench.action.files.save');
	// 	await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
	// });
807

R
rebornix 已提交
808 809 810 811 812
	// test('notebook revert', async function () {
	// 	const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
	// 	await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
	// 	await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
	// 	assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
813

R
rebornix 已提交
814 815 816
	// 	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');
817

R
rebornix 已提交
818 819 820 821 822
	// 	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');
823

R
rebornix 已提交
824 825 826
	// 	await vscode.commands.executeCommand('workbench.action.files.saveAll');
	// 	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	// });
827 828

	test('multiple tabs: dirty + clean', async function () {
829 830 831
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
832
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
833 834
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
835
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
836 837

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
838 839 840
		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);
841

R
rebornix 已提交
842
		const secondResource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './second.vsctestnb'));
843 844 845 846 847 848 849 850
		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 已提交
851
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
852

853
		await saveFileAndCloseAll(resource);
854 855 856
	});

	test('multiple tabs: two dirty tabs and switching', async function () {
857 858 859
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
860
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
861 862
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
863
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
864 865

		await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
R
rebornix 已提交
866 867 868
		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);
869

R
rebornix 已提交
870
		const secondResource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './second.vsctestnb'));
871 872
		await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
J
Johannes Rieken 已提交
873
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
874 875 876 877 878 879 880

		// 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 已提交
881
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
882 883 884 885 886 887 888

		// 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 已提交
889
		assert.equal(vscode.notebook.activeNotebookEditor?.selection?.document.getText(), '');
890

891 892 893
		await saveAllFilesAndCloseAll(secondResource);
		// await vscode.commands.executeCommand('workbench.action.files.saveAll');
		// await vscode.commands.executeCommand('workbench.action.closeAllEditors');
894 895 896
	});

	test('multiple tabs: different editors with same document', async function () {
897 898 899
		if (!assertInitalState()) {
			return;
		}
900

R
rebornix 已提交
901
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
902 903 904
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		const firstNotebookEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(firstNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
905
		assert.equal(firstNotebookEditor!.selection?.document.getText(), 'test');
906 907
		assert.equal(firstNotebookEditor!.selection?.language, 'typescript');

908
		await splitEditor();
909 910
		const secondNotebookEditor = vscode.notebook.activeNotebookEditor;
		assert.equal(secondNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
911
		assert.equal(secondNotebookEditor!.selection?.document.getText(), 'test');
912 913 914 915
		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 已提交
916
		assert.notEqual(firstNotebookEditor?.asWebviewUri(vscode.Uri.file('./hello.png')), secondNotebookEditor?.asWebviewUri(vscode.Uri.file('./hello.png')));
917

918 919 920 921
		await saveAllFilesAndCloseAll(resource);

		// await vscode.commands.executeCommand('workbench.action.files.saveAll');
		// await vscode.commands.executeCommand('workbench.action.closeAllEditors');
922
	});
923
});
924

R
rebornix 已提交
925 926
suite('metadata', () => {
	test('custom metadata should be supported', async function () {
927 928 929
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
930
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
R
rebornix 已提交
931 932
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
933
		assert.equal(vscode.notebook.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false);
R
rebornix 已提交
934
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.metadata.custom!['testCellMetadata'] as number, 123);
R
rebornix 已提交
935
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');
936

937
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
938
	});
939

940

R
rebornix 已提交
941
	// TODO@rebornix skip as it crashes the process all the time
942 943 944 945
	test.skip('custom metadata should be supported 2', async function () {
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
946
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
947 948 949 950 951 952
		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');

953 954 955 956 957
		// 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);
958

959
		await saveFileAndCloseAll(resource);
R
rebornix 已提交
960
	});
R
rebornix 已提交
961 962
});

963 964
suite('regression', () => {
	test('microsoft/vscode-github-issue-notebooks#26. Insert template cell in the new empty document', async function () {
965 966 967
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
968
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './empty.vsctestnb'));
969 970
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
971
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), '');
972
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');
973
		await saveFileAndCloseAll(resource);
974
	});
975 976

	test('#97830, #97764. Support switch to other editor types', async function () {
977 978 979
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
980
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './empty.vsctestnb'));
981 982
		await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
		await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
R
rebornix 已提交
983 984 985
		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);
986 987

		assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
J
Johannes Rieken 已提交
988
		assert.equal(vscode.notebook.activeNotebookEditor!.selection?.document.getText(), 'var abc = 0;');
989 990 991 992 993 994 995
		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');
	});
996 997 998

	// open text editor, pin, and then open a notebook
	test('#96105 - dirty editors', async function () {
999 1000 1001
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
1002
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './empty.vsctestnb'));
1003
		await vscode.commands.executeCommand('vscode.openWith', resource, 'default');
R
rebornix 已提交
1004
		const edit = new vscode.WorkspaceEdit();
R
rebornix 已提交
1005
		edit.insert(resource, new vscode.Position(0, 0), 'var abc = 0;');
R
rebornix 已提交
1006
		await vscode.workspace.applyEdit(edit);
1007 1008 1009 1010 1011 1012 1013 1014 1015

		// 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');
		assert.notEqual(vscode.window.activeTextEditor, undefined);

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

R
rebornix 已提交
1016
	test('#102411 - untitled notebook creation failed', async function () {
1017 1018 1019
		if (!assertInitalState()) {
			return;
		}
J
Johannes Rieken 已提交
1020
		await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: 'notebookCoreTest' });
R
rebornix 已提交
1021
		assert.notEqual(vscode.notebook.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined');
1022 1023

		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
R
rebornix 已提交
1024
	});
R
rebornix 已提交
1025 1026

	test('#102423 - copy/paste shares the same text buffer', async function () {
1027 1028 1029
		if (!assertInitalState()) {
			return;
		}
R
rebornix 已提交
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
		const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
		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 已提交
1042 1043 1044
		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 已提交
1045 1046

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

		await vscode.commands.executeCommand('workbench.action.closeAllEditors');
R
rebornix 已提交
1050
	});
1051
});
R
rebornix 已提交
1052

R
rebornix 已提交
1053
suite('webview', () => {
R
rebornix 已提交
1054
	// for web, `asWebUri` gets `https`?
1055 1056 1057 1058
	// test('asWebviewUri', async function () {
	// 	if (vscode.env.uiKind === vscode.UIKind.Web) {
	// 		return;
	// 	}
R
rebornix 已提交
1059

1060 1061 1062 1063
	// 	const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
	// 	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'));
1064
	// 	assert.equal(uri.scheme, 'vscode-webview-resource');
1065 1066
	// 	await vscode.commands.executeCommand('workbench.action.closeAllEditors');
	// });
R
rebornix 已提交
1067

R
rebornix 已提交
1068 1069

	// 404 on web
1070 1071 1072 1073
	// test('custom renderer message', async function () {
	// 	if (vscode.env.uiKind === vscode.UIKind.Web) {
	// 		return;
	// 	}
R
rebornix 已提交
1074

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

1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
	// 	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 已提交
1092
});