Skip to content

Commit 6679ce7

Browse files
Add comprehensive integration tests for .deepnote file execution
Co-Authored-By: Filip Pyrek <PyrekFilip@gmail.com>
1 parent f5401c3 commit 6679ce7

File tree

1 file changed

+103
-17
lines changed

1 file changed

+103
-17
lines changed

src/test/datascience/notebook/deepnote.vscode.test.ts

Lines changed: 103 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
/* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */
22
import { assert } from 'chai';
3-
import { Uri, workspace } from 'vscode';
3+
import { Uri, workspace, NotebookDocument } from 'vscode';
44
import { IDisposable } from '../../../platform/common/types';
5-
import { captureScreenShot, IExtensionTestApi } from '../../common.node';
5+
import { captureScreenShot, IExtensionTestApi, waitForCondition } from '../../common.node';
66
import { EXTENSION_ROOT_DIR_FOR_TESTS, initialize } from '../../initialize.node';
7-
import { closeNotebooksAndCleanUpAfterTests } from './helper.node';
7+
import { closeNotebooksAndCleanUpAfterTests, startJupyterServer, getDefaultKernelConnection } from './helper.node';
88
import { logger } from '../../../platform/logging';
99
import { IDeepnoteNotebookManager } from '../../../notebooks/types';
10+
import { IKernel, IKernelProvider, INotebookKernelExecution } from '../../../kernels/types';
11+
import { createKernelController } from './executionHelper';
1012

