Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,12 @@
"args": "none"
}
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/prefer-nullish-coalescing": "error",
"@typescript-eslint/quotes": [
"error",
"single",
Expand Down
89 changes: 89 additions & 0 deletions src/__tests__/NotebookPicker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { framePromise } from '@jupyterlab/testing';
import { NotebookPanel } from '@jupyterlab/notebook';
import { INotebookModel } from '@jupyterlab/notebook';
import { Widget } from '@lumino/widgets';
import { Message } from '@lumino/messaging';
import { simulate } from 'simulate-event';

describe('NotebookPicker', () => {
Expand Down Expand Up @@ -108,4 +109,92 @@ describe('NotebookPicker', () => {
expect(select.options.length).toBeGreaterThanOrEqual(1);
expect(select.options[0] && select.options[0].value).toBe('-');
});

it('should handle context.ready rejection gracefully', async () => {
const consoleErrorSpy = jest
.spyOn(console, 'error')
.mockImplementation(() => {});
const errorPanel = {
context: {
ready: Promise.reject(new Error('Failed to initialize')),
model: {
getMetadata: jest.fn()
}
},
model
} as any;

document.body.innerHTML = '';
const widget = new NotebookPicker(errorPanel);
(widget as any).onAfterAttach = jest.fn();
Widget.attach(widget, document.body);
await framePromise();

await new Promise(resolve => setTimeout(resolve, 10));

expect(consoleErrorSpy).toHaveBeenCalledWith(
'Failed to initialize NotebookPicker:',
expect.any(Error)
);

consoleErrorSpy.mockRestore();
});

it('should handle null model in handleChange', async () => {
const nullModelPanel = {
context: {
ready: Promise.resolve(),
model: {
getMetadata: jest.fn().mockReturnValue({
notebooks: {
nb1: { id: 'nb1', name: 'nb1', cells: [] }
},
notebook_names: ['nb1']
})
}
},
model: null
} as any;

document.body.innerHTML = '';
const widget = new NotebookPicker(nullModelPanel);
(widget as any).onAfterAttach = jest.fn();
Widget.attach(widget, document.body);
await framePromise();

const select = document.querySelector('select') as HTMLSelectElement;
simulate(select, 'change', { target: { value: 'nb1' } });
await framePromise();
});

it('should handle invalid metadata in handleChange', async () => {
const consoleErrorSpy = jest
.spyOn(console, 'error')
.mockImplementation(() => {});
const getMetadata = panel.context.model.getMetadata as jest.Mock;
getMetadata.mockReturnValue({ invalid: 'metadata' });

const select = document.querySelector('select') as HTMLSelectElement;
simulate(select, 'change', { target: { value: 'nb1' } });
await framePromise();

expect(consoleErrorSpy).toHaveBeenCalledWith(
'Invalid deepnote metadata:',
expect.anything()
);
expect(model.fromJSON).not.toHaveBeenCalled();

consoleErrorSpy.mockRestore();
});

it('should handle onAfterAttach without parent', async () => {
document.body.innerHTML = '';
const widget = new NotebookPicker(panel);
Widget.attach(widget, document.body);
await framePromise();

const onAfterAttachMethod = (widget as any).onAfterAttach.bind(widget);
onAfterAttachMethod({} as Message);
await new Promise(resolve => requestAnimationFrame(resolve));
});
});
Loading