@@ -868,36 +868,18 @@ suite('Interpreter Selection - applyInitialEnvironmentSelection', () => {
868868
869869 const showWarnStub = sandbox . stub ( windowApis , 'showWarningMessage' ) . resolves ( undefined ) ;
870870
871- // Block setEnvironments so we can control when global scope completes
872- let resolveSetEnvironments : ( ) => void ;
873- const setEnvironmentsPromise = new Promise < void > ( ( resolve ) => {
874- resolveSetEnvironments = resolve ;
875- } ) ;
876- mockEnvManagers . setEnvironments . callsFake ( async ( ) => {
877- await setEnvironmentsPromise ;
878- } ) ;
879-
880- let functionReturned = false ;
881- const resultPromise = applyInitialEnvironmentSelection (
871+ await applyInitialEnvironmentSelection (
882872 mockEnvManagers as unknown as EnvironmentManagers ,
883873 mockProjectManager as unknown as PythonProjectManager ,
884874 mockNativeFinder as unknown as NativePythonFinder ,
885875 mockApi as unknown as PythonEnvironmentApi ,
886- ) . then ( ( ) => {
887- functionReturned = true ;
888- } ) ;
889-
890- // Yield to microtasks — in deferred path, function should return
891- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
892- assert . ok ( functionReturned , 'Function should return before global scope completes (deferred path)' ) ;
876+ ) ;
893877
894878 // Workspace folder should resolve (venv found)
895879 assert . ok ( mockEnvManagers . setEnvironment . called , 'setEnvironment should be called for workspace folder' ) ;
896880
897- // Unblock global scope and let it finish
898- resolveSetEnvironments ! ( ) ;
899- await resultPromise ;
900- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
881+ // Wait a tick for the background global scope to complete
882+ await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) ) ;
901883
902884 // Global scope should still resolve (falls to auto-discovery) and show warning
903885 assert . ok ( mockEnvManagers . setEnvironments . called , 'setEnvironments should be called for global scope' ) ;
@@ -914,126 +896,30 @@ suite('Interpreter Selection - applyInitialEnvironmentSelection', () => {
914896 sandbox . stub ( workspaceApis , 'getConfiguration' ) . returns ( createMockConfig ( [ ] ) as WorkspaceConfiguration ) ;
915897 sandbox . stub ( helpers , 'getUserConfiguredSetting' ) . returns ( undefined ) ;
916898
917- // Block setEnvironments until we reject it, simulating a crash
918- let rejectSetEnvironments : ( err : Error ) => void ;
919- const setEnvironmentsPromise = new Promise < void > ( ( _resolve , reject ) => {
920- rejectSetEnvironments = reject ;
921- } ) ;
922- mockEnvManagers . setEnvironments . callsFake ( async ( ) => {
923- await setEnvironmentsPromise ;
924- } ) ;
899+ // Make setEnvironments throw — simulating a crash in global scope
900+ mockEnvManagers . setEnvironments . rejects ( new Error ( 'Simulated global scope crash' ) ) ;
925901
926- let functionReturned = false ;
927- const resultPromise = applyInitialEnvironmentSelection (
902+ // Should NOT throw — errors are caught inside resolveGlobalScope
903+ await applyInitialEnvironmentSelection (
928904 mockEnvManagers as unknown as EnvironmentManagers ,
929905 mockProjectManager as unknown as PythonProjectManager ,
930906 mockNativeFinder as unknown as NativePythonFinder ,
931907 mockApi as unknown as PythonEnvironmentApi ,
932- ) . then ( ( ) => {
933- functionReturned = true ;
934- } ) ;
908+ ) ;
935909
936- // Yield to microtasks — in deferred path, function should return
937- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
938- assert . ok ( functionReturned , 'Function should return before global scope completes (deferred path)' ) ;
910+ // Wait a tick for the background global scope to complete
911+ await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) ) ;
939912
940- // Workspace folder should have resolved
913+ // Workspace folder should still have resolved
941914 assert . ok ( mockEnvManagers . setEnvironment . called , 'setEnvironment should be called for workspace folder' ) ;
942915
943- // Trigger the crash and let it propagate through the catch chain
944- rejectSetEnvironments ! ( new Error ( 'Simulated global scope crash' ) ) ;
945- await resultPromise ;
946- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
947-
948916 // setEnvironments was called (and threw), proving the global scope was attempted
949917 assert . ok (
950918 mockEnvManagers . setEnvironments . called ,
951919 'setEnvironments should have been attempted for global scope' ,
952920 ) ;
953921 } ) ;
954922
955- test ( 'should defer global scope when workspace folder resolves with env' , async ( ) => {
956- // Core deferral test: when a workspace folder resolves with an environment,
957- // applyInitialEnvironmentSelection should return BEFORE setEnvironments completes
958- // for the global scope. This verifies the fire-and-forget optimization.
959- sandbox . stub ( workspaceApis , 'getWorkspaceFolders' ) . returns ( [ { uri : testUri , name : 'test' , index : 0 } ] ) ;
960- sandbox . stub ( workspaceApis , 'getConfiguration' ) . returns ( createMockConfig ( [ ] ) as WorkspaceConfiguration ) ;
961- sandbox . stub ( helpers , 'getUserConfiguredSetting' ) . returns ( undefined ) ;
962-
963- // Block setEnvironments so we can observe that the function returns before it completes
964- let resolveSetEnvironments : ( ) => void ;
965- const setEnvironmentsPromise = new Promise < void > ( ( resolve ) => {
966- resolveSetEnvironments = resolve ;
967- } ) ;
968- mockEnvManagers . setEnvironments . callsFake ( async ( ) => {
969- await setEnvironmentsPromise ;
970- } ) ;
971-
972- let functionReturned = false ;
973- const resultPromise = applyInitialEnvironmentSelection (
974- mockEnvManagers as unknown as EnvironmentManagers ,
975- mockProjectManager as unknown as PythonProjectManager ,
976- mockNativeFinder as unknown as NativePythonFinder ,
977- mockApi as unknown as PythonEnvironmentApi ,
978- ) . then ( ( ) => {
979- functionReturned = true ;
980- } ) ;
981-
982- // Yield to microtasks — in DEFERRED path, function returns before global completes
983- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
984- assert . ok ( functionReturned , 'Function should return before global scope completes (deferred path)' ) ;
985- assert . ok ( mockEnvManagers . setEnvironment . called , 'setEnvironment should be called for workspace folder' ) ;
986-
987- // Clean up: unblock the global scope
988- resolveSetEnvironments ! ( ) ;
989- await resultPromise ;
990- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
991- } ) ;
992-
993- test ( 'should await global scope when all workspace folders resolve with env=undefined' , async ( ) => {
994- // When workspace folders exist but all resolve to env=undefined (no Python found),
995- // workspaceFolderResolved stays false and global scope must be awaited (not deferred).
996- sandbox . stub ( workspaceApis , 'getWorkspaceFolders' ) . returns ( [ { uri : testUri , name : 'test' , index : 0 } ] ) ;
997- sandbox . stub ( workspaceApis , 'getConfiguration' ) . returns ( createMockConfig ( [ ] ) as WorkspaceConfiguration ) ;
998- sandbox . stub ( helpers , 'getUserConfiguredSetting' ) . returns ( undefined ) ;
999-
1000- // All managers return undefined for workspace scope — no Python found
1001- mockVenvManager . get . resolves ( undefined ) ;
1002- mockSystemManager . get . resolves ( undefined ) ;
1003-
1004- // Block setEnvironments so we can verify the function does NOT return before it completes
1005- let resolveSetEnvironments : ( ) => void ;
1006- const setEnvironmentsPromise = new Promise < void > ( ( resolve ) => {
1007- resolveSetEnvironments = resolve ;
1008- } ) ;
1009- mockEnvManagers . setEnvironments . callsFake ( async ( ) => {
1010- await setEnvironmentsPromise ;
1011- } ) ;
1012-
1013- let functionReturned = false ;
1014- const resultPromise = applyInitialEnvironmentSelection (
1015- mockEnvManagers as unknown as EnvironmentManagers ,
1016- mockProjectManager as unknown as PythonProjectManager ,
1017- mockNativeFinder as unknown as NativePythonFinder ,
1018- mockApi as unknown as PythonEnvironmentApi ,
1019- ) . then ( ( ) => {
1020- functionReturned = true ;
1021- } ) ;
1022-
1023- // Yield to microtasks — in AWAITED path, function should NOT have returned yet
1024- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
1025- assert . ok ( ! functionReturned , 'Function should NOT return before global scope completes (awaited path)' ) ;
1026-
1027- // Unblock global scope
1028- resolveSetEnvironments ! ( ) ;
1029- await resultPromise ;
1030-
1031- // Now the function has returned after global scope completed
1032- assert . ok ( functionReturned , 'Function should have returned after global scope completes' ) ;
1033- assert . ok ( mockEnvManagers . setEnvironment . called , 'setEnvironment should be called for workspace folder' ) ;
1034- assert . ok ( mockEnvManagers . setEnvironments . called , 'setEnvironments should be called for global scope' ) ;
1035- } ) ;
1036-
1037923 test ( 'notifyUserOfSettingErrors shows warning with Open Settings for defaultInterpreterPath' , async ( ) => {
1038924 // Trigger the defaultInterpreterPath error branch of notifyUserOfSettingErrors.
1039925 sandbox . stub ( workspaceApis , 'getWorkspaceFolders' ) . returns ( [ { uri : testUri , name : 'test' , index : 0 } ] ) ;
0 commit comments