mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
@@ -26,7 +26,7 @@
|
||||
.test-explorer .monaco-list-row .codicon-testing-hidden {
|
||||
display: none;
|
||||
flex-shrink: 0;
|
||||
margin-right: 1px;
|
||||
margin-right: 0.8em;
|
||||
}
|
||||
|
||||
.test-explorer .monaco-list-row:hover .monaco-action-bar,
|
||||
@@ -128,7 +128,8 @@
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget.test-output-peek .test-output-peek-message-container {
|
||||
.monaco-editor .zone-widget.test-output-peek .test-output-peek-message-container,
|
||||
.monaco-editor .zone-widget.test-output-peek .test-output-peek-tree {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -144,6 +145,7 @@
|
||||
.monaco-editor .zone-widget.test-output-peek .preview-text p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/** -- filter */
|
||||
.testing-filter-action-bar {
|
||||
flex-shrink: 0;
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Codicon } from 'vs/base/common/codicons';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { KeyChord, 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 { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -31,12 +30,12 @@ import { IActionableTestTreeElement, TestItemTreeElement } from 'vs/workbench/co
|
||||
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 { ITestingOutputTerminalService } from 'vs/workbench/contrib/testing/browser/testingOutputTerminalService';
|
||||
import { TestExplorerViewMode, TestExplorerViewSorting, Testing } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { InternalTestItem, ITestItem, TestIdPath, TestIdWithSrc } 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 { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { getPathForTestInResult, ITestResult } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
@@ -625,6 +624,7 @@ export class GoToTest extends Action2 {
|
||||
const { range, uri, extId } = element.test.item;
|
||||
|
||||
accessor.get(ITestExplorerFilterState).reveal.value = [extId];
|
||||
accessor.get(ITestingPeekOpener).closeAllPeeks();
|
||||
|
||||
let isFile = true;
|
||||
try {
|
||||
@@ -640,7 +640,7 @@ export class GoToTest extends Action2 {
|
||||
return;
|
||||
}
|
||||
|
||||
const pane = await editorService.openEditor({
|
||||
await editorService.openEditor({
|
||||
resource: uri,
|
||||
options: {
|
||||
selection: range
|
||||
@@ -649,12 +649,6 @@ export class GoToTest extends Action2 {
|
||||
preserveFocus: preserveFocus === true,
|
||||
},
|
||||
});
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -680,6 +674,7 @@ export class GoToTest extends Action2 {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
|
||||
accessor.get(ITestExplorerFilterState).reveal.value = [test.extId];
|
||||
accessor.get(ITestingPeekOpener).closeAllPeeks();
|
||||
|
||||
let isFile = true;
|
||||
try {
|
||||
@@ -695,7 +690,7 @@ export class GoToTest extends Action2 {
|
||||
return;
|
||||
}
|
||||
|
||||
const pane = await editorService.openEditor({
|
||||
await editorService.openEditor({
|
||||
resource: test.uri,
|
||||
options: {
|
||||
selection: test.range
|
||||
@@ -704,12 +699,6 @@ export class GoToTest extends Action2 {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,41 +943,47 @@ export class DebugCurrentFile extends RunOrDebugCurrentFile {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class RunOrDebugExtsById extends Action2 {
|
||||
export const runTestsByPath = async (
|
||||
workspaceTests: IWorkspaceTestCollectionService,
|
||||
progress: IProgressService,
|
||||
paths: ReadonlyArray<TestIdPath>,
|
||||
runTests: (tests: ReadonlyArray<InternalTestItem>) => Promise<ITestResult>,
|
||||
): Promise<ITestResult | undefined> => {
|
||||
const subscription = workspaceTests.subscribeToWorkspaceTests();
|
||||
try {
|
||||
const todo = Promise.all([...subscription.workspaceFolderCollections.values()].map(
|
||||
c => Promise.all(paths.map(p => getTestByPath(c, p))),
|
||||
));
|
||||
|
||||
const tests = flatten(await showDiscoveringWhile(progress, todo)).filter(isDefined);
|
||||
return tests.length ? await runTests(tests) : undefined;
|
||||
} finally {
|
||||
subscription.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
abstract class RunOrDebugExtsByPath extends Action2 {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public async run(accessor: ServicesAccessor) {
|
||||
public async run(accessor: ServicesAccessor, ...args: unknown[]) {
|
||||
const testService = accessor.get(ITestService);
|
||||
const paths = [...this.getTestExtIdsToRun(accessor)];
|
||||
if (paths.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workspaceTests = accessor.get(IWorkspaceTestCollectionService).subscribeToWorkspaceTests();
|
||||
|
||||
try {
|
||||
const todo = Promise.all([...workspaceTests.workspaceFolderCollections.values()].map(
|
||||
c => Promise.all(paths.map(p => getTestByPath(c, p))),
|
||||
));
|
||||
|
||||
const tests = flatten(await showDiscoveringWhile(accessor.get(IProgressService), todo)).filter(isDefined);
|
||||
if (tests.length) {
|
||||
await this.runTest(testService, tests);
|
||||
}
|
||||
} finally {
|
||||
workspaceTests.dispose();
|
||||
}
|
||||
await runTestsByPath(
|
||||
accessor.get(IWorkspaceTestCollectionService),
|
||||
accessor.get(IProgressService),
|
||||
[...this.getTestExtIdsToRun(accessor, ...args)],
|
||||
tests => this.runTest(testService, tests),
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract getTestExtIdsToRun(accessor: ServicesAccessor): Iterable<TestIdPath>;
|
||||
protected abstract getTestExtIdsToRun(accessor: ServicesAccessor, ...args: unknown[]): Iterable<TestIdPath>;
|
||||
|
||||
protected abstract filter(node: InternalTestItem): boolean;
|
||||
|
||||
protected abstract runTest(service: ITestService, node: InternalTestItem[]): Promise<ITestResult>;
|
||||
protected abstract runTest(service: ITestService, node: readonly InternalTestItem[]): Promise<ITestResult>;
|
||||
}
|
||||
|
||||
abstract class RunOrDebugFailedTests extends RunOrDebugExtsById {
|
||||
abstract class RunOrDebugFailedTests extends RunOrDebugExtsByPath {
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@@ -1012,12 +1007,13 @@ abstract class RunOrDebugFailedTests extends RunOrDebugExtsById {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class RunOrDebugLastRun extends RunOrDebugExtsById {
|
||||
abstract class RunOrDebugLastRun extends RunOrDebugExtsByPath {
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected *getTestExtIdsToRun(accessor: ServicesAccessor): Iterable<TestIdPath> {
|
||||
const lastResult = accessor.get(ITestResultService).results[0];
|
||||
protected *getTestExtIdsToRun(accessor: ServicesAccessor, runId?: string): Iterable<TestIdPath> {
|
||||
const resultService = accessor.get(ITestResultService);
|
||||
const lastResult = runId ? resultService.results.find(r => r.id === runId) : resultService.results[0];
|
||||
if (!lastResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { Extensions as ViewContainerExtensions, IViewContainersRegistry, IViewsRegistry, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
@@ -19,23 +20,24 @@ import { testingViewIcon } from 'vs/workbench/contrib/testing/browser/icons';
|
||||
import { TestingDecorations } from 'vs/workbench/contrib/testing/browser/testingDecorations';
|
||||
import { ITestExplorerFilterState, TestExplorerFilterState } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter';
|
||||
import { TestingExplorerView } from 'vs/workbench/contrib/testing/browser/testingExplorerView';
|
||||
import { CloseTestPeek, ITestingPeekOpener, TestingOutputPeekController, TestingPeekOpener } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
|
||||
import { CloseTestPeek, TestingOutputPeekController, TestingPeekOpener } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
|
||||
import { ITestingOutputTerminalService, TestingOutputTerminalService } from 'vs/workbench/contrib/testing/browser/testingOutputTerminalService';
|
||||
import { ITestingProgressUiService, TestingProgressUiService } from 'vs/workbench/contrib/testing/browser/testingProgressUiService';
|
||||
import { TestingViewPaneContainer } from 'vs/workbench/contrib/testing/browser/testingViewPaneContainer';
|
||||
import { testingConfiguation } from 'vs/workbench/contrib/testing/common/configuration';
|
||||
import { Testing } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { TestIdPath, TestIdWithSrc } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestIdPath, TestIdWithMaybeSrc, TestIdWithSrc } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { ITestingAutoRun, TestingAutoRun } from 'vs/workbench/contrib/testing/common/testingAutoRun';
|
||||
import { TestingContentProvider } from 'vs/workbench/contrib/testing/common/testingContentProvider';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { ITestResultService, TestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { ITestResultStorage, TestResultStorage } from 'vs/workbench/contrib/testing/common/testResultStorage';
|
||||
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { TestService } from 'vs/workbench/contrib/testing/common/testServiceImpl';
|
||||
import { IWorkspaceTestCollectionService, WorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { allTestActions } from './testExplorerActions';
|
||||
import { allTestActions, runTestsByPath } from './testExplorerActions';
|
||||
|
||||
registerSingleton(ITestService, TestService);
|
||||
registerSingleton(ITestResultStorage, TestResultStorage);
|
||||
@@ -108,9 +110,9 @@ registerEditorContribution(Testing.DecorationsContributionId, TestingDecorations
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'vscode.runTests',
|
||||
handler: async (accessor: ServicesAccessor, tests: TestIdWithSrc[]) => {
|
||||
handler: async (accessor: ServicesAccessor, tests: TestIdWithMaybeSrc[]) => {
|
||||
const testService = accessor.get(ITestService);
|
||||
testService.runTests({ debug: false, tests: tests.filter(t => t.src && t.testId) });
|
||||
testService.runTests({ debug: false, tests: tests.filter(t => !!t.testId) });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -140,4 +142,20 @@ CommandsRegistry.registerCommand({
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'vscode.runTestsByPath',
|
||||
handler: async (accessor: ServicesAccessor, debug: boolean, ...pathToTests: TestIdPath[]) => {
|
||||
const testService = accessor.get(ITestService);
|
||||
await runTestsByPath(
|
||||
accessor.get(IWorkspaceTestCollectionService),
|
||||
accessor.get(IProgressService),
|
||||
pathToTests,
|
||||
tests => testService.runTests({
|
||||
debug: false,
|
||||
tests: tests.map(t => ({ testId: t.item.extId, src: t.src })),
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).registerConfiguration(testingConfiguation);
|
||||
|
||||
@@ -51,7 +51,7 @@ import { HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/brows
|
||||
import { IActionableTestTreeElement, isActionableTestTreeElement, ITestTreeProjection, TestExplorerTreeElement, TestItemTreeElement, TestTreeErrorMessage, TestTreeWorkspaceFolder } from 'vs/workbench/contrib/testing/browser/explorerProjections/index';
|
||||
import { testingHiddenIcon, testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons';
|
||||
import { ITestExplorerFilterState, TestExplorerFilterState, TestingExplorerFilter } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter';
|
||||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
|
||||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { ITestingProgressUiService } from 'vs/workbench/contrib/testing/browser/testingProgressUiService';
|
||||
import { getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration';
|
||||
import { TestExplorerStateFilter, TestExplorerViewMode, TestExplorerViewSorting, Testing, testStateNames } from 'vs/workbench/contrib/testing/common/constants';
|
||||
|
||||
@@ -34,7 +34,7 @@ import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/br
|
||||
import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { getOuterEditor, IPeekViewService, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground, PeekViewWidget } from 'vs/editor/contrib/peekView/peekView';
|
||||
import { getOuterEditor, IPeekViewService, peekViewResultsBackground, peekViewResultsMatchForeground, peekViewResultsSelectionBackground, peekViewResultsSelectionForeground, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground, PeekViewWidget } from 'vs/editor/contrib/peekView/peekView';
|
||||
import { localize } from 'vs/nls';
|
||||
import { createAndFillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
@@ -43,21 +43,23 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { createDecorator, IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService';
|
||||
import { IColorTheme, IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IColorTheme, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { TestResultState } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
|
||||
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
|
||||
import { flatTestItemDelimiter } from 'vs/workbench/contrib/testing/browser/explorerProjections/display';
|
||||
import { testingStatesToIcons, testMessageSeverityToIcons } from 'vs/workbench/contrib/testing/browser/icons';
|
||||
import * as icons from 'vs/workbench/contrib/testing/browser/icons';
|
||||
import { ITestingOutputTerminalService } from 'vs/workbench/contrib/testing/browser/testingOutputTerminalService';
|
||||
import { testingPeekBorder } from 'vs/workbench/contrib/testing/browser/theme';
|
||||
import { AutoOpenPeekViewWhen, getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration';
|
||||
import { Testing } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { IRichLocation, ITestItem, ITestMessage, ITestRunTask, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { buildTestUri, parseTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri';
|
||||
import { getPathForTestInResult, ITestResult, maxCountPriority, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
@@ -84,18 +86,6 @@ class TestDto {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ITestingPeekOpener {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Tries to peek the first test error, if the item is in a failed state.
|
||||
* @returns a boolean indicating whether a peek was opened
|
||||
*/
|
||||
tryPeekFirstError(result: ITestResult, test: TestResultItem, options?: Partial<ITextEditorOptions>): Promise<boolean>;
|
||||
}
|
||||
|
||||
export const ITestingPeekOpener = createDecorator<ITestingPeekOpener>('testingPeekOpener');
|
||||
|
||||
export class TestingPeekOpener extends Disposable implements ITestingPeekOpener {
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
@@ -109,10 +99,7 @@ export class TestingPeekOpener extends Disposable implements ITestingPeekOpener
|
||||
this._register(testResults.onTestChanged(this.openPeekOnFailure, this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to peek the first test error, if the item is in a failed state.
|
||||
* @returns a boolean if a peek was opened
|
||||
*/
|
||||
/** @inheritdoc */
|
||||
public async tryPeekFirstError(result: ITestResult, test: TestResultItem, options?: Partial<ITextEditorOptions>) {
|
||||
const candidate = this.getCandidateMessage(test);
|
||||
if (!candidate) {
|
||||
@@ -141,6 +128,13 @@ export class TestingPeekOpener extends Disposable implements ITestingPeekOpener
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public closeAllPeeks() {
|
||||
for (const editor of this.codeEditorService.listCodeEditors()) {
|
||||
TestingOutputPeekController.get(editor).removePeek();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the peek view on a test failure, based on user preferences.
|
||||
*/
|
||||
@@ -766,7 +760,7 @@ export class TestResultElement implements ITreeElement {
|
||||
public readonly label = this.value.name;
|
||||
|
||||
public get icon() {
|
||||
return testingStatesToIcons.get(
|
||||
return icons.testingStatesToIcons.get(
|
||||
this.value.completedAt === undefined
|
||||
? TestResultState.Running
|
||||
: maxCountPriority(this.value.counts)
|
||||
@@ -778,22 +772,22 @@ export class TestResultElement implements ITreeElement {
|
||||
|
||||
export class TestCaseElement implements ITreeElement {
|
||||
public readonly type = 'test';
|
||||
public readonly context = this.value.item.extId;
|
||||
public readonly id = `${this.results.id}/${this.value.item.extId}`;
|
||||
public readonly label = this.value.item.label;
|
||||
public readonly context = this.test.item.extId;
|
||||
public readonly id = `${this.results.id}/${this.test.item.extId}`;
|
||||
public readonly label = this.test.item.label;
|
||||
public readonly description?: string;
|
||||
|
||||
public get icon() {
|
||||
return testingStatesToIcons.get(this.value.computedState);
|
||||
return icons.testingStatesToIcons.get(this.test.computedState);
|
||||
}
|
||||
|
||||
public get path() {
|
||||
return getPathForTestInResult(this.value, this.results);
|
||||
return getPathForTestInResult(this.test, this.results);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly results: ITestResult,
|
||||
public readonly value: TestResultItem,
|
||||
public readonly test: TestResultItem,
|
||||
) {
|
||||
for (const parent of this.parents()) {
|
||||
this.description = this.description
|
||||
@@ -804,7 +798,7 @@ export class TestCaseElement implements ITreeElement {
|
||||
|
||||
private *parents() {
|
||||
for (
|
||||
let parent = this.value.parent && this.results.getStateById(this.value.parent);
|
||||
let parent = this.test.parent && this.results.getStateById(this.test.parent);
|
||||
parent;
|
||||
parent = parent.parent && this.results.getStateById(parent.parent)
|
||||
) {
|
||||
@@ -825,7 +819,7 @@ class TestTaskElement implements ITreeElement {
|
||||
return getPathForTestInResult(this.test, this.results);
|
||||
}
|
||||
|
||||
constructor(private readonly results: ITestResult, private readonly test: TestResultItem, index: number) {
|
||||
constructor(private readonly results: ITestResult, public readonly test: TestResultItem, index: number) {
|
||||
this.id = `${results.id}/${test.item.extId}/${index}`;
|
||||
this.task = results.tasks[index];
|
||||
this.context = String(index);
|
||||
@@ -861,7 +855,7 @@ class TestMessageElement implements ITreeElement {
|
||||
|
||||
this.id = this.uri.toString();
|
||||
this.label = firstLine(renderStringAsPlaintext(message));
|
||||
this.icon = testMessageSeverityToIcons.get(severity);
|
||||
this.icon = icons.testMessageSeverityToIcons.get(severity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1155,9 +1149,9 @@ class TreeActionsProvider {
|
||||
) { }
|
||||
|
||||
public provideActionBar(element: ITreeElement) {
|
||||
const test = element instanceof TestCaseElement ? element.value : undefined;
|
||||
const test = element instanceof TestCaseElement ? element.test : undefined;
|
||||
const contextOverlay = this.contextKeyService.createOverlay([
|
||||
['view', Testing.OutputPeekContributionId],
|
||||
['peek', Testing.OutputPeekContributionId],
|
||||
[TestingContextKeys.peekItemType.key, element.type],
|
||||
[TestingContextKeys.testItemExtId.key, test?.item.extId],
|
||||
[TestingContextKeys.testItemHasUri.key, !!test?.item.uri],
|
||||
@@ -1172,23 +1166,62 @@ class TreeActionsProvider {
|
||||
|
||||
if (element instanceof TestResultElement) {
|
||||
primary.push(new Action(
|
||||
'testing.showResultOutput',
|
||||
'testing.outputPeek.showResultOutput',
|
||||
localize('testing.showResultOutput', "Show Result Output"),
|
||||
Codicon.terminal.classNames,
|
||||
undefined,
|
||||
() => this.testTerminalService.open(element.value)
|
||||
));
|
||||
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.reRunLastRun',
|
||||
localize('testing.reRunLastRun', "Rerun Test Run"),
|
||||
ThemeIcon.asClassName(icons.testingRunIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('testing.reRunLastRun', element.value.id),
|
||||
));
|
||||
|
||||
if (Iterable.some(element.value.tests, t => t.item.debuggable)) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.debugLastRun',
|
||||
localize('testing.debugLastRun', "Debug Test Run"),
|
||||
ThemeIcon.asClassName(icons.testingDebugIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('testing.debugLastRun', element.value.id),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof TestCaseElement || element instanceof TestTaskElement) {
|
||||
primary.push(new Action(
|
||||
'testing.revealInExplorer',
|
||||
'testing.outputPeek.revealInExplorer',
|
||||
localize('testing.revealInExplorer', "Reveal in Test Explorer"),
|
||||
Codicon.listTree.classNames,
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.revealTestInExplorer', element.path),
|
||||
));
|
||||
|
||||
if (element.test.item.runnable) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.runTest',
|
||||
localize('run test', 'Run Test'),
|
||||
ThemeIcon.asClassName(icons.testingRunIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.runTestsByPath', false, element.path),
|
||||
));
|
||||
}
|
||||
|
||||
if (element.test.item.debuggable) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.debugTest',
|
||||
localize('debug test', 'Debug Test'),
|
||||
ThemeIcon.asClassName(icons.testingDebugIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.runTestsByPath', true, element.path),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
const result = { primary, secondary };
|
||||
const actionsDisposable = createAndFillInActionBarActions(menu, {
|
||||
shouldForwardArgs: true,
|
||||
@@ -1200,3 +1233,32 @@ class TreeActionsProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const resultsBackground = theme.getColor(peekViewResultsBackground);
|
||||
if (resultsBackground) {
|
||||
collector.addRule(`.monaco-editor .test-output-peek .test-output-peek-tree { background-color: ${resultsBackground}; }`);
|
||||
}
|
||||
const resultsMatchForeground = theme.getColor(peekViewResultsMatchForeground);
|
||||
if (resultsMatchForeground) {
|
||||
collector.addRule(`.monaco-editor .test-output-peek .test-output-peek-tree { color: ${resultsMatchForeground}; }`);
|
||||
}
|
||||
const resultsSelectedBackground = theme.getColor(peekViewResultsSelectionBackground);
|
||||
if (resultsSelectedBackground) {
|
||||
collector.addRule(`.monaco-editor .test-output-peek .test-output-peek-tree .monaco-list:focus .monaco-list-rows > .monaco-list-row.selected:not(.highlighted) { background-color: ${resultsSelectedBackground}; }`);
|
||||
}
|
||||
const resultsSelectedForeground = theme.getColor(peekViewResultsSelectionForeground);
|
||||
if (resultsSelectedForeground) {
|
||||
collector.addRule(`.monaco-editor .test-output-peek .test-output-peek-tree .monaco-list:focus .monaco-list-rows > .monaco-list-row.selected:not(.highlighted) { color: ${resultsSelectedForeground} !important; }`);
|
||||
}
|
||||
|
||||
const textLinkForegroundColor = theme.getColor(textLinkForeground);
|
||||
if (textLinkForegroundColor) {
|
||||
collector.addRule(`.monaco-editor .test-output-peek .test-output-peek-message-container a { color: ${textLinkForegroundColor}; }`);
|
||||
}
|
||||
|
||||
const textLinkActiveForegroundColor = theme.getColor(textLinkActiveForeground);
|
||||
if (textLinkActiveForegroundColor) {
|
||||
collector.addRule(`.monaco-editor .test-output-peek .test-output-peek-message-container a :hover { color: ${textLinkActiveForegroundColor}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { ITestResult } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
|
||||
export interface ITestingPeekOpener {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Tries to peek the first test error, if the item is in a failed state.
|
||||
* @returns a boolean indicating whether a peek was opened
|
||||
*/
|
||||
tryPeekFirstError(result: ITestResult, test: TestResultItem, options?: Partial<ITextEditorOptions>): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Closes peeks for all visible editors.
|
||||
*/
|
||||
closeAllPeeks(): void;
|
||||
}
|
||||
|
||||
export const ITestingPeekOpener = createDecorator<ITestingPeekOpener>('testingPeekOpener');
|
||||
|
||||
Reference in New Issue
Block a user