@@ -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,191 @@ 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: Mock controller without variableProvider property
654+ const controllerWithoutApi = mock < NotebookController > ( ) ;
655+ when ( controllerWithoutApi . onDidChangeSelectedNotebooks ) . thenReturn ( onDidChangeSelectedNotebooks . event ) ;
656+ // Don't add variableProvider property to simulate API not being available
657+
658+ when (
659+ mockedVSCodeNamespaces . notebooks . createNotebookController (
660+ anything ( ) ,
661+ anything ( ) ,
662+ anything ( ) ,
663+ anything ( ) ,
664+ anything ( )
665+ )
666+ ) . thenReturn ( instance ( controllerWithoutApi ) ) ;
667+
668+ // Act
669+ const result = VSCodeNotebookController . create (
670+ instance ( kernelConnection ) ,
671+ 'test-id' ,
672+ 'jupyter-notebook' ,
673+ instance ( kernelProvider ) ,
674+ instance ( context ) ,
675+ disposables ,
676+ instance ( languageService ) ,
677+ instance ( configService ) ,
678+ instance ( extensionChecker ) ,
679+ instance ( serviceContainer ) ,
680+ instance ( displayDataProvider ) ,
681+ instance ( jupyterVariablesProvider )
682+ ) ;
683+
684+ // Assert
685+ assert . isDefined ( result ) ;
686+ assert . isUndefined (
687+ ( result . controller as any ) . variableProvider ,
688+ 'Variable provider should not be attached when API is not available'
689+ ) ;
690+ } ) ;
691+
692+ test ( 'Should handle errors when attaching variable provider' , function ( ) {
693+ // Arrange: Mock controller that throws when setting variableProvider
694+ const controllerWithError = mock < NotebookController > ( ) ;
695+ when ( controllerWithError . onDidChangeSelectedNotebooks ) . thenReturn ( onDidChangeSelectedNotebooks . event ) ;
696+
697+ const controllerInstance = instance ( controllerWithError ) ;
698+ Object . defineProperty ( controllerInstance , 'variableProvider' , {
699+ set : ( ) => {
700+ throw new Error ( 'API not supported' ) ;
701+ } ,
702+ configurable : true
703+ } ) ;
704+
705+ when (
706+ mockedVSCodeNamespaces . notebooks . createNotebookController (
707+ anything ( ) ,
708+ anything ( ) ,
709+ anything ( ) ,
710+ anything ( ) ,
711+ anything ( )
712+ )
713+ ) . thenReturn ( controllerInstance ) ;
714+
715+ // Act - should not throw
716+ const result = VSCodeNotebookController . create (
717+ instance ( kernelConnection ) ,
718+ 'test-id' ,
719+ 'jupyter-notebook' ,
720+ instance ( kernelProvider ) ,
721+ instance ( context ) ,
722+ disposables ,
723+ instance ( languageService ) ,
724+ instance ( configService ) ,
725+ instance ( extensionChecker ) ,
726+ instance ( serviceContainer ) ,
727+ instance ( displayDataProvider ) ,
728+ instance ( jupyterVariablesProvider )
729+ ) ;
730+
731+ // Assert
732+ assert . isDefined ( result ) ;
733+ } ) ;
734+ } ) ;
547735} ) ;
0 commit comments