@@ -141,9 +141,13 @@ class TestExtensionLoader extends ExtensionLoader {
141141
142142let extensionLoader : TestExtensionLoader ;
143143
144- const commandRegistry : CommandRegistry = { } as unknown as CommandRegistry ;
144+ const commandRegistry : CommandRegistry = {
145+ registerCommandsFromExtension : vi . fn ( ) ,
146+ } as unknown as CommandRegistry ;
145147
146- const menuRegistry : MenuRegistry = { } as unknown as MenuRegistry ;
148+ const menuRegistry : MenuRegistry = {
149+ registerMenus : vi . fn ( ) ,
150+ } as unknown as MenuRegistry ;
147151
148152const kubernetesGeneratorRegistry : KubeGeneratorRegistry = { } as unknown as KubeGeneratorRegistry ;
149153
@@ -213,16 +217,21 @@ const authenticationProviderRegistry: AuthenticationImpl = {
213217 registerAuthenticationProvider : vi . fn ( ) ,
214218} as unknown as AuthenticationImpl ;
215219
216- const iconRegistry : IconRegistry = { } as unknown as IconRegistry ;
220+ const iconRegistry : IconRegistry = {
221+ registerIconContribution : vi . fn ( ) ,
222+ } as unknown as IconRegistry ;
217223
218224const onboardingRegistry : OnboardingRegistry = {
219225 getOnboarding : vi . fn ( ) ,
226+ registerOnboarding : vi . fn ( ) ,
220227} as unknown as OnboardingRegistry ;
221228
222229const telemetryTrackMock = vi . fn ( ) ;
223230const telemetry : Telemetry = { aggregateTrack : vi . fn ( ) , track : telemetryTrackMock } as unknown as Telemetry ;
224231
225- const viewRegistry : ViewRegistry = { } as unknown as ViewRegistry ;
232+ const viewRegistry : ViewRegistry = {
233+ registerViews : vi . fn ( ) ,
234+ } as unknown as ViewRegistry ;
226235
227236const context : Context = new Context ( apiSender ) ;
228237
@@ -400,6 +409,14 @@ beforeEach(() => {
400409 telemetryTrackMock . mockResolvedValue ( undefined ) ;
401410 vi . clearAllMocks ( ) ;
402411
412+ configurationRegistryGetConfigurationMock . mockReturnValue ( {
413+ get : vi . fn ( ) . mockImplementation ( ( key : string , defaultValue ?: unknown ) => {
414+ if ( key === 'disabled' ) {
415+ return [ ] ;
416+ }
417+ return defaultValue ;
418+ } ) ,
419+ } ) ;
403420 vi . mocked ( extensionDevelopmentFolder ) . getDevelopmentFolders . mockReturnValue ( [ ] ) ;
404421} ) ;
405422
@@ -733,18 +750,113 @@ test('Verify extension load', async () => {
733750 dispose : vi . fn ( ) ,
734751 } ) ;
735752
736- expect ( telemetry . track ) . toBeCalledWith (
737- 'loadExtension.error' ,
738- expect . objectContaining ( { extensionId : id , extensionVersion : '1.1' } ) ,
739- ) ;
740-
741753 expect ( extensionDevelopmentFolder . addExternalExtensionId ) . toBeCalledWith ( id ) ;
742754
743755 // remove extension
744756 await extensionLoader . removeExtension ( id ) ;
745757 expect ( extensionDevelopmentFolder . removeExternalExtensionId ) . toBeCalledWith ( id ) ;
746758} ) ;
747759
760+ test ( 'Verify disabled extension skips registering contributions and runtime activation' , async ( ) => {
761+ const id = 'extension.disabled' ;
762+
763+ configurationRegistryGetConfigurationMock . mockReturnValue ( {
764+ get : vi . fn ( ) . mockImplementation ( ( key : string , defaultValue ?: unknown ) => {
765+ if ( key === 'disabled' ) {
766+ return [ id ] ;
767+ }
768+ return defaultValue ;
769+ } ) ,
770+ } ) ;
771+
772+ const loadRuntimeSpy = vi . spyOn ( extensionLoader , 'loadRuntime' as keyof TestExtensionLoader ) ;
773+
774+ const subscriptions : IDisposable [ ] = [ ] ;
775+
776+ await extensionLoader . loadExtension ( {
777+ id : id ,
778+ name : 'disabled-ext' ,
779+ path : 'dummy' ,
780+ api : { } as typeof containerDesktopAPI ,
781+ mainPath : 'main.js' ,
782+ removable : true ,
783+ devMode : false ,
784+ manifest : {
785+ version : '1.0' ,
786+ contributes : {
787+ commands : [ { command : 'ext.cmd' , title : 'Test Command' } ] ,
788+ menus : { 'dashboard/image' : [ { command : 'ext.cmd' } ] } ,
789+ icons : { 'ext-icon' : { default : 'icon.png' } } ,
790+ themes : [ { id : 'ext-theme' , name : 'Theme' , parent : 'dark' , colors : { } } ] ,
791+ views : { icons : [ { id : 'ext-view' , name : 'View' , when : '' } ] } ,
792+ onboarding : { title : 'Onboarding' , steps : [ ] } ,
793+ } ,
794+ } as unknown as ExtensionManifest ,
795+ subscriptions : subscriptions ,
796+ readme : '' ,
797+ dispose : vi . fn ( ) ,
798+ } ) ;
799+
800+ expect ( commandRegistry . registerCommandsFromExtension ) . not . toHaveBeenCalled ( ) ;
801+ expect ( menuRegistry . registerMenus ) . not . toHaveBeenCalled ( ) ;
802+ expect ( iconRegistry . registerIconContribution ) . not . toHaveBeenCalled ( ) ;
803+ expect ( colorRegistry . registerExtensionThemes ) . not . toHaveBeenCalled ( ) ;
804+ expect ( viewRegistry . registerViews ) . not . toHaveBeenCalled ( ) ;
805+ expect ( onboardingRegistry . registerOnboarding ) . not . toHaveBeenCalled ( ) ;
806+ expect ( notificationRegistry . registerExtension ) . not . toHaveBeenCalled ( ) ;
807+
808+ expect ( loadRuntimeSpy ) . not . toHaveBeenCalled ( ) ;
809+ } ) ;
810+
811+ test ( 'Verify enabled extension registers contributions and activates runtime' , async ( ) => {
812+ const id = 'extension.enabled' ;
813+
814+ vi . mocked ( commandRegistry . registerCommandsFromExtension ) . mockReturnValue ( Disposable . create ( ( ) => { } ) ) ;
815+ vi . mocked ( menuRegistry . registerMenus ) . mockReturnValue ( Disposable . create ( ( ) => { } ) ) ;
816+ vi . mocked ( colorRegistry . registerExtensionThemes ) . mockReturnValue ( Disposable . create ( ( ) => { } ) ) ;
817+ vi . mocked ( viewRegistry . registerViews ) . mockReturnValue ( Disposable . create ( ( ) => { } ) ) ;
818+ vi . mocked ( onboardingRegistry . registerOnboarding ) . mockReturnValue ( Disposable . create ( ( ) => { } ) ) ;
819+ vi . mocked ( notificationRegistry . registerExtension ) . mockReturnValue ( Disposable . create ( ( ) => { } ) ) ;
820+
821+ const subscriptions : IDisposable [ ] = [ ] ;
822+
823+ await extensionLoader . loadExtension ( {
824+ id : id ,
825+ name : 'enabled-ext' ,
826+ path : 'dummy' ,
827+ api : { } as typeof containerDesktopAPI ,
828+ mainPath : '' ,
829+ removable : true ,
830+ devMode : false ,
831+ manifest : {
832+ version : '1.0' ,
833+ contributes : {
834+ commands : [ { command : 'ext.cmd' , title : 'Test Command' } ] ,
835+ menus : { 'dashboard/image' : [ { command : 'ext.cmd' } ] } ,
836+ icons : { 'ext-icon' : { default : 'icon.png' } } ,
837+ themes : [ { id : 'ext-theme' , name : 'Theme' , parent : 'dark' , colors : { } } ] ,
838+ views : { icons : [ { id : 'ext-view' , name : 'View' , when : '' } ] } ,
839+ onboarding : { title : 'Onboarding' , steps : [ ] } ,
840+ } ,
841+ } as unknown as ExtensionManifest ,
842+ subscriptions : subscriptions ,
843+ readme : '' ,
844+ dispose : vi . fn ( ) ,
845+ } ) ;
846+
847+ expect ( commandRegistry . registerCommandsFromExtension ) . toHaveBeenCalledWith ( id , [
848+ { command : 'ext.cmd' , title : 'Test Command' } ,
849+ ] ) ;
850+ expect ( menuRegistry . registerMenus ) . toHaveBeenCalledWith ( { 'dashboard/image' : [ { command : 'ext.cmd' } ] } ) ;
851+ expect ( iconRegistry . registerIconContribution ) . toHaveBeenCalled ( ) ;
852+ expect ( colorRegistry . registerExtensionThemes ) . toHaveBeenCalled ( ) ;
853+ expect ( viewRegistry . registerViews ) . toHaveBeenCalledWith ( id , {
854+ icons : [ { id : 'ext-view' , name : 'View' , when : '' } ] ,
855+ } ) ;
856+ expect ( onboardingRegistry . registerOnboarding ) . toHaveBeenCalled ( ) ;
857+ expect ( notificationRegistry . registerExtension ) . toHaveBeenCalledWith ( id ) ;
858+ } ) ;
859+
748860test ( 'Verify extension do not add configuration to subscriptions' , async ( ) => {
749861 const id = 'extension.foo' ;
750862
0 commit comments