Skip to content

Commit 889a2c2

Browse files
authored
Add tests for shell startup (#1079)
Part of: #1019
1 parent 98cc93a commit 889a2c2

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import * as assert from 'assert';
2+
import * as sinon from 'sinon';
3+
import { Disposable, Progress } from 'vscode';
4+
5+
import * as commandApi from '../../../common/command.api';
6+
import { Common } from '../../../common/localize';
7+
import * as windowApis from '../../../common/window.apis';
8+
import {
9+
cleanupStartupScripts,
10+
handleSettingUpShellProfile,
11+
} from '../../../features/terminal/shellStartupSetupHandlers';
12+
import { ShellScriptEditState, ShellStartupScriptProvider } from '../../../features/terminal/shells/startupProvider';
13+
import * as terminalUtils from '../../../features/terminal/utils';
14+
15+
class TestStartupProvider implements ShellStartupScriptProvider {
16+
public readonly name: string;
17+
public readonly shellType: string;
18+
19+
public setupResult: ShellScriptEditState = ShellScriptEditState.Edited;
20+
public teardownResult: ShellScriptEditState = ShellScriptEditState.Edited;
21+
22+
public setupCalls = 0;
23+
public teardownCalls = 0;
24+
25+
constructor(name: string, shellType: string) {
26+
this.name = name;
27+
this.shellType = shellType;
28+
}
29+
30+
async isSetup(): Promise<never> {
31+
throw new Error('Not used in these unit tests');
32+
}
33+
34+
async setupScripts(): Promise<ShellScriptEditState> {
35+
this.setupCalls += 1;
36+
return this.setupResult;
37+
}
38+
39+
async teardownScripts(): Promise<ShellScriptEditState> {
40+
this.teardownCalls += 1;
41+
return this.teardownResult;
42+
}
43+
44+
async clearCache(): Promise<void> {
45+
// Not needed
46+
}
47+
}
48+
49+
suite('Shell Startup Setup Handlers', () => {
50+
teardown(() => sinon.restore());
51+
52+
test('handleSettingUpShellProfile: when user accepts and all providers edit, callback(true) is reported', async () => {
53+
sinon.stub(windowApis, 'showInformationMessage').resolves(Common.yes);
54+
sinon.stub(windowApis, 'withProgress').callsFake(async (_opts, task) => {
55+
const progress: Progress<{ message?: string; increment?: number }> = { report: () => undefined };
56+
const token = {
57+
isCancellationRequested: false,
58+
onCancellationRequested: () => new Disposable(() => undefined),
59+
};
60+
return task(progress, token);
61+
});
62+
63+
const showError = sinon.stub(windowApis, 'showErrorMessage');
64+
const callback = sinon.stub();
65+
66+
const p1 = new TestStartupProvider('bash', 'bash');
67+
const p2 = new TestStartupProvider('zsh', 'zsh');
68+
69+
await handleSettingUpShellProfile([p1, p2], callback);
70+
71+
// allow setImmediate prompt scheduling to run
72+
await new Promise<void>((resolve) => setImmediate(resolve));
73+
74+
assert.strictEqual(showError.called, false);
75+
assert.strictEqual(callback.callCount, 2);
76+
assert.deepStrictEqual(
77+
callback.args.map((a) => a[1]),
78+
[true, true],
79+
);
80+
});
81+
82+
test('handleSettingUpShellProfile: when user accepts but a provider fails, callback(false) and error prompt shown', async () => {
83+
sinon.stub(windowApis, 'showInformationMessage').resolves(Common.yes);
84+
sinon.stub(windowApis, 'withProgress').callsFake(async (_opts, task) => {
85+
const progress: Progress<{ message?: string; increment?: number }> = { report: () => undefined };
86+
const token = {
87+
isCancellationRequested: false,
88+
onCancellationRequested: () => new Disposable(() => undefined),
89+
};
90+
return task(progress, token);
91+
});
92+
93+
const showError = sinon.stub(windowApis, 'showErrorMessage').resolves(undefined);
94+
const callback = sinon.stub();
95+
96+
const p1 = new TestStartupProvider('bash', 'bash');
97+
const p2 = new TestStartupProvider('zsh', 'zsh');
98+
p2.setupResult = ShellScriptEditState.NotEdited;
99+
100+
await handleSettingUpShellProfile([p1, p2], callback);
101+
102+
await new Promise<void>((resolve) => setImmediate(resolve));
103+
104+
assert.strictEqual(showError.called, true);
105+
assert.strictEqual(callback.callCount, 2);
106+
assert.deepStrictEqual(
107+
callback.args.map((a) => a[1]),
108+
[false, false],
109+
);
110+
});
111+
112+
test('handleSettingUpShellProfile: if user clicks "View Logs" on error, executes command', async () => {
113+
sinon.stub(windowApis, 'showInformationMessage').resolves(Common.yes);
114+
sinon.stub(windowApis, 'withProgress').callsFake(async (_opts, task) => {
115+
const progress: Progress<{ message?: string; increment?: number }> = { report: () => undefined };
116+
const token = {
117+
isCancellationRequested: false,
118+
onCancellationRequested: () => new Disposable(() => undefined),
119+
};
120+
return task(progress, token);
121+
});
122+
123+
sinon.stub(windowApis, 'showErrorMessage').resolves(Common.viewLogs);
124+
const exec = sinon.stub(commandApi, 'executeCommand').resolves();
125+
126+
const p1 = new TestStartupProvider('bash', 'bash');
127+
p1.setupResult = ShellScriptEditState.NotEdited;
128+
129+
await handleSettingUpShellProfile([p1], () => undefined);
130+
131+
await new Promise<void>((resolve) => setImmediate(resolve));
132+
133+
assert.strictEqual(exec.calledWith('python-envs.viewLogs'), true);
134+
});
135+
136+
test('handleSettingUpShellProfile: when user declines, does not run setup and switches to command', async () => {
137+
sinon.stub(windowApis, 'showInformationMessage').resolves(undefined);
138+
const setAuto = sinon.stub(terminalUtils, 'setAutoActivationType').resolves();
139+
140+
const p1 = new TestStartupProvider('bash', 'bash');
141+
const p2 = new TestStartupProvider('zsh', 'zsh');
142+
143+
await handleSettingUpShellProfile([p1, p2], () => undefined);
144+
145+
assert.strictEqual(p1.setupCalls, 0);
146+
assert.strictEqual(p2.setupCalls, 0);
147+
// When user declines, it switches to command activation
148+
assert.strictEqual(setAuto.calledWith(terminalUtils.ACT_TYPE_COMMAND), true);
149+
});
150+
151+
test('cleanupStartupScripts: always calls teardown on all providers', async () => {
152+
sinon.stub(windowApis, 'showInformationMessage').resolves(undefined);
153+
sinon.stub(terminalUtils, 'getAutoActivationType').returns(terminalUtils.ACT_TYPE_COMMAND);
154+
155+
const setAuto = sinon.stub(terminalUtils, 'setAutoActivationType').resolves();
156+
157+
const p1 = new TestStartupProvider('bash', 'bash');
158+
const p2 = new TestStartupProvider('zsh', 'zsh');
159+
160+
await cleanupStartupScripts([p1, p2]);
161+
162+
assert.strictEqual(p1.teardownCalls, 1);
163+
assert.strictEqual(p2.teardownCalls, 1);
164+
assert.strictEqual(setAuto.called, false);
165+
});
166+
167+
test('cleanupStartupScripts: switches to command when current activation type is shellStartup', async () => {
168+
sinon.stub(windowApis, 'showInformationMessage').resolves(undefined);
169+
sinon.stub(terminalUtils, 'getAutoActivationType').returns(terminalUtils.ACT_TYPE_SHELL);
170+
171+
const setAuto = sinon.stub(terminalUtils, 'setAutoActivationType').resolves();
172+
173+
const p1 = new TestStartupProvider('bash', 'bash');
174+
175+
await cleanupStartupScripts([p1]);
176+
177+
await new Promise<void>((resolve) => setImmediate(resolve));
178+
179+
assert.strictEqual(setAuto.calledWith(terminalUtils.ACT_TYPE_COMMAND), true);
180+
});
181+
});

0 commit comments

Comments
 (0)