1113
/* eslint-disable @typescript-eslint/no-explicit-any, no-invalid-this */
1214
suite('Deepnote Integration Tests @kernelCore', function () {
@@ -20,13 +22,36 @@ suite('Deepnote Integration Tests @kernelCore', function () {
2022
'notebook',
2123
'test.deepnote'
2224
);
25+
let nbDocument: NotebookDocument;
26+
let kernel: IKernel;
27+
let kernelExecution: INotebookKernelExecution;
2328
this.timeout(240_000);
2429

2530
suiteSetup(async function () {
2631
logger.info('Suite Setup VS Code Notebook - Deepnote Integration');
2732
this.timeout(240_000);
2833
try {
2934
api = await initialize();
35+
logger.info('After initialize');
36+
37+
await startJupyterServer();
38+
logger.info('After starting Jupyter');
39+
40+
const notebookManager = api.serviceContainer.get<IDeepnoteNotebookManager>(IDeepnoteNotebookManager);
41+
notebookManager.selectNotebookForProject('test-project-id', 'main-notebook-id');
42+
43+
nbDocument = await workspace.openNotebookDocument(deepnoteFilePath);
44+
logger.info(`Opened notebook with ${nbDocument.cellCount} cells`);
45+
46+
const kernelProvider = api.serviceContainer.get<IKernelProvider>(IKernelProvider);
47+
const metadata = await getDefaultKernelConnection();
48+
const controller = createKernelController();
49+
kernel = kernelProvider.getOrCreate(nbDocument, { metadata, resourceUri: nbDocument.uri, controller });
50+
logger.info('Before starting kernel');
51+
await kernel.start();
52+
logger.info('After starting kernel');
53+
kernelExecution = kernelProvider.getKernelExecution(kernel);
54+
3055
logger.info('Suite Setup (completed)');
3156
} catch (e) {
3257
logger.error('Suite Setup (failed) - Deepnote Integration', e);
@@ -51,30 +76,91 @@ suite('Deepnote Integration Tests @kernelCore', function () {
5176
test('Load .deepnote file', async function () {
5277
logger.debug('Test: Load .deepnote file - starting');
5378

54-
const notebookManager = api.serviceContainer.get<IDeepnoteNotebookManager>(IDeepnoteNotebookManager);
55-
assert.isOk(notebookManager, 'Notebook manager should be available');
56-
57-
notebookManager.selectNotebookForProject('test-project-id', 'main-notebook-id');
58-
59-
const nbDocument = await workspace.openNotebookDocument(deepnoteFilePath);
60-
61-
logger.debug(`Opened notebook with type: ${nbDocument.notebookType}, cells: ${nbDocument.cellCount}`);
62-
6379
assert.equal(nbDocument.notebookType, 'deepnote', 'Notebook type should be deepnote');
6480
assert.equal(nbDocument.cellCount, 3, 'Notebook should have 3 cells');
65-
6681
assert.equal(nbDocument.metadata?.deepnoteProjectId, 'test-project-id', 'Project ID should match');
6782
assert.equal(nbDocument.metadata?.deepnoteNotebookId, 'main-notebook-id', 'Notebook ID should match');
6883

6984
logger.debug('Test: Load .deepnote file - completed');
7085
});
7186

72-
test('Extension services are available', async function () {
73-
logger.debug('Test: Extension services are available - starting');
87+
test('Execute code cell and verify output', async function () {
88+
logger.debug('Test: Execute code cell - starting');
89+
90+
const cell = nbDocument.cellAt(0);
91+
assert.equal(cell.kind, 1, 'First cell should be a code cell');
92+
93+
await kernelExecution.executeCell(cell);
94+
95+
await waitForCondition(
96+
async () => cell.executionSummary?.success === true,
97+
30_000,
98+
'Cell execution did not complete successfully'
99+
);
100+
101+
assert.isAtLeast(cell.executionSummary?.executionOrder || 0, 1, 'Cell should have execution order');
102+
assert.isTrue(cell.executionSummary?.success, 'Cell execution should succeed');
103+
assert.isAtLeast(cell.outputs.length, 1, 'Cell should have at least one output');
104+
105+
const outputText = new TextDecoder().decode(cell.outputs[0].items[0].data).toString();
106+
assert.include(outputText, 'Hello World', 'Output should contain "Hello World"');
107+
108+
logger.debug('Test: Execute code cell - completed');
109+
});
110+
111+
test('Execute multiple code cells with shared state', async function () {
112+
logger.debug('Test: Execute multiple code cells - starting');
113+
114+
const cell1 = nbDocument.cellAt(0);
115+
const cell2 = nbDocument.cellAt(1);
116+
117+
await kernelExecution.executeCell(cell1);
118+
await waitForCondition(
119+
async () => cell1.executionSummary?.success === true,
120+
30_000,
121+
'First cell execution did not complete'
122+
);
123+
124+
await kernelExecution.executeCell(cell2);
125+
await waitForCondition(
126+
async () => cell2.executionSummary?.success === true,
127+
30_000,
128+
'Second cell execution did not complete'
129+
);
130+
131+
assert.isTrue(cell2.executionSummary?.success, 'Second cell should execute successfully');
132+
assert.isAtLeast(cell2.outputs.length, 1, 'Second cell should have output');
133+
134+
const outputText = new TextDecoder().decode(cell2.outputs[0].items[0].data).toString();
135+
assert.include(outputText, '42', 'Output should contain the value 42');
136+
137+
logger.debug('Test: Execute multiple code cells - completed');
138+
});
139+
140+
test('Init notebook executes automatically', async function () {
141+
logger.debug('Test: Init notebook execution - starting');
74142

75143
const notebookManager = api.serviceContainer.get<IDeepnoteNotebookManager>(IDeepnoteNotebookManager);
76-
assert.isOk(notebookManager, 'Notebook manager should be available');
77144

78-
logger.debug('Test: Extension services are available - completed');
145+
await waitForCondition(
146+
async () => notebookManager.hasInitNotebookBeenRun('test-project-id'),
147+
60_000,
148+
'Init notebook did not execute within timeout'
149+
);
150+
151+
assert.isTrue(
152+
notebookManager.hasInitNotebookBeenRun('test-project-id'),
153+
'Init notebook should have been marked as run'
154+
);
155+
156+
const cell = nbDocument.cellAt(0);
157+
await kernelExecution.executeCell(cell);
158+
await waitForCondition(
159+
async () => cell.executionSummary?.success === true,
160+
30_000,
161+
'Cell execution did not complete'
162+
);
163+
164+
logger.debug('Test: Init notebook execution - completed');
79165
});
80166
});

0 commit comments

Comments
 (0)