diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 07b438e820b..023134c80ac 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2565,7 +2565,7 @@ declare module 'vscode' { /** * URI this TestItem is associated with. May be a file or directory. */ - uri: Uri; + uri?: Uri; /** * Display name describing the test item. @@ -2588,7 +2588,7 @@ declare module 'vscode' { /** * URI this TestItem is associated with. May be a file or directory. */ - readonly uri: Uri; + readonly uri?: Uri; /** * A mapping of children by ID to the associated TestItem instances. @@ -2820,7 +2820,7 @@ declare module 'vscode' { /** * URI this TestItem is associated with. May be a file or file. */ - readonly uri: Uri; + readonly uri?: Uri; /** * Display name describing the test case. diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index 7afd44dfc34..46f08ad1d9f 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -666,7 +666,7 @@ export class TestItemFilteredWrapper extends TestItemImpl { } } - const nowMatches = this.children.size > 0 || this.actual.uri.toString() === this.filterDocument.uri.toString(); + const nowMatches = this.children.size > 0 || this.actual.uri?.toString() === this.filterDocument.uri.toString(); this._cachedMatchesFilter = nowMatches; if (nowMatches !== didMatch) { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 61511cbec3e..abb2dc4411e 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -3263,7 +3263,7 @@ const rangeComparator = (a: vscode.Range | undefined, b: vscode.Range | undefine export class TestItemImpl implements vscode.TestItem { public readonly id!: string; - public readonly uri!: vscode.Uri; + public readonly uri!: vscode.Uri | undefined; public readonly children!: ReadonlyMap; public readonly parent!: TestItemImpl | undefined; @@ -3277,7 +3277,7 @@ export class TestItemImpl implements vscode.TestItem { /** Extension-owned resolve handler */ public resolveHandler?: (token: vscode.CancellationToken) => void; - constructor(id: string, public label: string, uri: vscode.Uri, public data: unknown) { + constructor(id: string, public label: string, uri: vscode.Uri | undefined, public data: unknown) { const api = getPrivateApiFor(this); Object.defineProperties(this, { diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index e831f8512c6..2fa24f191fd 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -537,6 +537,7 @@ export class EditFocusedTest extends ViewAction { f1: false, menu: { id: MenuId.TestItem, + when: TestingContextKeys.testItemHasUri.isEqualTo(true), }, keybinding: { weight: KeybindingWeight.EditorContrib - 10, @@ -568,6 +569,10 @@ export class EditFocusedTest extends ViewAction { * @override */ private async runForTest(accessor: ServicesAccessor, test: ITestItem, preserveFocus = true) { + if (!test.uri) { + return; + } + const commandService = accessor.get(ICommandService); const fileService = accessor.get(IFileService); const editorService = accessor.get(IEditorService); diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index c7305a1a8b0..aaafab933c9 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -113,7 +113,7 @@ export class TestingDecorations extends Disposable implements IEditorContributio updateFontFamilyVar(); this._register(this.results.onTestChanged(({ item: result }) => { - if (this.currentUri && result.item.uri.toString() === this.currentUri.toString()) { + if (this.currentUri && result.item.uri && result.item.uri.toString() === this.currentUri.toString()) { this.setDecorations(this.currentUri); } })); diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index c48217a909e..c71d027d0c4 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -687,7 +687,7 @@ class TestsFilter implements ITreeFilter { } for (let e: IActionableTestTreeElement | null = element; e instanceof TestItemTreeElement; e = e!.parent) { - return e.test.item.uri.toString() === this._filterToUri + return e.test.item.uri?.toString() === this._filterToUri ? FilterResult.Include : FilterResult.Exclude; } @@ -735,7 +735,7 @@ class TreeSorter implements ITreeSorter { if (this.viewModel.viewSorting === TestExplorerViewSorting.ByLocation) { if (a instanceof TestItemTreeElement && b instanceof TestItemTreeElement - && a.test.item.uri.toString() === b.test.item.uri.toString() && a.test.item.range && b.test.item.range) { + && a.test.item.uri && b.test.item.uri && a.test.item.uri.toString() === b.test.item.uri.toString() && a.test.item.range && b.test.item.range) { const delta = a.test.item.range.startLineNumber - b.test.item.range.startLineNumber; if (delta !== 0) { return delta; @@ -1013,7 +1013,8 @@ const getActionableElementActions = ( const test = element instanceof TestItemTreeElement ? element.test : undefined; const contextOverlay = contextKeyService.createOverlay([ ['view', Testing.ExplorerViewId], - [TestingContextKeys.testItemExtId.key, test?.item.extId] + [TestingContextKeys.testItemExtId.key, test?.item.extId], + [TestingContextKeys.testItemHasUri.key, !!test?.item.uri], ]); const menu = menuService.createMenu(MenuId.TestItem, contextOverlay); diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index d8f1bee1be3..03b6cadad54 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -129,7 +129,7 @@ export class TestingPeekOpener extends Disposable implements ITestingPeekOpener // don't show the peek if the user asked to only auto-open peeks for visible tests, // and this test is not in any of the editors' models. - const testUri = evt.item.item.uri.toString(); + const testUri = evt.item.item.uri?.toString(); if (cfg === AutoOpenPeekViewWhen.FailureVisible && (!testUri || !editors.some(e => e.getModel()?.uri.toString() === testUri))) { return; } diff --git a/src/vs/workbench/contrib/testing/common/testCollection.ts b/src/vs/workbench/contrib/testing/common/testCollection.ts index e84ddf09084..e08df28a267 100644 --- a/src/vs/workbench/contrib/testing/common/testCollection.ts +++ b/src/vs/workbench/contrib/testing/common/testCollection.ts @@ -89,7 +89,7 @@ export interface ITestItem { extId: string; label: string; children?: never; - uri: URI; + uri?: URI; range: IRange | null; description: string | null; error: string | IMarkdownString | null; diff --git a/src/vs/workbench/contrib/testing/common/testingContextKeys.ts b/src/vs/workbench/contrib/testing/common/testingContextKeys.ts index c2a97327607..04568516732 100644 --- a/src/vs/workbench/contrib/testing/common/testingContextKeys.ts +++ b/src/vs/workbench/contrib/testing/common/testingContextKeys.ts @@ -23,4 +23,8 @@ export namespace TestingContextKeys { type: 'string', description: localize('testing.testId', 'ID of the current test item, set when creating or opening menus on test items') }); + export const testItemHasUri = new RawContextKey('testItemHasUri', false, { + type: 'string', + description: localize('testing.testItemHasUri', 'Boolean indicating whether the test item has a URI defined') + }); }