Skip to content

Commit a3f414c

Browse files
committed
add some integration tests for notebook editing, #105283
1 parent dd3e9ee commit a3f414c

File tree

4 files changed

+104
-17
lines changed

4 files changed

+104
-17
lines changed

extensions/vscode-notebook-tests/src/notebook.test.ts

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,11 @@ async function saveFileAndCloseAll(resource: vscode.Uri) {
7070
await documentClosed;
7171
}
7272

73-
async function saveAllFilesAndCloseAll(resource: vscode.Uri) {
73+
async function saveAllFilesAndCloseAll(resource: vscode.Uri | undefined) {
7474
const documentClosed = new Promise((resolve, _reject) => {
75+
if (!resource) {
76+
return resolve();
77+
}
7578
const d = vscode.notebook.onDidCloseNotebookDocument(e => {
7679
if (e.uri.toString() === resource.toString()) {
7780
d.dispose();
@@ -393,23 +396,107 @@ suite('Notebook API tests', () => {
393396
await saveFileAndCloseAll(resource);
394397
});
395398

396-
test('edit API', async function () {
399+
test('edit API (replaceCells)', async function () {
397400
assertInitalState();
398401
const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
399402
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
400403

401404
const cellsChangeEvent = getEventOncePromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
402405
await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
403-
editBuilder.insert(1, 'test 2', 'javascript', vscode.CellKind.Code, [], undefined);
406+
editBuilder.replaceCells(1, 0, [{ cellKind: vscode.CellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]);
404407
});
405408

406409
const cellChangeEventRet = await cellsChangeEvent;
407-
assert.equal(cellChangeEventRet.document, vscode.notebook.activeNotebookEditor?.document);
408-
assert.equal(cellChangeEventRet.changes.length, 1);
409-
assert.deepEqual(cellChangeEventRet.changes[0].start, 1);
410-
assert.deepEqual(cellChangeEventRet.changes[0].deletedCount, 0);
411-
assert.equal(cellChangeEventRet.changes[0].items[0], vscode.notebook.activeNotebookEditor!.document.cells[1]);
410+
assert.strictEqual(cellChangeEventRet.document === vscode.notebook.activeNotebookEditor?.document, true);
411+
assert.strictEqual(cellChangeEventRet.document.isDirty, true);
412+
assert.strictEqual(cellChangeEventRet.changes.length, 1);
413+
assert.strictEqual(cellChangeEventRet.changes[0].start, 1);
414+
assert.strictEqual(cellChangeEventRet.changes[0].deletedCount, 0);
415+
assert.strictEqual(cellChangeEventRet.changes[0].items[0] === vscode.notebook.activeNotebookEditor!.document.cells[1], true);
416+
417+
await saveAllFilesAndCloseAll(resource);
418+
});
419+
420+
test('edit API (replaceOutput)', async function () {
421+
// no output events yet...
422+
this.skip();
423+
424+
assertInitalState();
425+
const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
426+
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
427+
428+
await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
429+
editBuilder.replaceOutput(0, [{ outputKind: vscode.CellOutputKind.Rich, data: { foo: 'bar' } }]);
430+
});
431+
432+
const document = vscode.notebook.activeNotebookEditor?.document!;
433+
assert.strictEqual(document.isDirty, false);
434+
assert.strictEqual(document.cells.length, 1);
435+
assert.strictEqual(document.cells[0].outputs.length, 1);
436+
assert.strictEqual(document.cells[0].outputs[0].outputKind, vscode.CellOutputKind.Rich);
437+
438+
await saveAllFilesAndCloseAll(undefined);
439+
});
440+
441+
test('edit API (replaceOutput, event)', async function () {
442+
// no output events yet...
443+
this.skip();
444+
445+
assertInitalState();
446+
const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
447+
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
448+
449+
const outputChangeEvent = getEventOncePromise<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs);
450+
await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
451+
editBuilder.replaceOutput(0, [{ outputKind: vscode.CellOutputKind.Rich, data: { foo: 'bar' } }]);
452+
});
453+
454+
const value = await outputChangeEvent;
455+
assert.strictEqual(value.document === vscode.notebook.activeNotebookEditor?.document, true);
456+
assert.strictEqual(value.cells.length, 1);
457+
assert.strictEqual(value.cells[0].outputs.length, 1);
458+
assert.strictEqual(value.cells[0].outputs[0].outputKind, vscode.CellOutputKind.Rich);
459+
460+
await saveAllFilesAndCloseAll(undefined);
461+
});
462+
463+
test('edit API (replaceMetadata)', async function () {
464+
465+
assertInitalState();
466+
const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
467+
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
468+
469+
await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
470+
editBuilder.replaceMetadata(0, { inputCollapsed: true, executionOrder: 17 });
471+
});
472+
473+
const document = vscode.notebook.activeNotebookEditor?.document!;
474+
assert.strictEqual(document.cells.length, 1);
475+
assert.strictEqual(document.cells[0].metadata.executionOrder, 17);
476+
assert.strictEqual(document.cells[0].metadata.inputCollapsed, true);
477+
478+
assert.strictEqual(document.isDirty, true);
479+
await saveFileAndCloseAll(resource);
480+
});
481+
482+
test('edit API (replaceMetadata, event)', async function () {
483+
484+
assertInitalState();
485+
const resource = await createRandomFile('', undefined, 'first', '.vsctestnb');
486+
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
487+
488+
const event = getEventOncePromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebook.onDidChangeCellMetadata);
489+
490+
await vscode.notebook.activeNotebookEditor!.edit(editBuilder => {
491+
editBuilder.replaceMetadata(0, { inputCollapsed: true, executionOrder: 17 });
492+
});
493+
494+
const data = await event;
495+
assert.strictEqual(data.document, vscode.notebook.activeNotebookEditor?.document);
496+
assert.strictEqual(data.cell.metadata.executionOrder, 17);
497+
assert.strictEqual(data.cell.metadata.inputCollapsed, true);
412498

499+
assert.strictEqual(data.document.isDirty, true);
413500
await saveFileAndCloseAll(resource);
414501
});
415502

