@@ -42,6 +42,7 @@ import { 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,185 @@ 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+ } ) ;
592+ when (
593+ mockedVSCodeNamespaces . notebooks . createNotebookController (
594+ anything ( ) ,
595+ anything ( ) ,
596+ anything ( ) ,
597+ anything ( ) ,
598+ anything ( )
599+ )
600+ ) . thenReturn ( instance ( controller ) ) ;
601+ } ) ;
602+
603+ teardown ( ( ) => ( disposables = dispose ( disposables ) ) ) ;
604+
605+ test ( 'Should attach variable provider when API is available' , function ( ) {
606+ // Arrange: Mock controller with variableProvider property
607+ const controllerWithApi = mock < NotebookController > ( ) ;
608+ when ( controllerWithApi . onDidChangeSelectedNotebooks ) . thenReturn ( onDidChangeSelectedNotebooks . event ) ;
609+ ( instance ( controllerWithApi ) as any ) . variableProvider = undefined ;
610+
611+ when (
612+ mockedVSCodeNamespaces . notebooks . createNotebookController (
613+ anything ( ) ,
614+ anything ( ) ,
615+ anything ( ) ,
616+ anything ( ) ,
617+ anything ( )
618+ )
619+ ) . thenReturn ( instance ( controllerWithApi ) ) ;
620+
621+ // Act
622+ const result = VSCodeNotebookController . create (
623+ instance ( kernelConnection ) ,
624+ 'test-id' ,
625+ 'jupyter-notebook' ,
626+ instance ( kernelProvider ) ,
627+ instance ( context ) ,
628+ disposables ,
629+ instance ( languageService ) ,
630+ instance ( configService ) ,
631+ instance ( extensionChecker ) ,
632+ instance ( serviceContainer ) ,
633+ instance ( displayDataProvider ) ,
634+ instance ( jupyterVariablesProvider )
635+ ) ;
636+
637+ // Assert
638+ assert . isDefined ( result ) ;
639+ assert . strictEqual (
640+ ( result . controller as any ) . variableProvider ,
641+ instance ( jupyterVariablesProvider ) ,
642+ 'Variable provider should be attached when API is available'
643+ ) ;
644+ } ) ;
645+
646+ test ( 'Should not attach variable provider when API is not available' , function ( ) {
647+ // Arrange: Mock controller without variableProvider property
648+ const controllerWithoutApi = mock < NotebookController > ( ) ;
649+ when ( controllerWithoutApi . onDidChangeSelectedNotebooks ) . thenReturn ( onDidChangeSelectedNotebooks . event ) ;
650+ // Don't add variableProvider property to simulate API not being available
651+
652+ when (
653+ mockedVSCodeNamespaces . notebooks . createNotebookController (
654+ anything ( ) ,
655+ anything ( ) ,
656+ anything ( ) ,
657+ anything ( ) ,
658+ anything ( )
659+ )
660+ ) . thenReturn ( instance ( controllerWithoutApi ) ) ;
661+
662+ // Act
663+ const result = VSCodeNotebookController . create (
664+ instance ( kernelConnection ) ,
665+ 'test-id' ,
666+ 'jupyter-notebook' ,
667+ instance ( kernelProvider ) ,
668+ instance ( context ) ,
669+ disposables ,
670+ instance ( languageService ) ,
671+ instance ( configService ) ,
672+ instance ( extensionChecker ) ,
673+ instance ( serviceContainer ) ,
674+ instance ( displayDataProvider ) ,
675+ instance ( jupyterVariablesProvider )
676+ ) ;
677+
678+ // Assert
679+ assert . isDefined ( result ) ;
680+ assert . isUndefined (
681+ ( result . controller as any ) . variableProvider ,
682+ 'Variable provider should not be attached when API is not available'
683+ ) ;
684+ } ) ;
685+
686+ test ( 'Should handle errors when attaching variable provider' , function ( ) {
687+ // Arrange: Mock controller that throws when setting variableProvider
688+ const controllerWithError = mock < NotebookController > ( ) ;
689+ when ( controllerWithError . onDidChangeSelectedNotebooks ) . thenReturn ( onDidChangeSelectedNotebooks . event ) ;
690+
691+ const controllerInstance = instance ( controllerWithError ) ;
692+ Object . defineProperty ( controllerInstance , 'variableProvider' , {
693+ set : ( ) => {
694+ throw new Error ( 'API not supported' ) ;
695+ } ,
696+ configurable : true
697+ } ) ;
698+
699+ when (
700+ mockedVSCodeNamespaces . notebooks . createNotebookController (
701+ anything ( ) ,
702+ anything ( ) ,
703+ anything ( ) ,
704+ anything ( ) ,
705+ anything ( )
706+ )
707+ ) . thenReturn ( controllerInstance ) ;
708+
709+ // Act - should not throw
710+ const result = VSCodeNotebookController . create (
711+ instance ( kernelConnection ) ,
712+ 'test-id' ,
713+ 'jupyter-notebook' ,
714+ instance ( kernelProvider ) ,
715+ instance ( context ) ,
716+ disposables ,
717+ instance ( languageService ) ,
718+ instance ( configService ) ,
719+ instance ( extensionChecker ) ,
720+ instance ( serviceContainer ) ,
721+ instance ( displayDataProvider ) ,
722+ instance ( jupyterVariablesProvider )
723+ ) ;
724+
725+ // Assert
726+ assert . isDefined ( result ) ;
727+ } ) ;
728+ } ) ;
547729} ) ;
0 commit comments