-
Notifications
You must be signed in to change notification settings - Fork 4
Add integration tests for .deepnote file handling (GRN-4766) #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -143,6 +143,44 @@ jobs: | |||||||||||||||||||||||||||||||||||
| - name: Check licenses | ||||||||||||||||||||||||||||||||||||
| run: npm run check-licenses | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| integration-tests: | ||||||||||||||||||||||||||||||||||||
| name: Integration Tests - Deepnote | ||||||||||||||||||||||||||||||||||||
| runs-on: ubicloud-standard-2 | ||||||||||||||||||||||||||||||||||||
| timeout-minutes: 30 | ||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||
| id-token: write | ||||||||||||||||||||||||||||||||||||
| contents: read | ||||||||||||||||||||||||||||||||||||
| packages: read | ||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||
| - name: Checkout | ||||||||||||||||||||||||||||||||||||
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - name: Setup Node.js | ||||||||||||||||||||||||||||||||||||
| uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5 | ||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||
| cache: 'npm' | ||||||||||||||||||||||||||||||||||||
| node-version-file: '.nvmrc' | ||||||||||||||||||||||||||||||||||||
| registry-url: 'https://npm.pkg.github.com' | ||||||||||||||||||||||||||||||||||||
| scope: '@deepnote' | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - name: Setup Python | ||||||||||||||||||||||||||||||||||||
| uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 | ||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||
| python-version: '3.12' | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - name: Install dependencies | ||||||||||||||||||||||||||||||||||||
| run: npm ci --prefer-offline --no-audit | ||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - name: Compile TypeScript | ||||||||||||||||||||||||||||||||||||
| run: npm run compile | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - name: Run Deepnote integration tests | ||||||||||||||||||||||||||||||||||||
| run: xvfb-run -a npm test | ||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||
| VSC_JUPYTER_CI_TEST_GREP: 'Deepnote Integration Tests' | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
Comment on lines
+179
to
+183
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Capture diagnostics on failures (screenshots/logs). Tests take screenshots on failure; upload them as artifacts to debug CI. - name: Run Deepnote integration tests
run: xvfb-run -a npm test
env:
VSC_JUPYTER_CI_TEST_GREP: 'Deepnote Integration Tests'
+
+ - name: Upload screenshots (on failure)
+ if: failure()
+ uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4
+ with:
+ name: deepnote-integration-screenshots
+ path: |
+ **/*screenshot*.png
+ **/screenshots/**📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
| check_licenses: | ||||||||||||||||||||||||||||||||||||
| name: Check Licenses | ||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,161 @@ | ||||||||||||||||||||||||||||||||||||||
| // Copyright (c) Microsoft Corporation. | ||||||||||||||||||||||||||||||||||||||
| // Licensed under the MIT License. | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+2
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Remove header from new test file (guidelines). New files shouldn’t include the Microsoft copyright header. As per coding guidelines. -// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ | ||||||||||||||||||||||||||||||||||||||
| import { assert } from 'chai'; | ||||||||||||||||||||||||||||||||||||||
| import * as path from '../../../platform/vscode-path/path'; | ||||||||||||||||||||||||||||||||||||||
| import { Uri, workspace } from 'vscode'; | ||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Import NotebookCellKind and use constants, not magic numbers. Avoid brittle numeric enums in tests. -import { Uri, workspace } from 'vscode';
+import { NotebookCellKind, Uri, workspace } from 'vscode';
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| import { IDisposable } from '../../../platform/common/types'; | ||||||||||||||||||||||||||||||||||||||
| import { captureScreenShot, IExtensionTestApi } from '../../common.node'; | ||||||||||||||||||||||||||||||||||||||
| import { EXTENSION_ROOT_DIR_FOR_TESTS, initialize } from '../../initialize.node'; | ||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||
| closeNotebooksAndCleanUpAfterTests, | ||||||||||||||||||||||||||||||||||||||
| startJupyterServer, | ||||||||||||||||||||||||||||||||||||||
| defaultNotebookTestTimeout, | ||||||||||||||||||||||||||||||||||||||
| waitForExecutionCompletedSuccessfully, | ||||||||||||||||||||||||||||||||||||||
| getCellOutputs, | ||||||||||||||||||||||||||||||||||||||
| getDefaultKernelConnection | ||||||||||||||||||||||||||||||||||||||
| } from './helper.node'; | ||||||||||||||||||||||||||||||||||||||
| import { logger } from '../../../platform/logging'; | ||||||||||||||||||||||||||||||||||||||
| import { IKernel, IKernelProvider, INotebookKernelExecution } from '../../../kernels/types'; | ||||||||||||||||||||||||||||||||||||||
| import { createKernelController, TestNotebookDocument } from './executionHelper'; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /* eslint-disable @typescript-eslint/no-explicit-any, no-invalid-this */ | ||||||||||||||||||||||||||||||||||||||
| suite('Deepnote Integration Tests @kernelCore', function () { | ||||||||||||||||||||||||||||||||||||||
| let api: IExtensionTestApi; | ||||||||||||||||||||||||||||||||||||||
| const disposables: IDisposable[] = []; | ||||||||||||||||||||||||||||||||||||||
| const deepnoteFileUri = Uri.file( | ||||||||||||||||||||||||||||||||||||||
| path.join(EXTENSION_ROOT_DIR_FOR_TESTS, 'src', 'test', 'datascience', 'notebook', 'test.deepnote') | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+27
to
+29
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Use Uri.joinPath per guidelines. Prefer Uri.joinPath over path.join + Uri.file. As per coding guidelines. - const deepnoteFileUri = Uri.file(
- path.join(EXTENSION_ROOT_DIR_FOR_TESTS, 'src', 'test', 'datascience', 'notebook', 'test.deepnote')
- );
+ const deepnoteFileUri = Uri.joinPath(
+ Uri.file(EXTENSION_ROOT_DIR_FOR_TESTS),
+ 'src',
+ 'test',
+ 'datascience',
+ 'notebook',
+ 'test.deepnote'
+ );📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| this.timeout(120_000); | ||||||||||||||||||||||||||||||||||||||
| let notebook: TestNotebookDocument; | ||||||||||||||||||||||||||||||||||||||
| let kernel: IKernel; | ||||||||||||||||||||||||||||||||||||||
| let kernelExecution: INotebookKernelExecution; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| suiteSetup(async function () { | ||||||||||||||||||||||||||||||||||||||
| logger.info('Suite Setup Deepnote Integration Tests'); | ||||||||||||||||||||||||||||||||||||||
| this.timeout(120_000); | ||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||
| api = await initialize(); | ||||||||||||||||||||||||||||||||||||||
| logger.debug('Before starting Jupyter'); | ||||||||||||||||||||||||||||||||||||||
| await startJupyterServer(); | ||||||||||||||||||||||||||||||||||||||
| logger.debug('After starting Jupyter'); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| logger.debug('Opening .deepnote file'); | ||||||||||||||||||||||||||||||||||||||
| const nbDocument = await workspace.openNotebookDocument(deepnoteFileUri); | ||||||||||||||||||||||||||||||||||||||
| logger.debug(`Opened .deepnote file with ${nbDocument.cellCount} cells`); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| notebook = new TestNotebookDocument(nbDocument.uri, 'deepnote' as any, nbDocument.metadata as any, false); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| await Promise.all( | ||||||||||||||||||||||||||||||||||||||
| nbDocument.getCells().map(async (cell) => { | ||||||||||||||||||||||||||||||||||||||
| if (cell.kind === 1) { | ||||||||||||||||||||||||||||||||||||||
| return notebook.appendCodeCell( | ||||||||||||||||||||||||||||||||||||||
| cell.document.getText(), | ||||||||||||||||||||||||||||||||||||||
| cell.document.languageId, | ||||||||||||||||||||||||||||||||||||||
| cell.metadata | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||
| return notebook.appendMarkdownCell(cell.document.getText(), cell.metadata); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+52
to
+60
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace magic numbers with NotebookCellKind. 1 = Code, 2 = Markup today, but using constants is safer and clearer. - if (cell.kind === 1) {
+ if (cell.kind === NotebookCellKind.Code) {
return notebook.appendCodeCell(
cell.document.getText(),
cell.document.languageId,
cell.metadata
);
} else {
return notebook.appendMarkdownCell(cell.document.getText(), cell.metadata);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const kernelProvider = api.serviceContainer.get<IKernelProvider>(IKernelProvider); | ||||||||||||||||||||||||||||||||||||||
| logger.debug('Before creating kernel connection'); | ||||||||||||||||||||||||||||||||||||||
| const metadata = await getDefaultKernelConnection(); | ||||||||||||||||||||||||||||||||||||||
| logger.debug('After creating kernel connection'); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const controller = createKernelController(); | ||||||||||||||||||||||||||||||||||||||
| kernel = kernelProvider.getOrCreate(notebook, { metadata, resourceUri: notebook.uri, controller }); | ||||||||||||||||||||||||||||||||||||||
| logger.debug('Before starting kernel'); | ||||||||||||||||||||||||||||||||||||||
| await kernel.start(); | ||||||||||||||||||||||||||||||||||||||
| logger.debug('After starting kernel'); | ||||||||||||||||||||||||||||||||||||||
| kernelExecution = kernelProvider.getKernelExecution(kernel); | ||||||||||||||||||||||||||||||||||||||
| logger.info('Suite Setup (completed)'); | ||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||
| logger.error('Suite Setup (failed) - Deepnote Integration Tests', e); | ||||||||||||||||||||||||||||||||||||||
| await captureScreenShot('deepnote-integration-suite'); | ||||||||||||||||||||||||||||||||||||||
| throw e; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| setup(function () { | ||||||||||||||||||||||||||||||||||||||
| logger.info(`Start Test ${this.currentTest?.title}`); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| teardown(async function () { | ||||||||||||||||||||||||||||||||||||||
| if (this.currentTest?.isFailed()) { | ||||||||||||||||||||||||||||||||||||||
| await captureScreenShot(this); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| logger.info(`Ended Test ${this.currentTest?.title}`); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| suiteTeardown(() => closeNotebooksAndCleanUpAfterTests(disposables)); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| test('Load .deepnote file', async () => { | ||||||||||||||||||||||||||||||||||||||
| const nbDocument = await workspace.openNotebookDocument(deepnoteFileUri); | ||||||||||||||||||||||||||||||||||||||
| assert.equal(nbDocument.notebookType, 'deepnote'); | ||||||||||||||||||||||||||||||||||||||
| assert.isAtLeast(nbDocument.cellCount, 1, 'Should have at least one cell'); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| test('Kernel starts for .deepnote file', async () => { | ||||||||||||||||||||||||||||||||||||||
| assert.isOk(kernel, 'Kernel should be created'); | ||||||||||||||||||||||||||||||||||||||
| assert.isOk(kernel.session, 'Kernel session should exist'); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| test('Execute code block with output validation', async function () { | ||||||||||||||||||||||||||||||||||||||
| this.timeout(defaultNotebookTestTimeout); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const cell = notebook.cells.find((c) => c.document.getText().includes('print("Hello World")')); | ||||||||||||||||||||||||||||||||||||||
| assert.isOk(cell, 'Should find cell with print statement'); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| await kernelExecution.executeCell(cell!); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| await waitForExecutionCompletedSuccessfully(cell!); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| assert.isTrue(cell!.executionSummary?.success, 'Cell execution should succeed'); | ||||||||||||||||||||||||||||||||||||||
| assert.isAtLeast(cell!.outputs.length, 0, 'Cell should have outputs'); | ||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Vacuous assertion; require at least one output. Length >= 0 is always true. - assert.isAtLeast(cell!.outputs.length, 0, 'Cell should have outputs');
+ assert.isAtLeast(cell!.outputs.length, 1, 'Cell should have outputs');📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const output = getCellOutputs(cell!); | ||||||||||||||||||||||||||||||||||||||
| assert.include(output, 'Hello World', 'Output should contain "Hello World"'); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| test('Execute multiple code blocks', async function () { | ||||||||||||||||||||||||||||||||||||||
| this.timeout(defaultNotebookTestTimeout); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const codeCells = notebook.cells.filter((c) => c.kind === 2); // Code cells | ||||||||||||||||||||||||||||||||||||||
| assert.isAtLeast(codeCells.length, 1, 'Should have at least one code cell'); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+127
to
+129
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong kind constant; this filters markup cells, not code. Use NotebookCellKind.Code. - const codeCells = notebook.cells.filter((c) => c.kind === 2); // Code cells
+ const codeCells = notebook.cells.filter((c) => c.kind === NotebookCellKind.Code); // Code cells📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| const firstCell = codeCells[0]; | ||||||||||||||||||||||||||||||||||||||
| await kernelExecution.executeCell(firstCell); | ||||||||||||||||||||||||||||||||||||||
| await waitForExecutionCompletedSuccessfully(firstCell); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| assert.isTrue(firstCell.executionSummary?.success, 'First cell execution should succeed'); | ||||||||||||||||||||||||||||||||||||||
| assert.isAtLeast(firstCell.executionSummary?.executionOrder || 0, 1, 'Should have execution order'); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| test('Verify cell execution order', async function () { | ||||||||||||||||||||||||||||||||||||||
| this.timeout(defaultNotebookTestTimeout); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const codeCells = notebook.cells.filter((c) => c.kind === 2 && c.document.getText().trim().length > 0); | ||||||||||||||||||||||||||||||||||||||
| if (codeCells.length < 2) { | ||||||||||||||||||||||||||||||||||||||
| this.skip(); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+141
to
+145
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue here; correct the code-cell filter. Use NotebookCellKind.Code and keep non-empty check. - const codeCells = notebook.cells.filter((c) => c.kind === 2 && c.document.getText().trim().length > 0);
+ const codeCells = notebook.cells.filter(
+ (c) => c.kind === NotebookCellKind.Code && c.document.getText().trim().length > 0
+ );📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| const cell1 = codeCells[0]; | ||||||||||||||||||||||||||||||||||||||
| const cell2 = codeCells[1]; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| await kernelExecution.executeCell(cell1); | ||||||||||||||||||||||||||||||||||||||
| await waitForExecutionCompletedSuccessfully(cell1); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| await kernelExecution.executeCell(cell2); | ||||||||||||||||||||||||||||||||||||||
| await waitForExecutionCompletedSuccessfully(cell2); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const order1 = cell1.executionSummary?.executionOrder || 0; | ||||||||||||||||||||||||||||||||||||||
| const order2 = cell2.executionSummary?.executionOrder || 0; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| assert.isAtLeast(order1, 1, 'First cell should have execution order'); | ||||||||||||||||||||||||||||||||||||||
| assert.isAtLeast(order2, order1 + 1, 'Second cell should have higher execution order'); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| metadata: | ||
| createdAt: '2025-01-01T00:00:00.000Z' | ||
| modifiedAt: '2025-01-01T00:00:00.000Z' | ||
| project: | ||
| id: test-project-id | ||
| name: Test Project | ||
| initNotebookId: init-notebook-id | ||
| notebooks: | ||
| - id: init-notebook-id | ||
| name: Init Notebook | ||
| blocks: | ||
| - id: init-block-1 | ||
| type: code | ||
| sortingKey: '0001' | ||
| content: | | ||
| # This is the init notebook | ||
| init_variable = "initialized" | ||
| print("Init notebook executed") | ||
| - id: main-notebook-id | ||
|
Comment on lines
+11
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Validate fixture schema against the deserializer; consider adding language for code blocks. If the deserializer keys differ (e.g., expects language), parsing may degrade. Add language to be explicit. blocks:
- id: init-block-1
type: code
+ language: python
sortingKey: '0001'
content: |
# This is the init notebook
init_variable = "initialized"
print("Init notebook executed")
@@
- id: block-1
type: code
+ language: python
sortingKey: '0001'
content: |
print("Hello World")
- id: block-2
type: code
+ language: python
sortingKey: '0002'
content: |
x = 42
print(f"The answer is {x}")Also applies to: 22-33 🤖 Prompt for AI Agents |
||
| name: Main Notebook | ||
| blocks: | ||
| - id: block-1 | ||
| type: code | ||
| sortingKey: '0001' | ||
| content: | | ||
| print("Hello World") | ||
| - id: block-2 | ||
| type: code | ||
| sortingKey: '0002' | ||
| content: | | ||
| x = 42 | ||
| print(f"The answer is {x}") | ||
| - id: block-3 | ||
| type: markdown | ||
| sortingKey: '0003' | ||
| content: | | ||
| # Test Markdown | ||
| This is a test markdown block. | ||
| version: '1.0' | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Ensure Jupyter is available on the runner.
Kernel startup will fail if Jupyter/ipykernel aren’t present. Install minimal deps before tests.
- name: Setup Python uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 with: python-version: '3.12' + - name: Install Python Jupyter deps + run: | + python -m pip install --upgrade pip + python -m pip install jupyter ipykernel + - name: Install dependencies run: npm ci --prefer-offline --no-audit env: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}Also applies to: 171-175
Length of output: 1472
🏁 Script executed:
Length of output: 389
🏁 Script executed:
Length of output: 457
🏁 Script executed:
Length of output: 2003
🏁 Script executed:
Length of output: 79
🏁 Script executed:
Length of output: 388
🏁 Script executed:
Length of output: 262776
🏁 Script executed:
Length of output: 280309
Install Jupyter + ipykernel on the runner before running tests.
Many tests start a Jupyter server or assert ipykernel is installed (startJupyterServer, multiple datascience tests). The workflow sets up Python but does not install Jupyter/ipykernel — kernel startup will fail during xvfb-run npm test. Add a step right after "Setup Python" to install minimal Python Jupyter deps (add jupyterlab if you need
jupyter lab):python -m pip install --upgrade pip
python -m pip install jupyter ipykernel
🤖 Prompt for AI Agents