Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/utils/wrapFunctionsInTelemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function stringifyError(e: unknown): string {
}

function handleError(e: unknown, functionName: string): never {
ext.outputChannel.appendLog(`Internal error: '${functionName}' threw an exception\n\t${stringifyError(e)}`);
ext.outputChannel?.appendLog(`Internal error: '${functionName}' threw an exception\n\t${stringifyError(e)}`);
if (e instanceof Error) {
e.message = functionName === 'branchDataProvider.getResourceItem' ?
// shortened message for anything displayed on the tree
Expand Down
47 changes: 38 additions & 9 deletions test/nightly/crud.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
import type { Location } from '@azure/arm-resources-subscriptions';
import { AzExtParentTreeItem, createTestActionContext, randomUtils, runWithTestActionContext } from '@microsoft/vscode-azext-utils';
import assert from "assert";
import * as vscode from 'vscode';
import { SubscriptionItem } from '../../src/tree/azure/SubscriptionItem';
import { settingUtils } from '../../src/utils/settingUtils';
import { longRunningTestsEnabled } from "../global.test";
import { setupAzureDevOpsSubscriptionProvider } from "../utils/azureDevOpsSubscriptionProvider";
import { getCachedTestApi } from "../utils/testApiAccess";

const useAzureFederatedCredentials: boolean = !/^(false|0)?$/i.test(process.env['AzCode_UseAzureFederatedCredentials'] || '');

let rgName: string;
let locations: Location[];
let testSubscription: SubscriptionItem;
Expand All @@ -24,21 +28,46 @@ suite('Resource CRUD Operations', function (this: Mocha.Suite): void {
}

const testApi = getCachedTestApi();
// Clear mock overrides that may have been set by other test suites
testApi.testing.setOverrideAzureServiceFactory(undefined);
testApi.testing.setOverrideAzureSubscriptionProvider(undefined);

// Re-establish the AzDO federated credential provider if running in a pipeline,
// since other test suites may have overwritten it with a mock provider.
if (useAzureFederatedCredentials) {
await setupAzureDevOpsSubscriptionProvider();
}

// Refresh the tree and wait for any pending tree operations to settle.
// This avoids a race condition where a background tree refresh (triggered by
// the logIn command in global.nightly.test.ts) cancels our getChildren() call
// via the shared cancellation token in AzureResourceTreeDataProvider.
await vscode.commands.executeCommand('azureResourceGroups.refresh');
await new Promise(resolve => setTimeout(resolve, 2000));
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hard-coded 2000ms timeout is a potential source of test flakiness. If the tree refresh takes longer than expected (due to slow CI or other factors), the test may fail intermittently. Consider alternatives such as polling for the tree state or using an event-based approach to detect when the refresh is complete. If a hard-coded timeout is necessary, consider making it configurable via an environment variable or increasing it to a more conservative value.

Copilot uses AI. Check for mistakes.

const subscriptionTreeItems = await testApi.compatibility.getAppResourceTree().getChildren() as unknown as SubscriptionItem[];
if (subscriptionTreeItems.length > 0) {
const testContext = await createTestActionContext();
testSubscription = subscriptionTreeItems[0] as SubscriptionItem;
const context = {
...testContext,
...testSubscription.subscription,
environment: structuredClone(testSubscription.subscription.environment)
};
locations = (await testApi.testing.getLocations(context)).slice(0, 5); // limit to 5 locations for test speed

// Filter to actual SubscriptionItems (exclude sign-in/placeholder items).
const actualSubscriptions = subscriptionTreeItems.filter(
(item): item is SubscriptionItem => !!(item as SubscriptionItem).subscription?.subscriptionId
);

// if we can't find any subscriptions, then something is wrong with the test setup (e.g. auth failure), so skip the tests rather than fail them
if (actualSubscriptions.length === 0) {
this.skip();
return;
}

const testContext = await createTestActionContext();
testSubscription = actualSubscriptions[0];

const context = {
...testContext,
...testSubscription.subscription,
environment: structuredClone(testSubscription.subscription.environment)
};
locations = (await testApi.testing.getLocations(context)).slice(0, 5); // limit to 5 locations for test speed

rgName = randomUtils.getRandomHexString(12);
});

Expand Down
8 changes: 8 additions & 0 deletions test/utils/azureDevOpsSubscriptionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ export async function setupAzureDevOpsSubscriptionProvider(): Promise<void> {
// Create the provider instance now so we can return it synchronously
const provider = await factory();

// Sign in to establish the token credential.
// This must be done before the provider can return subscriptions.
const signedIn = await provider.signIn();

if (!signedIn) {
throw new Error('Failed to sign in with Azure DevOps federated credentials');
}

// Set the override via the test API
const testApi = getCachedTestApi();
testApi.testing.setOverrideAzureSubscriptionProvider(() => provider);
Expand Down