testing: be more consistent about focus actions, add context menu to reveal

Fixes #119649
This commit is contained in:
Connor Peet 2021-03-29 16:14:19 -07:00
parent 3aff04dcae
commit ca43526452
No known key found for this signature in database
GPG key ID: CF8FD2EA0DBC61BD
2 changed files with 70 additions and 37 deletions

View file

@ -9,10 +9,13 @@ import { Codicon } from 'vs/base/common/codicons';
import { Iterable } from 'vs/base/common/iterator';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { isDefined } from 'vs/base/common/types';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { Range } from 'vs/editor/common/core/range';
import { localize } from 'vs/nls';
import { Action2, MenuId } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyAndExpr, ContextKeyEqualsExpr, ContextKeyFalseExpr, ContextKeyTrueExpr } from 'vs/platform/contextkey/common/contextkey';
import { IFileService } from 'vs/platform/files/common/files';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { INotificationService } from 'vs/platform/notification/common/notification';
@ -23,10 +26,13 @@ import { ExtHostTestingResource } from 'vs/workbench/api/common/extHost.protocol
import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane';
import { FocusedViewContext } from 'vs/workbench/common/views';
import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
import { REVEAL_IN_EXPLORER_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileCommands';
import * as icons from 'vs/workbench/contrib/testing/browser/icons';
import { ITestExplorerFilterState } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter';
import { TestingExplorerView, TestingExplorerViewModel } from 'vs/workbench/contrib/testing/browser/testingExplorerView';
import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
import { TestExplorerViewMode, TestExplorerViewSorting, Testing } from 'vs/workbench/contrib/testing/common/constants';
import { InternalTestItem, TestIdPath, TestIdWithSrc, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
import { InternalTestItem, ITestItem, TestIdPath, TestIdWithSrc, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
import { ITestingAutoRun } from 'vs/workbench/contrib/testing/common/testingAutoRun';
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates';
@ -500,8 +506,11 @@ export class EditFocusedTest extends ViewAction<TestingExplorerView> {
super({
id: 'testing.editFocusedTest',
viewId: Testing.ExplorerViewId,
title: localize('testing.editFocusedTest', "Open Focused Test in Editor"),
title: localize('testing.editFocusedTest', "Go to Test"),
f1: false,
menu: {
id: MenuId.TestItem,
},
keybinding: {
weight: KeybindingWeight.EditorContrib - 10,
when: FocusedViewContext.isEqualTo(Testing.ExplorerViewId),
@ -510,13 +519,60 @@ export class EditFocusedTest extends ViewAction<TestingExplorerView> {
});
}
public async run(accessor: ServicesAccessor, test?: ITestItem, preserveFocus?: boolean) {
if (test) {
await this.runForTest(accessor, test, preserveFocus);
} else {
await super.run(accessor);
}
}
/**
* @override
*/
public runInView(_accessor: ServicesAccessor, view: TestingExplorerView) {
public runInView(accessor: ServicesAccessor, view: TestingExplorerView) {
const selected = view.viewModel.tree.getFocus().find(isDefined);
if (selected) {
view.viewModel.openEditorForItem(selected, false);
if (selected?.test) {
this.runForTest(accessor, selected.test.item, false);
}
}
/**
* @override
*/
private async runForTest(accessor: ServicesAccessor, test: ITestItem, preserveFocus = true) {
const commandService = accessor.get(ICommandService);
const fileService = accessor.get(IFileService);
const editorService = accessor.get(IEditorService);
accessor.get(ITestExplorerFilterState).reveal.value = [test.extId];
let isFile = true;
try {
if (!(await fileService.resolve(test.uri)).isFile) {
isFile = false;
}
} catch {
// ignored
}
if (!isFile) {
await commandService.executeCommand(REVEAL_IN_EXPLORER_COMMAND_ID, test.uri);
return;
}
const pane = await editorService.openEditor({
resource: test.uri,
options: {
selection: test.range && { startColumn: test.range.startColumn, startLineNumber: test.range.startLineNumber },
preserveFocus,
},
});
// if the user selected a failed test and now they didn't, hide the peek
const control = pane?.getControl();
if (isCodeEditor(control)) {
TestingOutputPeekController.get(control).removePeek();
}
}
}

View file

@ -23,7 +23,6 @@ import { Disposable, dispose, IDisposable, MutableDisposable } from 'vs/base/com
import { isDefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import 'vs/css!./media/testing';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { localize } from 'vs/nls';
import { createAndFillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
@ -52,7 +51,7 @@ import { HierarchicalByLocationProjection } from 'vs/workbench/contrib/testing/b
import { HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName';
import { testingHiddenIcon, testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons';
import { ITestExplorerFilterState, TestExplorerFilterState, TestingExplorerFilter } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter';
import { ITestingPeekOpener, TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
import { ITestingProgressUiService } from 'vs/workbench/contrib/testing/browser/testingProgressUiService';
import { TestExplorerStateFilter, TestExplorerViewMode, TestExplorerViewSorting, Testing, testStateNames } from 'vs/workbench/contrib/testing/common/constants';
import { TestIdPath, TestItemExpandState } from 'vs/workbench/contrib/testing/common/testCollection';
@ -62,7 +61,7 @@ import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResu
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
import { IWorkspaceTestCollectionService, TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { DebugAction, HideOrShowTestAction, RunAction } from './testExplorerActions';
import { DebugAction, EditFocusedTest, HideOrShowTestAction, RunAction } from './testExplorerActions';
export class TestingExplorerView extends ViewPane {
public viewModel!: TestingExplorerViewModel;
@ -278,7 +277,7 @@ export class TestingExplorerViewModel extends Disposable {
@ITestService private readonly testService: ITestService,
@ITestExplorerFilterState private readonly filterState: TestExplorerFilterState,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IEditorService private readonly editorService: IEditorService,
@IEditorService editorService: IEditorService,
@IStorageService private readonly storageService: IStorageService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@ITestResultService private readonly testResults: ITestResultService,
@ -368,10 +367,12 @@ export class TestingExplorerViewModel extends Disposable {
this.updatePreferredProjection();
this.onDidChangeSelection = this.tree.onDidChangeSelection;
this._register(this.tree.onDidChangeSelection(evt => {
this._register(this.tree.onDidChangeSelection(async evt => {
const selected = evt.elements[0];
if (selected && evt.browserEvent && !selected.children.size) {
this.openEditorForItem(selected);
if (selected && evt.browserEvent && selected.expandable === TestItemExpandState.NotExpandable) {
if (!(await this.tryPeekError(selected)) && selected?.test) {
this.instantiationService.invokeFunction(accessor => new EditFocusedTest().run(accessor, selected.test!.item, true));
}
}
}));
@ -469,30 +470,6 @@ export class TestingExplorerViewModel extends Disposable {
this.tree.collapseAll();
}
/**
* Opens an editor for the item. If there is a failure associated with the
* test item, it will be shown.
*/
public async openEditorForItem(item: ITestTreeElement, preserveFocus = true) {
if (await this.tryPeekError(item)) {
return;
}
const pane = await this.editorService.openEditor({
resource: item.uri,
options: {
selection: item.range && { startColumn: item.range.startColumn, startLineNumber: item.range.startLineNumber },
preserveFocus,
},
});
// if the user selected a failed test and now they didn't, hide the peek
const control = pane?.getControl();
if (isCodeEditor(control)) {
TestingOutputPeekController.get(control).removePeek();
}
}
/**
* Tries to peek the first test error, if the item is in a failed state.
*/
@ -908,7 +885,7 @@ const getTestItemActions = (
const result = { primary, secondary };
const actionsDisposable = createAndFillInActionBarActions(menu, {
arg: element.test?.item.extId,
arg: element.test?.item,
shouldForwardArgs: true,
}, result, 'inline');