Skip to content

Commit 58e97c1

Browse files
committed
types
1 parent 4d58d74 commit 58e97c1

1 file changed

Lines changed: 76 additions & 50 deletions

File tree

src/test/features/terminal/terminalManager.unit.test.ts

Lines changed: 76 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,66 +3,95 @@
33

44
import * as assert from 'assert';
55
import * as sinon from 'sinon';
6-
import { EventEmitter, Progress, Terminal, TerminalOptions } from 'vscode';
6+
import { Disposable, Event, EventEmitter, Progress, Terminal, TerminalOptions, Uri } from 'vscode';
77
import { PythonEnvironment } from '../../../api';
88
import * as windowApis from '../../../common/window.apis';
99
import * 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';
1211
import {
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';
1620
import * 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

1960
suite('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

Comments
 (0)