diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 45144e66c97..8d64db9d651 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -12,44 +12,14 @@ async function createRandomNotebookFile() { return createRandomFile('', undefined, '.vsctestnb'); } -// 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 = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); - await vscode.commands.executeCommand('workbench.action.splitEditor'); - await once; +async function openRandomNotebookDocument() { + const uri = await createRandomNotebookFile(); + return vscode.notebook.openNotebookDocument(uri); } -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'); +async function saveAllFilesAndCloseAll() { + await saveAllEditors(); await closeAllEditors(); - await documentClosed; -} - -async function saveAllFilesAndCloseAll(resource: vscode.Uri | undefined) { - const documentClosed = new Promise((resolve, _reject) => { - if (!resource) { - return resolve(); - } - const d = vscode.notebook.onDidCloseNotebookDocument(e => { - if (e.uri.toString() === resource.toString()) { - d.dispose(); - resolve(); - } - }); - }); - await vscode.commands.executeCommand('workbench.action.files.saveAll'); - await closeAllEditors(); - await documentClosed; } async function withEvent(event: vscode.Event, callback: (e: Promise) => Promise) { @@ -178,7 +148,7 @@ suite('Notebook API tests', function () { let kernel1: Kernel; let kernel2: Kernel; - setup(() => { + setup(async function () { kernel1 = new Kernel('mainKernel', 'Notebook Primary Test Kernel'); @@ -209,38 +179,37 @@ suite('Notebook API tests', function () { }; testDisposables.push(kernel1.controller, listener, kernel2.controller); + await saveAllFilesAndCloseAll(); }); - teardown(() => { + teardown(async function () { disposeAll(testDisposables); testDisposables.length = 0; + await saveAllFilesAndCloseAll(); }); test('shared document in notebook editors', async function () { - const resource = await createRandomNotebookFile(); let counter = 0; - const disposables: vscode.Disposable[] = []; - disposables.push(vscode.notebook.onDidOpenNotebookDocument(() => { + testDisposables.push(vscode.notebook.onDidOpenNotebookDocument(() => { counter++; })); - disposables.push(vscode.notebook.onDidCloseNotebookDocument(() => { - counter--; - })); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + const notebook = await openRandomNotebookDocument(); assert.strictEqual(counter, 1); - await splitEditor(); + await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Active }); assert.strictEqual(counter, 1); - await closeAllEditors(); - assert.strictEqual(counter, 0); + assert.strictEqual(vscode.window.visibleNotebookEditors.length, 1); - disposables.forEach(d => d.dispose()); + await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Beside }); + assert.strictEqual(counter, 1); + assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); }); - test('editor open/close event', async function () { + test('editor onDidChangeVisibleNotebookEditors-event', async function () { const resource = await createRandomNotebookFile(); const firstEditorOpen = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + await vscode.window.showNotebookDocument(resource); await firstEditorOpen; const firstEditorClose = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); @@ -248,7 +217,7 @@ suite('Notebook API tests', function () { await firstEditorClose; }); - test('editor open/close event 2', async function () { + test('editor onDidChangeVisibleNotebookEditors-event 2', async function () { const resource = await createRandomNotebookFile(); let count = 0; const disposables: vscode.Disposable[] = []; @@ -256,10 +225,10 @@ suite('Notebook API tests', function () { count = vscode.window.visibleNotebookEditors.length; })); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Active }); assert.strictEqual(count, 1); - await splitEditor(); + await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Beside }); assert.strictEqual(count, 2); await closeAllEditors(); @@ -333,8 +302,6 @@ suite('Notebook API tests', function () { // cells: vscode.window.activeNotebookEditor!.document.cellAt(0), // language: 'markdown' // }); - - await saveAllFilesAndCloseAll(undefined); }); test('editor move cell event', async function () { @@ -355,20 +322,20 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const firstEditor = vscode.window.activeNotebookEditor; assert.strictEqual(firstEditor?.document.cellCount, 2); - await saveAllFilesAndCloseAll(undefined); }); test('notebook editor active/visible', async function () { const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const firstEditor = vscode.window.activeNotebookEditor; - assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true); + const firstEditor = await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Active }); + assert.strictEqual(firstEditor === vscode.window.activeNotebookEditor, true); + assert.strictEqual(vscode.window.visibleNotebookEditors.includes(firstEditor), true); + + const secondEditor = await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Beside }); + assert.strictEqual(secondEditor === vscode.window.activeNotebookEditor, true); - await splitEditor(); - const secondEditor = vscode.window.activeNotebookEditor; - assert.strictEqual(secondEditor && vscode.window.visibleNotebookEditors.indexOf(secondEditor) >= 0, true); assert.notStrictEqual(firstEditor, secondEditor); - assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true); + assert.strictEqual(vscode.window.visibleNotebookEditors.includes(secondEditor), true); + assert.strictEqual(vscode.window.visibleNotebookEditors.includes(firstEditor), true); assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); const untitledEditorChange = asPromise(vscode.window.onDidChangeActiveNotebookEditor); @@ -386,8 +353,6 @@ suite('Notebook API tests', function () { assert.strictEqual(secondEditor, vscode.window.activeNotebookEditor); assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); assert.strictEqual(secondEditor && vscode.window.visibleNotebookEditors.indexOf(secondEditor) >= 0, true); - - await saveAllFilesAndCloseAll(undefined); }); test('notebook active editor change', async function () { @@ -399,8 +364,6 @@ suite('Notebook API tests', function () { const firstEditorDeactivate = asPromise(vscode.window.onDidChangeActiveNotebookEditor); await vscode.commands.executeCommand('workbench.action.splitEditor'); await firstEditorDeactivate; - - await saveFileAndCloseAll(resource); }); test('edit API (replaceMetadata)', async function () { @@ -416,7 +379,6 @@ suite('Notebook API tests', function () { assert.strictEqual(document.cellAt(0).metadata.inputCollapsed, true); assert.strictEqual(document.isDirty, true); - await saveFileAndCloseAll(resource); }); test('edit API (replaceMetadata, event)', async function () { @@ -434,7 +396,6 @@ suite('Notebook API tests', function () { assert.strictEqual(data.cell.metadata.inputCollapsed, true); assert.strictEqual(data.document.isDirty, true); - await saveFileAndCloseAll(resource); }); test('edit API batch edits', async function () { @@ -452,7 +413,6 @@ suite('Notebook API tests', function () { await cellsChangeEvent; await cellMetadataChangeEvent; assert.strictEqual(version + 1, vscode.window.activeNotebookEditor!.document.version); - await saveAllFilesAndCloseAll(resource); }); test('edit API batch edits undo/redo', async function () { @@ -477,24 +437,18 @@ suite('Notebook API tests', function () { assert.strictEqual(version + 2, vscode.window.activeNotebookEditor!.document.version); assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata?.inputCollapsed, undefined); assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 2); - - await saveAllFilesAndCloseAll(resource); }); test('initialzation should not emit cell change events.', async function () { const resource = await createRandomNotebookFile(); let count = 0; - const disposables: vscode.Disposable[] = []; - disposables.push(vscode.notebook.onDidChangeNotebookCells(() => { + + testDisposables.push(vscode.notebook.onDidChangeNotebookCells(() => { count++; })); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(count, 0); - - disposables.forEach(d => d.dispose()); - - await saveFileAndCloseAll(resource); }); // }); @@ -641,8 +595,6 @@ suite('Notebook API tests', function () { const newActiveCell = getFocusedCell(vscode.window.activeNotebookEditor); assert.deepStrictEqual(activeCell, newActiveCell); - - await saveFileAndCloseAll(resource); }); // test('document runnable based on kernel count', async () => { @@ -680,8 +632,6 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('notebook.execute'); assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work - - await saveAllFilesAndCloseAll(undefined); }); test('cell execute command takes arguments 2', async () => { @@ -712,8 +662,6 @@ suite('Notebook API tests', function () { assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath); }); - - await saveAllFilesAndCloseAll(undefined); }); test('document execute command takes arguments', async () => { @@ -743,8 +691,6 @@ suite('Notebook API tests', function () { assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath); }); - - await saveAllFilesAndCloseAll(undefined); }); test('cell execute and select kernel', async function () { @@ -776,8 +722,6 @@ suite('Notebook API tests', function () { 'my second output' ]); }); - - await saveAllFilesAndCloseAll(undefined); }); test('set outputs on cancel', async () => { @@ -822,13 +766,11 @@ suite('Notebook API tests', function () { }); cancelableKernel.controller.dispose(); - await saveAllFilesAndCloseAll(undefined); }); test('set outputs on interrupt', async () => { const interruptableKernel = new class extends Kernel { - constructor() { super('interruptableKernel', 'Notebook Interruptable Test Kernel'); this.controller.interruptHandler = this.interrupt.bind(this); @@ -841,7 +783,6 @@ suite('Notebook API tests', function () { this._task.start(); } - async interrupt() { await this._task!.replaceOutput([new vscode.NotebookCellOutput([ new vscode.NotebookCellOutputItem('text/plain', ['Interrupted'], undefined) @@ -870,7 +811,6 @@ suite('Notebook API tests', function () { }); interruptableKernel.controller.dispose(); - await saveAllFilesAndCloseAll(undefined); }); test('onDidChangeCellExecutionState is fired', async () => { @@ -900,7 +840,6 @@ suite('Notebook API tests', function () { await p; listener.dispose(); - await saveAllFilesAndCloseAll(undefined); }); // suite('notebook dirty state', () => { @@ -930,8 +869,6 @@ suite('Notebook API tests', function () { assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor)); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;'); }); - - await saveFileAndCloseAll(resource); }); // }); @@ -974,8 +911,6 @@ suite('Notebook API tests', function () { // assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 2); // assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(getFocusedCell(vscode.window.activeNotebookEditor)!), 1); // assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'test'); - - await saveFileAndCloseAll(resource); }); test('multiple tabs: dirty + clean', async function () { @@ -999,7 +934,6 @@ suite('Notebook API tests', function () { assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;'); - await saveFileAndCloseAll(resource); }); test('multiple tabs: two dirty tabs and switching', async function () { @@ -1032,19 +966,19 @@ suite('Notebook API tests', function () { assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 3); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), ''); - await saveAllFilesAndCloseAll(secondResource); }); test.skip('multiple tabs: different editors with same document', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const firstNotebookEditor = vscode.window.activeNotebookEditor; + + const notebook = await openRandomNotebookDocument(); + const firstNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.One }); + assert.ok(firstNotebookEditor === vscode.window.activeNotebookEditor); + assert.strictEqual(firstNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.getText(), 'test'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript'); - await splitEditor(); - const secondNotebookEditor = vscode.window.activeNotebookEditor; + const secondNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Two }); assert.strictEqual(secondNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.getText(), 'test'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript'); @@ -1052,7 +986,6 @@ suite('Notebook API tests', function () { assert.notStrictEqual(firstNotebookEditor, secondNotebookEditor); assert.strictEqual(firstNotebookEditor?.document, secondNotebookEditor?.document, 'split notebook editors share the same document'); - await saveAllFilesAndCloseAll(resource); }); test('custom metadata should be supported', async function () { @@ -1063,7 +996,6 @@ suite('Notebook API tests', function () { assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.metadata.custom!['testCellMetadata'] as number, 123); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.languageId, 'typescript'); - await saveFileAndCloseAll(resource); }); @@ -1082,42 +1014,37 @@ suite('Notebook API tests', function () { // assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1); // assert.strictEqual(activeCell?.metadata.custom!['testCellMetadata'] as number, 123); - await saveFileAndCloseAll(resource); }); test('#106657. Opening a notebook from markers view is broken ', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const document = vscode.window.activeNotebookEditor?.document!; + const document = await openRandomNotebookDocument(); const [cell] = document.getCells(); - await saveAllFilesAndCloseAll(document.uri); assert.strictEqual(vscode.window.activeNotebookEditor, undefined); // opening a cell-uri opens a notebook editor await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active); + // await vscode.window.showTextDocument(cell.document, { viewColumn: vscode.ViewColumn.Active }); assert.strictEqual(!!vscode.window.activeNotebookEditor, true); - assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), resource.toString()); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString()); }); - test.skip('Cannot open notebook from cell-uri with vscode.open-command', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + test('Cannot open notebook from cell-uri with vscode.open-command', async function () { - const document = vscode.window.activeNotebookEditor?.document!; + const document = await openRandomNotebookDocument(); const [cell] = document.getCells(); - await saveAllFilesAndCloseAll(document.uri); + await saveAllFilesAndCloseAll(); assert.strictEqual(vscode.window.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.document.uri); - assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), resource.toString()); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString()); }); test('#97830, #97764. Support switch to other editor types', async function () { @@ -1137,8 +1064,6 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, resource.path); - - await closeAllEditors(); }); // open text editor, pin, and then open a notebook @@ -1154,7 +1079,6 @@ suite('Notebook API tests', function () { assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'notebook first'); // assert.notStrictEqual(vscode.window.activeTextEditor, undefined); - await closeAllEditors(); }); test('#102411 - untitled notebook creation failed', async function () { @@ -1234,7 +1158,6 @@ suite('Notebook API tests', function () { await assertKernel(verifyOutputSyncKernel.controller); await vscode.commands.executeCommand('notebook.cell.execute'); - await saveAllFilesAndCloseAll(undefined); verifyOutputSyncKernel.controller.dispose(); }); @@ -1252,20 +1175,17 @@ suite('Notebook API tests', function () { assert.strictEqual(cell.latestExecutionSummary!.success, true); assert.strictEqual(typeof cell.latestExecutionSummary!.executionOrder, 'number'); - await saveAllFilesAndCloseAll(undefined); }); test('initialize latestExecutionSummary', async () => { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const editor = vscode.window.activeNotebookEditor!; - const cell = editor.document.cellAt(0); + + const document = await openRandomNotebookDocument(); + const cell = document.cellAt(0); assert.strictEqual(cell.latestExecutionSummary?.success, undefined); assert.strictEqual(cell.latestExecutionSummary?.startTime, 10); assert.strictEqual(cell.latestExecutionSummary?.endTime, 20); - await saveAllFilesAndCloseAll(undefined); });