@@ -18,7 +18,7 @@ import { IDisposableRegistry, Product } from '../common/types';
1818import { IInterpreterService } from '../interpreter/contracts' ;
1919import { IServiceContainer } from '../ioc/types' ;
2020import { EventName } from '../telemetry/constants' ;
21- import { captureTelemetry , sendTelemetryEvent } from '../telemetry/index' ;
21+ import { sendTelemetryEvent } from '../telemetry/index' ;
2222import { selectTestWorkspace } from './common/testUtils' ;
2323import { TestSettingsPropertyNames } from './configuration/types' ;
2424import { ITestConfigurationService , ITestsHelper } from './common/types' ;
@@ -43,25 +43,21 @@ export class TestingService implements ITestingService {
4343}
4444
4545/**
46- * Registers test commands early in the extension activation to prevent race conditions.
47- * This function should be called synchronously before any async operations in the activation flow .
46+ * Registers command handlers but defers service resolution until the commands are actually invoked,
47+ * allowing registration to happen before all services are fully initialized .
4848 */
4949export function registerTestCommands ( serviceContainer : IServiceContainer ) : void {
50+ // Resolve only the essential services needed for command registration itself
5051 const disposableRegistry = serviceContainer . get < Disposable [ ] > ( IDisposableRegistry ) ;
5152 const commandManager = serviceContainer . get < ICommandManager > ( ICommandManager ) ;
52- const workspaceService = serviceContainer . get < IWorkspaceService > ( IWorkspaceService ) ;
53-
54- // Get test controller if available
55- let testController : ITestController | undefined ;
56- if ( tests && ! ! tests . createTestController ) {
57- testController = serviceContainer . get < ITestController > ( ITestController ) ;
58- }
5953
60- // Helper function to configure tests
54+ // Helper function to configure tests - services are resolved when invoked, not at registration time
6155 const configureTestsHandler = async ( resource ?: Uri ) => {
62- // Send telemetry for test configuration
6356 sendTelemetryEvent ( EventName . UNITTEST_CONFIGURE ) ;
64-
57+
58+ // Resolve services lazily when the command is invoked
59+ const workspaceService = serviceContainer . get < IWorkspaceService > ( IWorkspaceService ) ;
60+
6561 let wkspace : Uri | undefined ;
6662 if ( resource ) {
6763 const wkspaceFolder = workspaceService . getWorkspaceFolder ( resource ) ;
@@ -84,28 +80,33 @@ export function registerTestCommands(serviceContainer: IServiceContainer): void
8480 } ;
8581
8682 disposableRegistry . push (
83+ // Command: python.configureTests - prompts user to configure test framework
8784 commandManager . registerCommand (
8885 constants . Commands . Tests_Configure ,
8986 ( _ , _cmdSource : constants . CommandSource = constants . CommandSource . commandPalette , resource ?: Uri ) => {
90- // Ignore the exceptions returned.
91- // This command will be invoked from other places of the extension.
87+ // Invoke configuration handler (errors are ignored as this can be called from multiple places)
9288 configureTestsHandler ( resource ) . ignoreErrors ( ) ;
9389 traceVerbose ( 'Testing: Trigger refresh after config change' ) ;
94- testController ?. refreshTestData ( resource , { forceRefresh : true } ) ;
90+ // Refresh test data if test controller is available (resolved lazily)
91+ if ( tests && ! ! tests . createTestController ) {
92+ const testController = serviceContainer . get < ITestController > ( ITestController ) ;
93+ testController ?. refreshTestData ( resource , { forceRefresh : true } ) ;
94+ }
9595 } ,
9696 ) ,
97+ // Command: python.tests.copilotSetup - Copilot integration for test setup
9798 commandManager . registerCommand ( constants . Commands . Tests_CopilotSetup , ( resource ?: Uri ) :
9899 | { message : string ; command : Command }
99100 | undefined => {
101+ // Resolve services lazily when the command is invoked
102+ const workspaceService = serviceContainer . get < IWorkspaceService > ( IWorkspaceService ) ;
100103 const wkspaceFolder =
101104 workspaceService . getWorkspaceFolder ( resource ) || workspaceService . workspaceFolders ?. at ( 0 ) ;
102105 if ( ! wkspaceFolder ) {
103106 return undefined ;
104107 }
105108
106- const configurationService = serviceContainer . get < ITestConfigurationService > (
107- ITestConfigurationService ,
108- ) ;
109+ const configurationService = serviceContainer . get < ITestConfigurationService > ( ITestConfigurationService ) ;
109110 if ( configurationService . hasConfiguredTests ( wkspaceFolder . uri ) ) {
110111 return undefined ;
111112 }
@@ -119,6 +120,7 @@ export function registerTestCommands(serviceContainer: IServiceContainer): void
119120 } ,
120121 } ;
121122 } ) ,
123+ // Command: python.copyTestId - copies test ID to clipboard
122124 commandManager . registerCommand ( constants . Commands . CopyTestId , async ( testItem : TestItem ) => {
123125 writeTestIdToClipboard ( testItem ) ;
124126 } ) ,
@@ -163,8 +165,6 @@ export class UnitTestManagementService implements IExtensionActivationService {
163165 this . activatedOnce = true ;
164166
165167 this . registerHandlers ( ) ;
166- // Note: Commands are now registered early in extensionActivation.ts via registerTestCommands()
167- // to avoid race conditions where commands are invoked before extension activation completes.
168168
169169 if ( ! ! tests . testResults ) {
170170 await this . updateTestUIButtons ( ) ;
@@ -214,8 +214,6 @@ export class UnitTestManagementService implements IExtensionActivationService {
214214 await Promise . all ( changedWorkspaces . map ( ( u ) => this . testController ?. refreshTestData ( u ) ) ) ;
215215 }
216216
217-
218-
219217 private registerHandlers ( ) {
220218 const interpreterService = this . serviceContainer . get < IInterpreterService > ( IInterpreterService ) ;
221219 this . disposableRegistry . push (
0 commit comments