src/vs/workbench/api/browser/mainThreadNotebook.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
242242
const disposableStore = new DisposableStore();
243243
const textModel = this._notebookService.getNotebookTextModel(doc);
244244
disposableStore.add(textModel!.onDidModelChangeProxy(e => {
245-
this._proxy.$acceptModelChanged(textModel!.uri, e);
245+
this._proxy.$acceptModelChanged(textModel!.uri, e, textModel!.isDirty);
246246
this._proxy.$acceptEditorPropertiesChanged(doc, { selections: { selections: textModel!.selections }, metadata: null });
247247
}));
248248
disposableStore.add(textModel!.onDidSelectionChange(e => {

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1668,7 +1668,7 @@ export interface ExtHostNotebookShape {
16681668
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
16691669
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelId: string | undefined }): void;
16701670
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
1671-
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void;
1671+
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent, isDirty: boolean): void;
16721672
$acceptModelSaved(uriComponents: UriComponents): void;
16731673
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void;
16741674
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void;

src/vs/workbench/api/common/extHostNotebook.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ export class ExtHostNotebookDocument extends Disposable {
213213
private _metadataChangeListener: IDisposable;
214214
private _displayOrder: string[] = [];
215215
private _versionId = 0;
216+
private _isDirty: boolean = false;
216217
private _backupCounter = 1;
217218
private _backup?: vscode.NotebookDocumentBackup;
218219
private _disposed = false;
@@ -274,7 +275,7 @@ export class ExtHostNotebookDocument extends Disposable {
274275
get version() { return that._versionId; },
275276
get fileName() { return that.uri.fsPath; },
276277
get viewType() { return that._viewType; },
277-
get isDirty() { return false; },
278+
get isDirty() { return that._isDirty; },
278279
get isUntitled() { return that.uri.scheme === Schemas.untitled; },
279280
get cells(): ReadonlyArray<vscode.NotebookCell> { return that._cells.map(cell => cell.cell); },
280281
get languages() { return that._languages; },
@@ -311,8 +312,9 @@ export class ExtHostNotebookDocument extends Disposable {
311312
this._backup = undefined;
312313
}
313314

314-
acceptModelChanged(event: NotebookCellsChangedEvent): void {
315+
acceptModelChanged(event: NotebookCellsChangedEvent, isDirty: boolean): void {
315316
this._versionId = event.versionId;
317+
this._isDirty = isDirty;
316318
if (event.kind === NotebookCellsChangeType.Initialize) {
317319
this._spliceNotebookCells(event.changes, true);
318320
} if (event.kind === NotebookCellsChangeType.ModelChange) {
@@ -1255,12 +1257,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
12551257
this._webviewComm.get(editorId)?.onDidReceiveMessage(forRendererType, message);
12561258
}
12571259

1258-
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void {
1259-
1260+
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent, isDirty: boolean): void {
12601261
const document = this._documents.get(URI.revive(uriComponents));
1261-
12621262
if (document) {
1263-
document.acceptModelChanged(event);
1263+
document.acceptModelChanged(event, isDirty);
12641264
}
12651265
}
12661266

@@ -1401,7 +1401,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
14011401
0,
14021402
modelData.cells
14031403
]]
1404-
});
1404+
}, false);
14051405

14061406
// add cell document as vscode.TextDocument
14071407
addedCellDocuments.push(...modelData.cells.map(cell => ExtHostCell.asModelAddData(document.notebookDocument, cell)));

0 commit comments

Comments
 (0)