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
44 changes: 40 additions & 4 deletions src/commands/testExplorerCommands.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import { DebugConfiguration, TestItem, TestRunRequest } from 'vscode';
import { DebugConfiguration, TestItem, TestRunRequest, Uri } from 'vscode';
import { sendInfo } from 'vscode-extension-telemetry-wrapper';
import { runTests, testController } from '../controller/testController';
import { loadChildren, runTests, testController } from '../controller/testController';
import { loadJavaProjects } from '../controller/utils';
import { showTestItemsInCurrentFile } from '../extension';

Expand Down Expand Up @@ -39,10 +39,46 @@ export async function runTestsFromTestExplorer(testItem: TestItem, launchConfigu

export async function refreshExplorer(): Promise<void> {
sendInfo('', { name: 'refreshTests' });

await loadJavaProjects();

// Force re-resolution of all existing project roots
const loadPromises: Promise<void>[] = [];
testController?.items.forEach((root: TestItem) => {
testController?.items.delete(root.id);
loadPromises.push(loadChildren(root));
});
await Promise.all(loadPromises);

await loadJavaProjects();
await showTestItemsInCurrentFile();
}

/**
* Refresh only the project subtree that matches the given classpath-change URI.
* Falls back to a full (incremental) refresh if no matching project is found.
*/
export async function refreshProject(classpathUri: Uri): Promise<void> {
sendInfo('', { name: 'refreshProject' });
const uriString: string = classpathUri.toString();

// Find the project root with the longest matching URI prefix (most specific match)
let matchedProject: TestItem | undefined;
let matchedUriLength: number = 0;
testController?.items.forEach((root: TestItem) => {
if (root.uri) {
const rootUriString: string = root.uri.toString();
if (uriString.startsWith(rootUriString) && rootUriString.length > matchedUriLength) {
matchedProject = root;
matchedUriLength = rootUriString.length;
}
}
});

if (matchedProject) {
// Re-resolve only the matched project's children
await loadChildren(matchedProject);
} else {
// No matching project found – do incremental full refresh
await loadJavaProjects();
}
await showTestItemsInCurrentFile();
}
8 changes: 8 additions & 0 deletions src/controller/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ export async function loadJavaProjects(): Promise<void> {
return project.testKind !== TestKind.None;
});

// Remove projects that no longer exist
const projectIds: Set<string> = new Set(testProjects.map((p: IJavaTestItem) => p.id));
testController?.items.forEach((root: TestItem) => {
if (!projectIds.has(root.id)) {
testController?.items.delete(root.id);
}
});

for (const project of testProjects) {
if (testController?.items.get(project.id)) {
continue;
Expand Down
6 changes: 3 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentO
import { navigateToTestOrTarget } from './commands/navigation/navigationCommands';
import { generateTests } from './commands/generationCommands';
import { runTestsFromJavaProjectExplorer } from './commands/projectExplorerCommands';
import { refreshExplorer, runTestsFromTestExplorer } from './commands/testExplorerCommands';
import { refreshExplorer, refreshProject, runTestsFromTestExplorer } from './commands/testExplorerCommands';
import { openStackTrace } from './commands/testReportCommands';
import { Context, ExtensionName, JavaTestRunnerCommands, VSCodeCommands } from './constants';
import { createTestController, testController, watchers } from './controller/testController';
Expand Down Expand Up @@ -76,11 +76,11 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom

if (extensionApi.onDidClasspathUpdate) {
const onDidClasspathUpdate: Event<Uri> = extensionApi.onDidClasspathUpdate;
context.subscriptions.push(onDidClasspathUpdate(async () => {
context.subscriptions.push(onDidClasspathUpdate(async (uri: Uri) => {
// workaround: wait more time to make sure Language Server has updated all caches
setTimeout(() => {
testSourceProvider.clear();
refreshExplorer();
refreshProject(uri);
}, 1000 /* ms */);
}));
}
Expand Down