1

We're developing a VSCode extension that works with Jupyter notebooks and need to run integration tests in CI/CD. The main issue is that when running integration tests, VSCode prompts the user to manually select a Jupyter kernel, which breaks automation.

The current setup is a custom extension that integrates with Jupyter notebooks and uses 'vscode/test-electron' for integration testing.

When running the current integration tests:

  1. VSCode opens a notebook file
  2. Try to execute a cell
  3. Test hangs waiting for manual kernel selection in the UI. In CI/CD, this causes tests to timeout. If the user does click on the test kernel the test succeed.

Here is the current setup to try to programmatically select a default kernel to execute a jupyter notebook cell:

Notebook Metadata Injection

We inject the kernel specification directly into the notebook file:

{
  "metadata": {
    "kernelspec": {
      "name": "test-kernel",
      "display_name": "Python (Test Environment)",
      "language": "python"
    }
  }
}

VSCode Settings Configuration

We create workspace-specific settings to configure the Jupyter extension:

{
  "python.defaultInterpreterPath": "/path/to/test-venv/bin/python",
  "jupyter.jupyterServerType": "local",
  "jupyter.kernels.default": "test-kernel",
  "jupyter.alwaysTrustNotebooks": true
}

Current Test Code

test('Execute notebook cell', async function () {
    this.timeout(10000);
    
    const nbWsPath = vscode.workspace.workspaceFolders![0].uri.fsPath;
    const nbPath = path.join(nbWsPath, 'simple_notebook.ipynb');

    // Open notebook
    const nbDoc = await vscode.workspace.openNotebookDocument(vscode.Uri.file(nbPath));
    const editor = await vscode.window.showNotebookDocument(nbDoc);

    // Wait for notebook to initialize
    await new Promise(resolve => setTimeout(resolve, 3000));

    // Execute our extension functionality that triggers kernel selection prompt
    await executeCell(editor, 0);
    
    // Wait for execution to complete
    await waitForCellExecution(editor, 0);

    // Verify execution
    const cell = editor.notebook.cellAt(0);
    assert.ok(cell.executionSummary, 'Cell should have execution summary');
    assert.ok(cell.executionSummary.executionOrder, 'Cell should have execution order');
});

Test Setup Code

Here's a simplified version of how we set up the test environment:

// src/test/runTest.ts (simplified)
async function main(): Promise<void> {
    const extensionDevelopmentPath = path.resolve(__dirname, '../../../');
    const fixturesPath = path.resolve(extensionDevelopmentPath, 'src/test/fixtures/workspaces');
    const userDataDir = path.resolve(fixturesPath, 'userdata');

    // Download and setup VSCode
    const vscodeExecutablePath = await downloadAndUnzipVSCode('stable');
    const cli = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath);

    // Install required extensions
    spawnSync(cli[0], [...cli.slice(1), '--install-extension', 'ms-toolsai.jupyter'], { stdio: 'inherit' });
    spawnSync(cli[0], [...cli.slice(1), '--install-extension', 'ms-python.python'], { stdio: 'inherit' });

    // Create test virtual environment and register kernel
    const venvDir = path.join(os.tmpdir(), 'test-venv');
    const systemPython = 'python3';
    
    if (!fs.existsSync(venvDir)) {
        spawnSync(systemPython, ['-m', 'venv', venvDir], { stdio: 'inherit' });
    }
    
    const venvPython = path.join(venvDir, 'bin', 'python');
    spawnSync(venvPython, ['-m', 'pip', 'install', 'ipykernel'], { stdio: 'inherit' });
    spawnSync(venvPython, ['-m', 'ipykernel', 'install', '--sys-prefix', '--name', 'test-kernel', '--display-name', 'Python (Test Environment)'], { stdio: 'inherit' });

    // Setup workspace with settings
    const workspaceFolder = path.join(fixturesPath, 'simple_cell_execution');
    const wsVscodeDir = path.join(workspaceFolder, '.vscode');
    const wsSettingsPath = path.join(wsVscodeDir, 'settings.json');
    
    if (!fs.existsSync(wsVscodeDir)) fs.mkdirSync(wsVscodeDir, { recursive: true });
    
    const settings = {
        "python.defaultInterpreterPath": venvPython,
        "jupyter.jupyterServerType": "local",
        "jupyter.kernels.default": "test-kernel",
        "jupyter.alwaysTrustNotebooks": true
    };
    fs.writeFileSync(wsSettingsPath, JSON.stringify(settings, null, 2));

    // Run tests
    await runTests({
        vscodeExecutablePath,
        extensionDevelopmentPath,
        extensionTestsPath: path.resolve(__dirname, './suite/index'),
        launchArgs: [
            `--user-data-dir=${userDataDir}`, 
            `--enable-proposed-api=ms-toolsai.jupyter`,
            `--enable-proposed-api=ms-python.python`,
            workspaceFolder
        ],
    });
}

Key Files

  • Test Runner: src/test/runTest.ts
  • Integration Test: src/test/integration/simple_cell_execution.integration.test.ts
  • Notebook: src/test/fixtures/workspaces/simple_cell_execution/simple_notebook.ipynb
  • Settings: src/test/fixtures/workspaces/simple_cell_execution/.vscode/settings.json

So my questions are:

  • why isn't the jupyter notebook directly using the default kernel like it does in my personnal instance of vscode (compare to the integration test context)
  • Is there another way to select the jupyter notebook kernel programmatically ?
2
  • Welcome to stackoverflow. Can you edit your question and make the title more descriptive? "issue" is pointless; ask a question in the title. Trim the text, we don't need a cookie cutter template with headings for environment and expected results and what not. It just bloats your question. Use less bold font. Simplify the code in favor of a minimal reproducible example: if the test never runs anyway, shorten it to an empty function. Don't ask for best practices; this is off-topic as it leads to opinion-based answers. Good luck! Commented Oct 3 at 14:10
  • Thanks for the feedback, I have edited down my question. Commented Oct 3 at 16:13

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.