Skip to content

Commit 0601d34

Browse files
committed
test: preserve package refresh failures
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: edcaaa35-9a42-4351-98fa-55bcf8f1968e
1 parent ebb222d commit 0601d34

4 files changed

Lines changed: 35 additions & 13 deletions

File tree

‎src/test/common/testUtils.unit.test.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ suite('Test Utilities', () => {
7171
);
7272
assert.ok(counter >= 3);
7373
});
74+
75+
test('should preserve condition errors when retries are disabled', async () => {
76+
const conditionError = new Error('Package refresh failed');
77+
78+
await assert.rejects(
79+
() => waitForCondition(() => Promise.reject(conditionError), 1000, 'Should not time out', 10, false),
80+
(error: unknown) => error === conditionError,
81+
);
82+
});
7483
});
7584

7685
suite('retryUntilSuccess', () => {

‎src/test/integration/packageManager.integration.test.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ for (const profile of profiles) {
156156
30_000,
157157
'Package not installed',
158158
1_000,
159+
false,
159160
);
160161

161162
const directPackageNames = await vscode.commands.executeCommand<string[] | undefined>(
@@ -176,6 +177,7 @@ for (const profile of profiles) {
176177
30_000,
177178
'Package not uninstalled',
178179
1_000,
180+
false,
179181
);
180182
}
181183
});

‎src/test/managers/common/packageManagerHeadlessConformance.unit.test.ts‎

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ suite('Package manager headless conformance', () => {
3838
const condaPicker = sinon.stub(condaUtils, 'getCommonCondaPackagesToInstall');
3939
const poetryInput = sinon.stub(windowApis, 'showInputBox');
4040

41-
for (const manager of createManagers()) {
41+
for (const manager of createManagers().all) {
4242
await manager.manage(environment, { install: [], runHeadless: true });
4343
}
4444

@@ -61,7 +61,7 @@ suite('Package manager headless conformance', () => {
6161
const showErrorMessage = sinon.stub(windowApis, 'showErrorMessage').resolves(undefined);
6262
const showErrorMessageWithLogs = sinon.stub(errorUtils, 'showErrorMessageWithLogs').resolves();
6363

64-
for (const manager of createManagers()) {
64+
for (const manager of createManagers().all) {
6565
await assert.rejects(
6666
manager.manage(environment, { install: ['requests'], runHeadless: true }),
6767
(error: unknown) => error === operationError,
@@ -92,7 +92,7 @@ suite('Package manager headless conformance', () => {
9292
sinon.stub(PipPackageManager.prototype, 'getDirectPackageNames').resolves(undefined);
9393
const showErrorMessage = sinon.stub(windowApis, 'showErrorMessage').resolves(undefined);
9494
const showErrorMessageWithLogs = sinon.stub(errorUtils, 'showErrorMessageWithLogs').resolves();
95-
const manager = createManagers()[0];
95+
const manager = createManagers().pip;
9696

9797
await manager.manage(environment, { install: ['requests'], runHeadless: true });
9898
await flushImmediate();
@@ -110,7 +110,7 @@ suite('Package manager headless conformance', () => {
110110
sinon.stub(condaUtils, 'runCondaExecutable').rejects(refreshError);
111111
const showErrorMessage = sinon.stub(windowApis, 'showErrorMessage').resolves(undefined);
112112
const showErrorMessageWithLogs = sinon.stub(errorUtils, 'showErrorMessageWithLogs').resolves();
113-
const manager = createManagers()[1];
113+
const manager = createManagers().conda;
114114

115115
await assert.rejects(
116116
manager.manage(environment, { install: ['requests'], runHeadless: true }),
@@ -141,7 +141,7 @@ suite('Package manager headless conformance', () => {
141141
});
142142
const showErrorMessage = sinon.stub(windowApis, 'showErrorMessage').resolves(undefined);
143143
const showErrorMessageWithLogs = sinon.stub(errorUtils, 'showErrorMessageWithLogs').resolves();
144-
const manager = createManagers()[2];
144+
const manager = createManagers().poetry;
145145

146146
await manager.manage(environment, { install: ['requests'], runHeadless: true });
147147
await flushImmediate();
@@ -152,7 +152,12 @@ suite('Package manager headless conformance', () => {
152152
assert.ok(showErrorMessageWithLogs.notCalled);
153153
});
154154

155-
function createManagers(): PackageManager[] {
155+
function createManagers(): {
156+
pip: PackageManager;
157+
conda: PackageManager;
158+
poetry: PackageManager;
159+
all: PackageManager[];
160+
} {
156161
const api = {
157162
createPackageItem: sinon.stub(),
158163
getPythonProjects: sinon.stub().returns([]),
@@ -163,11 +168,12 @@ suite('Package manager headless conformance', () => {
163168
info: sinon.stub(),
164169
show: sinon.stub(),
165170
} as unknown as LogOutputChannel;
166-
return [
167-
new PipPackageManager(api, log, { getProjectsByEnvironment: sinon.stub().returns([]) } as unknown as VenvManager),
168-
new CondaPackageManager(api, log),
169-
new PoetryPackageManager(api, log, {} as PoetryManager),
170-
];
171+
const pip = new PipPackageManager(api, log, {
172+
getProjectsByEnvironment: sinon.stub().returns([]),
173+
} as unknown as VenvManager);
174+
const conda = new CondaPackageManager(api, log);
175+
const poetry = new PoetryPackageManager(api, log, {} as PoetryManager);
176+
return { pip, conda, poetry, all: [pip, conda, poetry] };
171177
}
172178

173179
async function flushImmediate(): Promise<void> {

‎src/test/testUtils.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export function sleep(ms: number): Promise<void> {
2828
* @param timeoutMs - Maximum time to wait (default: 10 seconds)
2929
* @param errorMessage - Error message if condition is not met
3030
* @param pollIntervalMs - How often to check condition (default: 100ms)
31+
* @param retryOnError - Whether rejected conditions should be retried (default: true)
3132
*
3233
* @example
3334
* // Wait for extension to activate
@@ -50,6 +51,7 @@ export async function waitForCondition(
5051
timeoutMs: number = 10_000,
5152
errorMessage: string | (() => string) = 'Condition not met within timeout',
5253
pollIntervalMs: number = 100,
54+
retryOnError: boolean = true,
5355
): Promise<void> {
5456
return new Promise<void>((resolve, reject) => {
5557
const startTime = Date.now();
@@ -61,8 +63,11 @@ export async function waitForCondition(
6163
resolve();
6264
return;
6365
}
64-
} catch {
65-
// Condition threw - keep waiting
66+
} catch (error) {
67+
if (!retryOnError) {
68+
reject(error);
69+
return;
70+
}
6671
}
6772

6873
if (Date.now() - startTime >= timeoutMs) {

0 commit comments

Comments
 (0)