@@ -37,11 +37,12 @@ import { KernelConnector } from './kernelConnector';
3737import { ITrustedKernelPaths } from '../../kernels/raw/finder/types' ;
3838import { IInterpreterService } from '../../platform/interpreter/contracts' ;
3939import { PythonEnvironment } from '../../platform/pythonEnvironments/info' ;
40- import { IConnectionDisplayDataProvider } from './types' ;
40+ import { IConnectionDisplayData , IConnectionDisplayDataProvider } from './types' ;
4141import { ConnectionDisplayDataProvider } from './connectionDisplayData.node' ;
4242import { mockedVSCodeNamespaces , resetVSCodeMocks } from '../../test/vscode-mock' ;
4343import { Environment , PythonExtension } from '@vscode/python-extension' ;
4444import { crateMockedPythonApi , whenResolveEnvironment } from '../../kernels/helpers.unit.test' ;
45+ import { IJupyterVariablesProvider } from '../../kernels/variables/types' ;
4546
4647suite ( `Notebook Controller` , function ( ) {
4748 let controller : NotebookController ;
@@ -544,4 +545,215 @@ suite(`Notebook Controller`, function () {
544545 } ) ;
545546 } ) ;
546547 } ) ;
548+
549+ suite ( 'VSCodeNotebookController.create' , function ( ) {
550+ let kernelConnection : KernelConnectionMetadata ;
551+ let kernelProvider : IKernelProvider ;
552+ let context : IExtensionContext ;
553+ let languageService : NotebookCellLanguageService ;
554+ let configService : IConfigurationService ;
555+ let extensionChecker : IPythonExtensionChecker ;
556+ let serviceContainer : IServiceContainer ;
557+ let displayDataProvider : IConnectionDisplayDataProvider ;
558+ let jupyterVariablesProvider : IJupyterVariablesProvider ;
559+ let disposables : IDisposable [ ] = [ ] ;
560+ let controller : NotebookController ;
561+ let onDidChangeSelectedNotebooks : EventEmitter < {
562+ readonly notebook : NotebookDocument ;
563+ readonly selected : boolean ;
564+ } > ;
565+
566+ setup ( function ( ) {
567+ resetVSCodeMocks ( ) ;
568+ disposables . push ( new Disposable ( ( ) => resetVSCodeMocks ( ) ) ) ;
569+ kernelConnection = mock < KernelConnectionMetadata > ( ) ;
570+ kernelProvider = mock < IKernelProvider > ( ) ;
571+ context = mock < IExtensionContext > ( ) ;
572+ languageService = mock < NotebookCellLanguageService > ( ) ;
573+ configService = mock < IConfigurationService > ( ) ;
574+ extensionChecker = mock < IPythonExtensionChecker > ( ) ;
575+ serviceContainer = mock < IServiceContainer > ( ) ;
576+ displayDataProvider = mock < IConnectionDisplayDataProvider > ( ) ;
577+ jupyterVariablesProvider = mock < IJupyterVariablesProvider > ( ) ;
578+ controller = mock < NotebookController > ( ) ;
579+ onDidChangeSelectedNotebooks = new EventEmitter < {
580+ readonly notebook : NotebookDocument ;
581+ readonly selected : boolean ;
582+ } > ( ) ;
583+ disposables . push ( onDidChangeSelectedNotebooks ) ;
584+
585+ when ( context . extensionUri ) . thenReturn ( Uri . file ( 'extension' ) ) ;
586+ when ( controller . onDidChangeSelectedNotebooks ) . thenReturn ( onDidChangeSelectedNotebooks . event ) ;
587+ when ( displayDataProvider . getDisplayData ( anything ( ) ) ) . thenReturn ( {
588+ label : 'Test Kernel' ,
589+ description : 'Test Description' ,
590+ detail : 'Test Detail' ,
591+ category : 'Test Category' ,
592+ serverDisplayName : 'Test Server' ,
593+ onDidChange : new EventEmitter < IConnectionDisplayData > ( ) . event ,
594+ dispose : ( ) => {
595+ /* noop */
596+ }
597+ } ) ;
598+ when (
599+ mockedVSCodeNamespaces . notebooks . createNotebookController (
600+ anything ( ) ,
601+ anything ( ) ,
602+ anything ( ) ,
603+ anything ( ) ,
604+ anything ( )
605+ )
606+ ) . thenReturn ( instance ( controller ) ) ;
607+ } ) ;
608+
609+ teardown ( ( ) => ( disposables = dispose ( disposables ) ) ) ;
610+
611+ test ( 'Should attach variable provider when API is available' , function ( ) {
612+ // Arrange: Mock controller with variableProvider property
613+ const controllerWithApi = mock < NotebookController > ( ) ;
614+ when ( controllerWithApi . onDidChangeSelectedNotebooks ) . thenReturn ( onDidChangeSelectedNotebooks . event ) ;
615+ ( instance ( controllerWithApi ) as any ) . variableProvider = undefined ;
616+
617+ when (
618+ mockedVSCodeNamespaces . notebooks . createNotebookController (
619+ anything ( ) ,
620+ anything ( ) ,
621+ anything ( ) ,
622+ anything ( ) ,
623+ anything ( )
624+ )
625+ ) . thenReturn ( instance ( controllerWithApi ) ) ;
626+
627+ // Act
628+ const result = VSCodeNotebookController . create (
629+ instance ( kernelConnection ) ,
630+ 'test-id' ,
631+ 'jupyter-notebook' ,
632+ instance ( kernelProvider ) ,
633+ instance ( context ) ,
634+ disposables ,
635+ instance ( languageService ) ,
636+ instance ( configService ) ,
637+ instance ( extensionChecker ) ,
638+ instance ( serviceContainer ) ,
639+ instance ( displayDataProvider ) ,
640+ instance ( jupyterVariablesProvider )
641+ ) ;
642+
643+ // Assert
644+ assert . isDefined ( result ) ;
645+ assert . strictEqual (
646+ ( result . controller as any ) . variableProvider ,
647+ instance ( jupyterVariablesProvider ) ,
648+ 'Variable provider should be attached when API is available'
649+ ) ;
650+ } ) ;
651+
652+ test ( 'Should not attach variable provider when API is not available' , function ( ) {
653+ // Arrange: Create a plain object without variableProvider property
654+ const controllerWithoutApi = {
655+ onDidChangeSelectedNotebooks : onDidChangeSelectedNotebooks . event ,
656+ id : 'test-id' ,
657+ notebookType : 'jupyter-notebook' ,
658+ supportedLanguages : [ ] ,
659+ supportsExecutionOrder : true ,
660+ description : '' ,
661+ detail : '' ,
662+ label : 'Test Kernel' ,
663+ dispose : ( ) => {
664+ /* noop */
665+ } ,
666+ createNotebookCellExecution : ( ) => ( { } ) as any ,
667+ createNotebookExecution : ( ) => ( { } ) as any ,
668+ executeHandler : ( ) => {
669+ /* noop */
670+ } ,
671+ interruptHandler : undefined ,
672+ updateNotebookAffinity : ( ) => {
673+ /* noop */
674+ } ,
675+ rendererScripts : [ ] ,
676+ onDidReceiveMessage : new EventEmitter < any > ( ) . event ,
677+ postMessage : ( ) => Promise . resolve ( true ) ,
678+ asWebviewUri : ( uri : Uri ) => uri
679+ // Note: no variableProvider property to simulate API not being available
680+ } as NotebookController ;
681+
682+ when (
683+ mockedVSCodeNamespaces . notebooks . createNotebookController (
684+ anything ( ) ,
685+ anything ( ) ,
686+ anything ( ) ,
687+ anything ( ) ,
688+ anything ( )
689+ )
690+ ) . thenReturn ( controllerWithoutApi ) ;
691+
692+ // Act
693+ const result = VSCodeNotebookController . create (
694+ instance ( kernelConnection ) ,
695+ 'test-id' ,
696+ 'jupyter-notebook' ,
697+ instance ( kernelProvider ) ,
698+ instance ( context ) ,
699+ disposables ,
700+ instance ( languageService ) ,
701+ instance ( configService ) ,
702+ instance ( extensionChecker ) ,
703+ instance ( serviceContainer ) ,
704+ instance ( displayDataProvider ) ,
705+ instance ( jupyterVariablesProvider )
706+ ) ;
707+
708+ // Assert
709+ assert . isDefined ( result ) ;
710+ assert . isFalse (
711+ 'variableProvider' in result . controller ,
712+ 'Variable provider property should not exist when API is not available'
713+ ) ;
714+ } ) ;
715+
716+ test ( 'Should handle errors when attaching variable provider' , function ( ) {
717+ // Arrange: Mock controller that throws when setting variableProvider
718+ const controllerWithError = mock < NotebookController > ( ) ;
719+ when ( controllerWithError . onDidChangeSelectedNotebooks ) . thenReturn ( onDidChangeSelectedNotebooks . event ) ;
720+
721+ const controllerInstance = instance ( controllerWithError ) ;
722+ Object . defineProperty ( controllerInstance , 'variableProvider' , {
723+ set : ( ) => {
724+ throw new Error ( 'API not supported' ) ;
725+ } ,
726+ configurable : true
727+ } ) ;
728+
729+ when (
730+ mockedVSCodeNamespaces . notebooks . createNotebookController (
731+ anything ( ) ,
732+ anything ( ) ,
733+ anything ( ) ,
734+ anything ( ) ,
735+ anything ( )
736+ )
737+ ) . thenReturn ( controllerInstance ) ;
738+
739+ // Act - should not throw
740+ const result = VSCodeNotebookController . create (
741+ instance ( kernelConnection ) ,
742+ 'test-id' ,
743+ 'jupyter-notebook' ,
744+ instance ( kernelProvider ) ,
745+ instance ( context ) ,
746+ disposables ,
747+ instance ( languageService ) ,
748+ instance ( configService ) ,
749+ instance ( extensionChecker ) ,
750+ instance ( serviceContainer ) ,
751+ instance ( displayDataProvider ) ,
752+ instance ( jupyterVariablesProvider )
753+ ) ;
754+
755+ // Assert
756+ assert . isDefined ( result ) ;
757+ } ) ;
758+ } ) ;
547759} ) ;
0 commit comments