33
44import * as assert from 'assert' ;
55import * as sinon from 'sinon' ;
6- import { EventEmitter , Progress , Terminal , TerminalOptions } from 'vscode' ;
6+ import { Disposable , Event , EventEmitter , Progress , Terminal , TerminalOptions , Uri } from 'vscode' ;
77import { PythonEnvironment } from '../../../api' ;
88import * as windowApis from '../../../common/window.apis' ;
99import * as workspaceApis from '../../../common/workspace.apis' ;
10- import { TerminalActivationInternal } from '../../../features/terminal/terminalActivationState' ;
11- import { TerminalManagerImpl } from '../../../features/terminal/terminalManager' ;
10+ import * as activationUtils from '../../../features/common/activation' ;
1211import {
1312 ShellEnvsProvider ,
1413 ShellStartupScriptProvider ,
1514} from '../../../features/terminal/shells/startupProvider' ;
15+ import {
16+ DidChangeTerminalActivationStateEvent ,
17+ TerminalActivationInternal ,
18+ } from '../../../features/terminal/terminalActivationState' ;
19+ import { TerminalManagerImpl } from '../../../features/terminal/terminalManager' ;
1620import * as terminalUtils from '../../../features/terminal/utils' ;
17- import * as activationUtils from '../../../features/common/activation' ;
21+
22+ /**
23+ * Test implementation of TerminalActivationInternal that tracks method calls.
24+ */
25+ class TestTerminalActivation implements TerminalActivationInternal {
26+ public callOrder : string [ ] = [ ] ;
27+ public activateCalls = 0 ;
28+ public deactivateCalls = 0 ;
29+
30+ private onDidChangeEmitter = new EventEmitter < DidChangeTerminalActivationStateEvent > ( ) ;
31+ public onDidChangeTerminalActivationState : Event < DidChangeTerminalActivationStateEvent > =
32+ this . onDidChangeEmitter . event ;
33+
34+ isActivated ( _terminal : Terminal , _environment ?: PythonEnvironment ) : boolean {
35+ return false ;
36+ }
37+
38+ async activate ( _terminal : Terminal , _environment : PythonEnvironment ) : Promise < void > {
39+ this . activateCalls += 1 ;
40+ this . callOrder . push ( 'activate' ) ;
41+ }
42+
43+ async deactivate ( _terminal : Terminal ) : Promise < void > {
44+ this . deactivateCalls += 1 ;
45+ }
46+
47+ getEnvironment ( _terminal : Terminal ) : PythonEnvironment | undefined {
48+ return undefined ;
49+ }
50+
51+ updateActivationState ( _terminal : Terminal , _environment : PythonEnvironment , _activated : boolean ) : void {
52+ // Not used in these tests
53+ }
54+
55+ dispose ( ) : void {
56+ this . onDidChangeEmitter . dispose ( ) ;
57+ }
58+ }
1859
1960suite ( 'TerminalManager - create()' , ( ) => {
20- let terminalActivation : TerminalActivationInternal ;
61+ let terminalActivation : TestTerminalActivation ;
2162 let mockGetAutoActivationType : sinon . SinonStub ;
2263 let terminalManager : TerminalManagerImpl ;
23-
24- // Tracking variables for show() and activate() call order
25- let callOrder : string [ ] ;
2664 let mockTerminal : Partial < Terminal > & { show : sinon . SinonStub } ;
2765
28- const createMockEnvironment = ( ) : PythonEnvironment =>
29- ( {
30- envId : { id : 'test-env-id' , managerId : 'test-manager' } ,
31- environmentPath : { fsPath : '/path/to/python' } ,
32- displayName : 'Test Environment' ,
33- execInfo : {
34- activation : { executable : 'source' , args : [ '/path/to/activate' ] } ,
35- } ,
36- } as unknown as PythonEnvironment ) ;
66+ const createMockEnvironment = ( ) : PythonEnvironment => ( {
67+ envId : { id : 'test-env-id' , managerId : 'test-manager' } ,
68+ name : 'Test Environment' ,
69+ displayName : 'Test Environment' ,
70+ shortDisplayName : 'TestEnv' ,
71+ displayPath : '/path/to/env' ,
72+ version : '3.9.0' ,
73+ environmentPath : Uri . file ( '/path/to/python' ) ,
74+ sysPrefix : '/path/to/env' ,
75+ execInfo : {
76+ run : { executable : '/path/to/python' } ,
77+ activation : [ { executable : '/path/to/activate' } ] ,
78+ } ,
79+ } ) ;
3780
3881 setup ( ( ) => {
39- callOrder = [ ] ;
82+ terminalActivation = new TestTerminalActivation ( ) ;
4083
41- // Create mock terminal with tracking
84+ // Create mock terminal with tracking - shares callOrder with terminalActivation
4285 mockTerminal = {
4386 name : 'Test Terminal' ,
4487 creationOptions : { } as TerminalOptions ,
4588 shellIntegration : undefined ,
4689 show : sinon . stub ( ) . callsFake ( ( ) => {
47- callOrder . push ( 'show' ) ;
90+ terminalActivation . callOrder . push ( 'show' ) ;
4891 } ) ,
4992 sendText : sinon . stub ( ) ,
5093 } ;
5194
52- // Mock terminal activation using unknown cast for simpler typing
53- const onDidChangeEmitter = new EventEmitter < unknown > ( ) ;
54- terminalActivation = {
55- isActivated : sinon . stub ( ) . returns ( false ) ,
56- activate : sinon . stub ( ) . callsFake ( async ( ) => {
57- callOrder . push ( 'activate' ) ;
58- } ) ,
59- deactivate : sinon . stub ( ) . resolves ( ) ,
60- getEnvironment : sinon . stub ( ) . returns ( undefined ) ,
61- updateActivationState : sinon . stub ( ) ,
62- onDidChangeTerminalActivationState : onDidChangeEmitter . event ,
63- dispose : sinon . stub ( ) ,
64- } as unknown as TerminalActivationInternal ;
65-
6695 // Stub terminalUtils
6796 mockGetAutoActivationType = sinon . stub ( terminalUtils , 'getAutoActivationType' ) ;
6897 sinon . stub ( terminalUtils , 'waitForShellIntegration' ) . resolves ( false ) ;
@@ -71,38 +100,35 @@ suite('TerminalManager - create()', () => {
71100 sinon . stub ( activationUtils , 'isActivatableEnvironment' ) . returns ( true ) ;
72101
73102 // Stub window APIs
74- sinon . stub ( windowApis , 'createTerminal' ) . returns ( mockTerminal as unknown as Terminal ) ;
75- sinon . stub ( windowApis , 'onDidOpenTerminal' ) . returns ( { dispose : sinon . stub ( ) } ) ;
76- sinon . stub ( windowApis , 'onDidCloseTerminal' ) . returns ( { dispose : sinon . stub ( ) } ) ;
77- sinon . stub ( windowApis , 'onDidChangeWindowState' ) . returns ( { dispose : sinon . stub ( ) } ) ;
103+ sinon . stub ( windowApis , 'createTerminal' ) . returns ( mockTerminal as Terminal ) ;
104+ sinon . stub ( windowApis , 'onDidOpenTerminal' ) . returns ( new Disposable ( ( ) => { } ) ) ;
105+ sinon . stub ( windowApis , 'onDidCloseTerminal' ) . returns ( new Disposable ( ( ) => { } ) ) ;
106+ sinon . stub ( windowApis , 'onDidChangeWindowState' ) . returns ( new Disposable ( ( ) => { } ) ) ;
78107 sinon . stub ( windowApis , 'terminals' ) . returns ( [ ] ) ;
79108
80109 // Stub withProgress to execute the callback directly
81110 sinon . stub ( windowApis , 'withProgress' ) . callsFake ( async ( _options , task ) => {
82111 const mockProgress : Progress < { message ?: string ; increment ?: number } > = { report : ( ) => { } } ;
83112 const mockCancellationToken = {
84113 isCancellationRequested : false ,
85- onCancellationRequested : ( ) => ( { dispose : ( ) => { } } ) ,
114+ onCancellationRequested : ( ) => new Disposable ( ( ) => { } ) ,
86115 } ;
87116 return task ( mockProgress , mockCancellationToken as never ) ;
88117 } ) ;
89118
90119 // Stub workspace APIs
91- sinon . stub ( workspaceApis , 'onDidChangeConfiguration' ) . returns ( { dispose : sinon . stub ( ) } ) ;
120+ sinon . stub ( workspaceApis , 'onDidChangeConfiguration' ) . returns ( new Disposable ( ( ) => { } ) ) ;
92121 } ) ;
93122
94123 teardown ( ( ) => {
95124 sinon . restore ( ) ;
125+ terminalActivation . dispose ( ) ;
96126 } ) ;
97127
98128 function createTerminalManager ( ) : TerminalManagerImpl {
99129 const emptyEnvProviders : ShellEnvsProvider [ ] = [ ] ;
100130 const emptyScriptProviders : ShellStartupScriptProvider [ ] = [ ] ;
101- return new TerminalManagerImpl (
102- terminalActivation as TerminalActivationInternal ,
103- emptyEnvProviders ,
104- emptyScriptProviders ,
105- ) ;
131+ return new TerminalManagerImpl ( terminalActivation , emptyEnvProviders , emptyScriptProviders ) ;
106132 }
107133
108134 // Regression test for https://github.com/microsoft/vscode-python-environments/issues/640
@@ -118,6 +144,7 @@ suite('TerminalManager - create()', () => {
118144 await terminalManager . create ( env , { cwd : '/workspace' } ) ;
119145
120146 // Assert - show() must be called before activate() so terminal is visible during activation
147+ const { callOrder } = terminalActivation ;
121148 assert . ok ( callOrder . includes ( 'show' ) , 'Terminal show() should be called' ) ;
122149 assert . ok ( callOrder . includes ( 'activate' ) , 'Terminal activate() should be called' ) ;
123150 const showIndex = callOrder . indexOf ( 'show' ) ;
@@ -140,6 +167,7 @@ suite('TerminalManager - create()', () => {
140167 await terminalManager . create ( env , { cwd : '/workspace' } ) ;
141168
142169 // Assert - no blocking activation means caller (runInTerminal) will show terminal
170+ const { callOrder } = terminalActivation ;
143171 assert . strictEqual ( callOrder . includes ( 'show' ) , false , 'show() deferred to caller' ) ;
144172 assert . strictEqual ( callOrder . includes ( 'activate' ) , false , 'No command activation for shell startup mode' ) ;
145173 } ) ;
@@ -154,6 +182,7 @@ suite('TerminalManager - create()', () => {
154182 await terminalManager . create ( env , { cwd : '/workspace' } ) ;
155183
156184 // Assert - no activation means caller (runInTerminal) will show terminal
185+ const { callOrder } = terminalActivation ;
157186 assert . strictEqual ( callOrder . includes ( 'show' ) , false , 'show() deferred to caller' ) ;
158187 assert . strictEqual ( callOrder . includes ( 'activate' ) , false , 'Activation disabled' ) ;
159188 } ) ;
@@ -168,12 +197,9 @@ suite('TerminalManager - create()', () => {
168197 const terminal = await terminalManager . create ( env , { cwd : '/workspace' , disableActivation : true } ) ;
169198
170199 // Assert - terminal returned without any activation logic
200+ const { callOrder } = terminalActivation ;
171201 assert . ok ( terminal , 'Terminal should be returned' ) ;
172202 assert . strictEqual ( callOrder . includes ( 'show' ) , false , 'No show() when activation skipped' ) ;
173- assert . strictEqual (
174- ( terminalActivation . activate as sinon . SinonStub ) . called ,
175- false ,
176- 'No activate() when disableActivation is true' ,
177- ) ;
203+ assert . strictEqual ( terminalActivation . activateCalls , 0 , 'No activate() when disableActivation is true' ) ;
178204 } ) ;
179205} ) ;
0 commit comments