testing: make test ids locally unique, instead of globally unique
This commit is contained in:
parent
42c268a626
commit
da7d92b8b1
11
src/vs/vscode.proposed.d.ts
vendored
11
src/vs/vscode.proposed.d.ts
vendored
|
@ -2190,11 +2190,11 @@ declare module 'vscode' {
|
|||
*/
|
||||
export interface TestItem {
|
||||
/**
|
||||
* Unique identifier for the TestItem. This is used to correlate
|
||||
* Identifier for the TestItem. This is used to correlate
|
||||
* test results and tests in the document with those in the workspace
|
||||
* (test explorer). This must not change for the lifetime of the TestItem.
|
||||
* (test explorer). This cannot change for the lifetime of the TestItem,
|
||||
* and must be unique among its parent's direct children.
|
||||
*/
|
||||
// todo@API globally vs extension vs controller unique. I would strongly recommend non-global
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
|
@ -2380,6 +2380,11 @@ declare module 'vscode' {
|
|||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* Parent of this item.
|
||||
*/
|
||||
readonly parent?: TestResultSnapshot;
|
||||
|
||||
/**
|
||||
* URI this TestItem is associated with. May be a file or file.
|
||||
*/
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
@ -18,11 +17,12 @@ import { generateUuid } from 'vs/base/common/uuid';
|
|||
import { ExtHostTestingShape, MainContext, MainThreadTestingShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { TestItemImpl } from 'vs/workbench/api/common/extHostTestingPrivateApi';
|
||||
import { TestItemImpl, TestItemRootImpl } from 'vs/workbench/api/common/extHostTestingPrivateApi';
|
||||
import * as Convert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { TestRunProfileGroup, TestRunRequest } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { SingleUseTestCollection, TestPosition } from 'vs/workbench/contrib/testing/common/ownedTestCollection';
|
||||
import { SingleUseTestCollection } from 'vs/workbench/contrib/testing/common/ownedTestCollection';
|
||||
import { AbstractIncrementalTestCollection, CoverageDetails, IFileCoverage, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, ISerializedTestResults, ITestIdWithSrc, ITestItem, RunTestForControllerRequest, TestRunProfileBitset, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestId, TestIdPathParts, TestPosition } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import type * as vscode from 'vscode';
|
||||
|
||||
interface ControllerInfo {
|
||||
|
@ -58,7 +58,6 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
|||
public createTestController(controllerId: string, label: string): vscode.TestController {
|
||||
const disposable = new DisposableStore();
|
||||
const collection = disposable.add(new SingleUseTestCollection(controllerId));
|
||||
const initialExpand = disposable.add(new RunOnceScheduler(() => collection.expand(collection.root.id, 0), 0));
|
||||
const profiles = new Map<number, vscode.TestRunProfile>();
|
||||
const proxy = this.proxy;
|
||||
|
||||
|
@ -92,9 +91,6 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
|||
},
|
||||
set resolveChildrenHandler(fn) {
|
||||
collection.resolveHandler = fn;
|
||||
if (fn) {
|
||||
initialExpand.schedule();
|
||||
}
|
||||
},
|
||||
get resolveChildrenHandler() {
|
||||
return collection.resolveHandler;
|
||||
|
@ -239,7 +235,7 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
|||
.map(id => lookup.collection.tree.get(id))
|
||||
.filter(isDefined)
|
||||
.filter(exclude => includeTests.some(
|
||||
include => collection.tree.comparePositions(include, exclude) === TestPosition.IsChild,
|
||||
include => include.fullId.compare(exclude.fullId) === TestPosition.IsChild,
|
||||
));
|
||||
|
||||
if (!includeTests.length) {
|
||||
|
@ -247,7 +243,7 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
|||
}
|
||||
|
||||
const publicReq = new TestRunRequest(
|
||||
includeTests.map(t => t.actual),
|
||||
includeTests.some(i => i.actual instanceof TestItemRootImpl) ? undefined : includeTests.map(t => t.actual),
|
||||
excludeTests.map(t => t.actual),
|
||||
profile,
|
||||
);
|
||||
|
@ -437,12 +433,15 @@ const tryGetProfileFromTestRunReq = (request: vscode.TestRunRequest) => {
|
|||
};
|
||||
|
||||
export class TestRunDto {
|
||||
private readonly includePrefix: string[];
|
||||
private readonly excludePrefix: string[];
|
||||
|
||||
public static fromPublic(controllerId: string, collection: SingleUseTestCollection, request: vscode.TestRunRequest) {
|
||||
return new TestRunDto(
|
||||
controllerId,
|
||||
generateUuid(),
|
||||
request.include && new Set(request.include.map(t => t.id)),
|
||||
new Set(request.exclude?.map(t => t.id) ?? Iterable.empty()),
|
||||
request.include?.map(t => TestId.fromExtHostTestItem(t, controllerId).toString()) ?? [controllerId],
|
||||
request.exclude?.map(t => TestId.fromExtHostTestItem(t, controllerId).toString()) ?? [],
|
||||
collection,
|
||||
);
|
||||
}
|
||||
|
@ -451,8 +450,8 @@ export class TestRunDto {
|
|||
return new TestRunDto(
|
||||
request.controllerId,
|
||||
request.runId,
|
||||
request.testIds.includes(collection.root.id) ? undefined : new Set(request.testIds),
|
||||
new Set(request.excludeExtIds),
|
||||
request.testIds,
|
||||
request.excludeExtIds,
|
||||
collection,
|
||||
);
|
||||
}
|
||||
|
@ -460,21 +459,29 @@ export class TestRunDto {
|
|||
constructor(
|
||||
public readonly controllerId: string,
|
||||
public readonly id: string,
|
||||
private readonly include: ReadonlySet<string> | undefined,
|
||||
private readonly exclude: ReadonlySet<string>,
|
||||
include: string[],
|
||||
exclude: string[],
|
||||
public readonly colllection: SingleUseTestCollection,
|
||||
) { }
|
||||
) {
|
||||
this.includePrefix = include.map(id => id + TestIdPathParts.Delimiter);
|
||||
this.excludePrefix = exclude.map(id => id + TestIdPathParts.Delimiter);
|
||||
}
|
||||
|
||||
public isIncluded(test: vscode.TestItem) {
|
||||
for (let t: vscode.TestItem | undefined = test; t; t = t.parent) {
|
||||
if (this.include?.has(t.id)) {
|
||||
return true;
|
||||
} else if (this.exclude.has(t.id)) {
|
||||
const id = TestId.fromExtHostTestItem(test, this.controllerId).toString() + TestIdPathParts.Delimiter;
|
||||
for (const prefix of this.excludePrefix) {
|
||||
if (id === prefix || id.startsWith(prefix)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.include === undefined; // default to true if running all tests with include=undefined
|
||||
for (const prefix of this.includePrefix) {
|
||||
if (id === prefix || id.startsWith(prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,16 +581,18 @@ class TestRunImpl implements vscode.TestRun {
|
|||
}
|
||||
|
||||
setState(test: vscode.TestItem, state: vscode.TestResultState, duration?: number): void {
|
||||
if (!this.#ended && this.#req.isIncluded(test)) {
|
||||
const req = this.#req;
|
||||
if (!this.#ended && req.isIncluded(test)) {
|
||||
this.ensureTestIsKnown(test);
|
||||
this.#proxy.$updateTestStateInRun(this.#req.id, this.taskId, test.id, state, duration);
|
||||
this.#proxy.$updateTestStateInRun(req.id, this.taskId, TestId.fromExtHostTestItem(test, req.controllerId).toString(), state, duration);
|
||||
}
|
||||
}
|
||||
|
||||
appendMessage(test: vscode.TestItem, message: vscode.TestMessage): void {
|
||||
if (!this.#ended && this.#req.isIncluded(test)) {
|
||||
const req = this.#req;
|
||||
if (!this.#ended && req.isIncluded(test)) {
|
||||
this.ensureTestIsKnown(test);
|
||||
this.#proxy.$appendTestMessageInRun(this.#req.id, this.taskId, test.id, Convert.TestMessage.from(message));
|
||||
this.#proxy.$appendTestMessageInRun(req.id, this.taskId, TestId.fromExtHostTestItem(test, req.controllerId).toString(), Convert.TestMessage.from(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,8 +617,9 @@ class TestRunImpl implements vscode.TestRun {
|
|||
}
|
||||
|
||||
const chain: ITestItem[] = [];
|
||||
const root = this.#req.colllection.root;
|
||||
while (true) {
|
||||
chain.unshift(Convert.TestItem.from(test));
|
||||
chain.unshift(Convert.TestItem.from(test, root.id));
|
||||
|
||||
if (sent.has(test.id)) {
|
||||
break;
|
||||
|
@ -623,10 +633,9 @@ class TestRunImpl implements vscode.TestRun {
|
|||
test = test.parent;
|
||||
}
|
||||
|
||||
const root = this.#req.colllection.root;
|
||||
if (!sent.has(root.id)) {
|
||||
sent.add(root.id);
|
||||
chain.unshift(Convert.TestItem.from(root));
|
||||
chain.unshift(Convert.TestItem.from(root, root.id));
|
||||
}
|
||||
|
||||
this.#proxy.$addTestsToRun(this.#req.controllerId, this.#req.id, chain);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TestIdPathParts } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export const enum ExtHostTestItemEventOp {
|
||||
|
@ -242,6 +243,9 @@ export class TestItemImpl implements vscode.TestItem {
|
|||
*/
|
||||
constructor(id: string, label: string, uri: vscode.Uri | undefined) {
|
||||
const api = getPrivateApiFor(this);
|
||||
if (id.includes(TestIdPathParts.Delimiter)) {
|
||||
throw new Error(`Test IDs may not include the ${JSON.stringify(id)} symbol`);
|
||||
}
|
||||
|
||||
Object.defineProperties(this, {
|
||||
id: {
|
||||
|
@ -256,7 +260,9 @@ export class TestItemImpl implements vscode.TestItem {
|
|||
},
|
||||
parent: {
|
||||
enumerable: false,
|
||||
get() { return api.parent; },
|
||||
get() {
|
||||
return api.parent instanceof TestItemRootImpl ? undefined : api.parent;
|
||||
},
|
||||
},
|
||||
children: {
|
||||
value: createTestItemCollection(this),
|
||||
|
@ -272,3 +278,9 @@ export class TestItemImpl implements vscode.TestItem {
|
|||
getPrivateApiFor(this).listener?.({ op: ExtHostTestItemEventOp.Invalidated });
|
||||
}
|
||||
}
|
||||
|
||||
export class TestItemRootImpl extends TestItemImpl {
|
||||
constructor(controllerId: string, label: string) {
|
||||
super(controllerId, label, undefined);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import * as notebooks from 'vs/workbench/contrib/notebook/common/notebookCommon'
|
|||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||
import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import { CoverageDetails, DetailType, ICoveredCount, IFileCoverage, ISerializedTestResults, ITestItem, ITestItemContext, ITestMessage, SerializedTestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import type * as vscode from 'vscode';
|
||||
|
@ -1658,11 +1659,11 @@ export namespace TestMessage {
|
|||
}
|
||||
|
||||
export namespace TestItem {
|
||||
export type Raw<T = unknown> = vscode.TestItem;
|
||||
export type Raw = vscode.TestItem;
|
||||
|
||||
export function from(item: vscode.TestItem): ITestItem {
|
||||
export function from(item: vscode.TestItem, controllerId: string): ITestItem {
|
||||
return {
|
||||
extId: item.id,
|
||||
extId: TestId.fromExtHostTestItem(item, controllerId).toString(),
|
||||
label: item.label,
|
||||
uri: item.uri,
|
||||
range: Range.from(item.range) || null,
|
||||
|
@ -1671,20 +1672,9 @@ export namespace TestItem {
|
|||
};
|
||||
}
|
||||
|
||||
export function fromResultSnapshot(item: vscode.TestResultSnapshot): ITestItem {
|
||||
return {
|
||||
extId: item.id,
|
||||
label: item.label,
|
||||
uri: item.uri,
|
||||
range: Range.from(item.range) || null,
|
||||
description: item.description || null,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
export function toPlain(item: ITestItem): Omit<vscode.TestItem, 'children' | 'invalidate' | 'discoverChildren'> {
|
||||
return {
|
||||
id: item.extId,
|
||||
id: TestId.fromString(item.extId).localId,
|
||||
label: item.label,
|
||||
uri: URI.revive(item.uri),
|
||||
range: Range.to(item.range || undefined),
|
||||
|
@ -1695,8 +1685,8 @@ export namespace TestItem {
|
|||
};
|
||||
}
|
||||
|
||||
export function to(item: ITestItem): TestItemImpl {
|
||||
const testItem = new TestItemImpl(item.extId, item.label, URI.revive(item.uri));
|
||||
function to(item: ITestItem): TestItemImpl {
|
||||
const testItem = new TestItemImpl(TestId.fromString(item.extId).localId, item.label, URI.revive(item.uri));
|
||||
testItem.range = Range.to(item.range || undefined);
|
||||
testItem.description = item.description || undefined;
|
||||
return testItem;
|
||||
|
@ -1715,18 +1705,27 @@ export namespace TestItem {
|
|||
}
|
||||
|
||||
export namespace TestResults {
|
||||
const convertTestResultItem = (item: SerializedTestResultItem, byInternalId: Map<string, SerializedTestResultItem>): vscode.TestResultSnapshot => ({
|
||||
...TestItem.toPlain(item.item),
|
||||
taskStates: item.tasks.map(t => ({
|
||||
state: t.state,
|
||||
duration: t.duration,
|
||||
messages: t.messages.map(TestMessage.to),
|
||||
})),
|
||||
children: item.children
|
||||
.map(c => byInternalId.get(c))
|
||||
.filter(isDefined)
|
||||
.map(c => convertTestResultItem(c, byInternalId)),
|
||||
});
|
||||
const convertTestResultItem = (item: SerializedTestResultItem, byInternalId: Map<string, SerializedTestResultItem>): vscode.TestResultSnapshot => {
|
||||
const snapshot: vscode.TestResultSnapshot = ({
|
||||
...TestItem.toPlain(item.item),
|
||||
parent: undefined,
|
||||
taskStates: item.tasks.map(t => ({
|
||||
state: t.state,
|
||||
duration: t.duration,
|
||||
messages: t.messages.map(TestMessage.to),
|
||||
})),
|
||||
children: item.children
|
||||
.map(c => byInternalId.get(c))
|
||||
.filter(isDefined)
|
||||
.map(c => convertTestResultItem(c, byInternalId))
|
||||
});
|
||||
|
||||
for (const child of snapshot.children) {
|
||||
(child as any).parent = snapshot;
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
};
|
||||
|
||||
export function to(serialized: ISerializedTestResults): vscode.TestRunResult {
|
||||
const roots: SerializedTestResultItem[] = [];
|
||||
|
|
|
@ -29,15 +29,15 @@ import { ITestExplorerFilterState } from 'vs/workbench/contrib/testing/browser/t
|
|||
import type { TestingExplorerView, TestingExplorerViewModel } from 'vs/workbench/contrib/testing/browser/testingExplorerView';
|
||||
import { ITestingOutputTerminalService } from 'vs/workbench/contrib/testing/browser/testingOutputTerminalService';
|
||||
import { TestExplorerViewMode, TestExplorerViewSorting, Testing } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { identifyTest, InternalTestItem, ITestIdWithSrc, ITestItem, ITestRunProfile, TestIdPath, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { identifyTest, InternalTestItem, ITestIdWithSrc, ITestItem, ITestRunProfile, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { ITestProfileService } from 'vs/workbench/contrib/testing/common/testConfigurationService';
|
||||
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 { ITestResult } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { getTestByPath, IMainThreadTestCollection, ITestService, testsInFile } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { expandAndGetTestById, IMainThreadTestCollection, ITestService, testsInFile } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
|
||||
|
@ -660,7 +660,7 @@ export class GoToTest extends Action2 {
|
|||
const editorService = accessor.get(IEditorService);
|
||||
const { range, uri, extId } = element.test.item;
|
||||
|
||||
accessor.get(ITestExplorerFilterState).reveal.value = [extId];
|
||||
accessor.get(ITestExplorerFilterState).reveal.value = extId;
|
||||
accessor.get(ITestingPeekOpener).closeAllPeeks();
|
||||
|
||||
let isFile = true;
|
||||
|
@ -710,7 +710,7 @@ export class GoToTest extends Action2 {
|
|||
const fileService = accessor.get(IFileService);
|
||||
const editorService = accessor.get(IEditorService);
|
||||
|
||||
accessor.get(ITestExplorerFilterState).reveal.value = [test.extId];
|
||||
accessor.get(ITestExplorerFilterState).reveal.value = test.extId;
|
||||
accessor.get(ITestingPeekOpener).closeAllPeeks();
|
||||
|
||||
let isFile = true;
|
||||
|
@ -928,13 +928,13 @@ export class DebugCurrentFile extends ExecuteTestsInCurrentFile {
|
|||
}
|
||||
}
|
||||
|
||||
export const runTestsByPath = async (
|
||||
export const discoverAndRunTests = async (
|
||||
collection: IMainThreadTestCollection,
|
||||
progress: IProgressService,
|
||||
paths: ReadonlyArray<TestIdPath>,
|
||||
ids: ReadonlyArray<string>,
|
||||
runTests: (tests: ReadonlyArray<InternalTestItem>) => Promise<ITestResult>,
|
||||
): Promise<ITestResult | undefined> => {
|
||||
const todo = Promise.all(paths.map(p => getTestByPath(collection, p)));
|
||||
const todo = Promise.all(ids.map(p => expandAndGetTestById(collection, p)));
|
||||
const tests = (await showDiscoveringWhile(progress, todo)).filter(isDefined);
|
||||
return tests.length ? await runTests(tests) : undefined;
|
||||
};
|
||||
|
@ -945,7 +945,7 @@ abstract class RunOrDebugExtsByPath extends Action2 {
|
|||
*/
|
||||
public async run(accessor: ServicesAccessor, ...args: unknown[]) {
|
||||
const testService = accessor.get(ITestService);
|
||||
await runTestsByPath(
|
||||
await discoverAndRunTests(
|
||||
accessor.get(ITestService).collection,
|
||||
accessor.get(IProgressService),
|
||||
[...this.getTestExtIdsToRun(accessor, ...args)],
|
||||
|
@ -953,7 +953,7 @@ abstract class RunOrDebugExtsByPath extends Action2 {
|
|||
);
|
||||
}
|
||||
|
||||
protected abstract getTestExtIdsToRun(accessor: ServicesAccessor, ...args: unknown[]): Iterable<TestIdPath>;
|
||||
protected abstract getTestExtIdsToRun(accessor: ServicesAccessor, ...args: unknown[]): Iterable<string>;
|
||||
|
||||
protected abstract runTest(service: ITestService, node: readonly InternalTestItem[]): Promise<ITestResult>;
|
||||
}
|
||||
|
@ -971,23 +971,21 @@ abstract class RunOrDebugFailedTests extends RunOrDebugExtsByPath {
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected getTestExtIdsToRun(accessor: ServicesAccessor): Iterable<TestIdPath> {
|
||||
protected getTestExtIdsToRun(accessor: ServicesAccessor) {
|
||||
const { results } = accessor.get(ITestResultService);
|
||||
const paths = new Map<string /* id */, string /* path */>();
|
||||
const sep = '$$TEST SEP$$';
|
||||
const ids = new Set<string>();
|
||||
for (let i = results.length - 1; i >= 0; i--) {
|
||||
const resultSet = results[i];
|
||||
for (const test of resultSet.tests) {
|
||||
const path = getPathForTestInResult(test, resultSet).join(sep);
|
||||
if (isFailedState(test.ownComputedState)) {
|
||||
paths.set(test.item.extId, path);
|
||||
ids.add(test.item.extId);
|
||||
} else {
|
||||
paths.delete(test.item.extId);
|
||||
ids.delete(test.item.extId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Iterable.map(paths.values(), p => p.split(sep));
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1008,7 +1006,7 @@ abstract class RunOrDebugLastRun extends RunOrDebugExtsByPath {
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected *getTestExtIdsToRun(accessor: ServicesAccessor, runId?: string): Iterable<TestIdPath> {
|
||||
protected *getTestExtIdsToRun(accessor: ServicesAccessor, runId?: string): Iterable<string> {
|
||||
const resultService = accessor.get(ITestResultService);
|
||||
const lastResult = runId ? resultService.results.find(r => r.id === runId) : resultService.results[0];
|
||||
if (!lastResult) {
|
||||
|
@ -1017,10 +1015,7 @@ abstract class RunOrDebugLastRun extends RunOrDebugExtsByPath {
|
|||
|
||||
for (const test of lastResult.request.targets) {
|
||||
for (const testId of test.testIds) {
|
||||
const test = lastResult.getStateById(testId);
|
||||
if (test) {
|
||||
yield getPathForTestInResult(test, lastResult);
|
||||
}
|
||||
yield testId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1086,7 +1081,7 @@ export class ReRunLastRun extends RunOrDebugLastRun {
|
|||
|
||||
protected runTest(service: ITestService, internalTests: InternalTestItem[]): Promise<ITestResult> {
|
||||
return service.runTests({
|
||||
group: TestRunProfileBitset.Debug,
|
||||
group: TestRunProfileBitset.Run,
|
||||
tests: internalTests.map(identifyTest),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import { ITestingProgressUiService, TestingProgressUiService } from 'vs/workbenc
|
|||
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 { identifyTest, ITestIdWithSrc, TestIdPath, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { identifyTest, ITestIdWithSrc, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { ITestProfileService, TestProfileService } from 'vs/workbench/contrib/testing/common/testConfigurationService';
|
||||
import { ITestingAutoRun, TestingAutoRun } from 'vs/workbench/contrib/testing/common/testingAutoRun';
|
||||
import { TestingContentProvider } from 'vs/workbench/contrib/testing/common/testingContentProvider';
|
||||
|
@ -37,7 +37,7 @@ import { ITestResultStorage, TestResultStorage } from 'vs/workbench/contrib/test
|
|||
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { TestService } from 'vs/workbench/contrib/testing/common/testServiceImpl';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { allTestActions, runTestsByPath } from './testExplorerActions';
|
||||
import { allTestActions, discoverAndRunTests } from './testExplorerActions';
|
||||
import './testingConfigurationUi';
|
||||
|
||||
registerSingleton(ITestService, TestService, true);
|
||||
|
@ -127,8 +127,8 @@ CommandsRegistry.registerCommand({
|
|||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'vscode.revealTestInExplorer',
|
||||
handler: async (accessor: ServicesAccessor, pathToTest: TestIdPath) => {
|
||||
accessor.get(ITestExplorerFilterState).reveal.value = pathToTest;
|
||||
handler: async (accessor: ServicesAccessor, testId: string) => {
|
||||
accessor.get(ITestExplorerFilterState).reveal.value = testId;
|
||||
accessor.get(IViewsService).openView(Testing.ExplorerViewId);
|
||||
}
|
||||
});
|
||||
|
@ -144,13 +144,13 @@ CommandsRegistry.registerCommand({
|
|||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'vscode.runTestsByPath',
|
||||
handler: async (accessor: ServicesAccessor, group: TestRunProfileBitset, ...pathToTests: TestIdPath[]) => {
|
||||
id: 'vscode.runTestsById',
|
||||
handler: async (accessor: ServicesAccessor, group: TestRunProfileBitset, ...testIds: string[]) => {
|
||||
const testService = accessor.get(ITestService);
|
||||
await runTestsByPath(
|
||||
await discoverAndRunTests(
|
||||
accessor.get(ITestService).collection,
|
||||
accessor.get(IProgressService),
|
||||
pathToTests,
|
||||
testIds,
|
||||
tests => testService.runTests({ group, tests: tests.map(identifyTest) }),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -437,20 +437,8 @@ abstract class RunTestDecoration extends Disposable {
|
|||
}));
|
||||
}
|
||||
|
||||
testActions.push(new Action('testing.gutter.reveal', localize('reveal test', 'Reveal in Test Explorer'), undefined, undefined, async () => {
|
||||
const path = [test];
|
||||
while (true) {
|
||||
const parentId = path[0].parent;
|
||||
const parent = parentId && collection.getNodeById(parentId);
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
|
||||
path.unshift(parent);
|
||||
}
|
||||
|
||||
await this.commandService.executeCommand('vscode.revealTestInExplorer', path.map(t => t.item.extId));
|
||||
}));
|
||||
testActions.push(new Action('testing.gutter.reveal', localize('reveal test', 'Reveal in Test Explorer'), undefined, undefined,
|
||||
() => this.commandService.executeCommand('vscode.revealTestInExplorer', test.item.extId)));
|
||||
|
||||
return testActions;
|
||||
}
|
||||
|
|
|
@ -27,19 +27,14 @@ import { testingFilterIcon } from 'vs/workbench/contrib/testing/browser/icons';
|
|||
import { TestExplorerStateFilter, Testing } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { MutableObservableValue } from 'vs/workbench/contrib/testing/common/observableValue';
|
||||
import { StoredValue } from 'vs/workbench/contrib/testing/common/storedValue';
|
||||
import { TestIdPath } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
|
||||
export interface ITestExplorerFilterState {
|
||||
_serviceBrand: undefined;
|
||||
readonly text: MutableObservableValue<string>;
|
||||
/**
|
||||
* Reveal request: the path to the test to reveal. The last element of the
|
||||
* array is the test the user wanted to reveal, and the previous
|
||||
* items are its parents.
|
||||
*/
|
||||
readonly reveal: MutableObservableValue<TestIdPath | undefined>;
|
||||
/** Test ID the user wants to reveal in the explorer */
|
||||
readonly reveal: MutableObservableValue<string | undefined>;
|
||||
readonly stateFilter: MutableObservableValue<TestExplorerStateFilter>;
|
||||
readonly currentDocumentOnly: MutableObservableValue<boolean>;
|
||||
/** Whether excluded test should be shown in the view */
|
||||
|
@ -67,7 +62,7 @@ export class TestExplorerFilterState implements ITestExplorerFilterState {
|
|||
}, this.storage), false);
|
||||
|
||||
public readonly showExcludedTests = new MutableObservableValue(false);
|
||||
public readonly reveal = new MutableObservableValue<TestIdPath | undefined>(undefined);
|
||||
public readonly reveal = new MutableObservableValue</* test ID */string | undefined>(undefined);
|
||||
|
||||
public readonly onDidRequestInputFocus = this.focusEmitter.event;
|
||||
|
||||
|
|
|
@ -55,12 +55,13 @@ import { ITestExplorerFilterState, TestExplorerFilterState, TestingExplorerFilte
|
|||
import { ITestingProgressUiService } from 'vs/workbench/contrib/testing/browser/testingProgressUiService';
|
||||
import { getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration';
|
||||
import { labelForTestInState, TestExplorerStateFilter, TestExplorerViewMode, TestExplorerViewSorting, Testing, testStateNames } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { identifyTest, ITestRunProfile, TestIdPath, TestItemExpandState, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { identifyTest, ITestRunProfile, TestItemExpandState, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { capabilityContextKeys, ITestProfileService } from 'vs/workbench/contrib/testing/common/testConfigurationService';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { cmpPriority, isFailedState, isStateWithResult } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { getPathForTestInResult, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { ITestService, testCollectionIsEmpty } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { ConfigureTestProfilesAction, DebugAllAction, GoToTest, RunAllAction, SelectDefaultTestProfiles } from './testExplorerActions';
|
||||
|
@ -451,7 +452,7 @@ export class TestingExplorerViewModel extends Disposable {
|
|||
}
|
||||
}));
|
||||
|
||||
this._register(filterState.reveal.onDidChange(this.revealByIdPath, this));
|
||||
this._register(filterState.reveal.onDidChange(this.revealById, this));
|
||||
|
||||
this._register(onDidChangeVisibility(visible => {
|
||||
if (visible) {
|
||||
|
@ -495,7 +496,7 @@ export class TestingExplorerViewModel extends Disposable {
|
|||
return;
|
||||
}
|
||||
|
||||
this.revealByIdPath(getPathForTestInResult(evt.item, evt.result), false, false);
|
||||
this.revealById(evt.item.item.extId, false, false);
|
||||
}));
|
||||
|
||||
this._register(testResults.onResultsChanged(evt => {
|
||||
|
@ -525,8 +526,8 @@ export class TestingExplorerViewModel extends Disposable {
|
|||
* Tries to reveal by extension ID. Queues the request if the extension
|
||||
* ID is not currently available.
|
||||
*/
|
||||
private revealByIdPath(idPath: TestIdPath | undefined, expand = true, focus = true) {
|
||||
if (!idPath) {
|
||||
private revealById(id: string | undefined, expand = true, focus = true) {
|
||||
if (!id) {
|
||||
this.hasPendingReveal = false;
|
||||
return;
|
||||
}
|
||||
|
@ -538,6 +539,7 @@ export class TestingExplorerViewModel extends Disposable {
|
|||
// If the item itself is visible in the tree, show it. Otherwise, expand
|
||||
// its closest parent.
|
||||
let expandToLevel = 0;
|
||||
const idPath = [...TestId.fromString(id).idsFromRoot()];
|
||||
for (let i = idPath.length - 1; i >= expandToLevel; i--) {
|
||||
const element = this.projection.value.getElementByTestId(idPath[i]);
|
||||
// Skip all elements that aren't in the tree.
|
||||
|
@ -687,7 +689,7 @@ export class TestingExplorerViewModel extends Disposable {
|
|||
this.projection.value?.applyTo(this.tree);
|
||||
|
||||
if (this.hasPendingReveal) {
|
||||
this.revealByIdPath(this.filterState.reveal.value);
|
||||
this.revealById(this.filterState.reveal.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingC
|
|||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { buildTestUri, ParsedTestUri, parseTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri';
|
||||
import { getPathForTestInResult, ITestResult, maxCountPriority, resultItemParents, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { ITestResult, maxCountPriority, resultItemParents, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { ITestResultService, ResultChangeEvent } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
@ -900,10 +900,6 @@ export class TestCaseElement implements ITreeElement {
|
|||
return icons.testingStatesToIcons.get(this.test.computedState);
|
||||
}
|
||||
|
||||
public get path() {
|
||||
return getPathForTestInResult(this.test, this.results);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly results: ITestResult,
|
||||
public readonly test: TestResultItem,
|
||||
|
@ -926,11 +922,7 @@ class TestTaskElement implements ITreeElement {
|
|||
public readonly label: string;
|
||||
public readonly icon = undefined;
|
||||
|
||||
public get path() {
|
||||
return getPathForTestInResult(this.test, this.results);
|
||||
}
|
||||
|
||||
constructor(private readonly results: ITestResult, public readonly test: TestResultItem, index: number) {
|
||||
constructor(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);
|
||||
|
@ -1318,12 +1310,13 @@ class TreeActionsProvider {
|
|||
}
|
||||
|
||||
if (element instanceof TestCaseElement || element instanceof TestTaskElement) {
|
||||
const extId = element.test.item.extId;
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.revealInExplorer',
|
||||
localize('testing.revealInExplorer', "Reveal in Test Explorer"),
|
||||
Codicon.listTree.classNames,
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.revealTestInExplorer', element.path),
|
||||
() => this.commandService.executeCommand('vscode.revealTestInExplorer', extId),
|
||||
));
|
||||
|
||||
if (capabilities & TestRunProfileBitset.Run) {
|
||||
|
@ -1332,17 +1325,17 @@ class TreeActionsProvider {
|
|||
localize('run test', 'Run Test'),
|
||||
ThemeIcon.asClassName(icons.testingRunIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.runTestsByPath', false, element.path),
|
||||
() => this.commandService.executeCommand('vscode.runTestsById', TestRunProfileBitset.Run, extId),
|
||||
));
|
||||
}
|
||||
|
||||
if (capabilities & TestRunProfileBitset.Coverage) {
|
||||
if (capabilities & TestRunProfileBitset.Debug) {
|
||||
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),
|
||||
() => this.commandService.executeCommand('vscode.runTestsById', TestRunProfileBitset.Debug, extId),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
|||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { assertNever } from 'vs/base/common/types';
|
||||
import { diffTestItems, ExtHostTestItemEvent, ExtHostTestItemEventOp, getPrivateApiFor, TestItemImpl } from 'vs/workbench/api/common/extHostTestingPrivateApi';
|
||||
import { diffTestItems, ExtHostTestItemEvent, ExtHostTestItemEventOp, getPrivateApiFor, TestItemImpl, TestItemRootImpl } from 'vs/workbench/api/common/extHostTestingPrivateApi';
|
||||
import * as Convert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { applyTestItemUpdate, TestDiffOpType, TestItemExpandState, TestsDiff, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
|
||||
type TestItemRaw = Convert.TestItem.Raw;
|
||||
|
||||
|
@ -22,9 +23,10 @@ export interface IHierarchyProvider {
|
|||
* @private
|
||||
*/
|
||||
export interface OwnedCollectionTestItem {
|
||||
expand: TestItemExpandState;
|
||||
parent: string | null;
|
||||
readonly fullId: TestId;
|
||||
readonly parent: TestId | null;
|
||||
actual: TestItemImpl;
|
||||
expand: TestItemExpandState;
|
||||
/**
|
||||
* Number of levels of items below this one that are expanded. May be infinite.
|
||||
*/
|
||||
|
@ -32,118 +34,6 @@ export interface OwnedCollectionTestItem {
|
|||
resolveBarrier?: Barrier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum for describing relative positions of tests. Similar to
|
||||
* `node.compareDocumentPosition` in the DOM.
|
||||
*/
|
||||
export const enum TestPosition {
|
||||
/** Neither a nor b are a child of one another. They may share a common parent, though. */
|
||||
Disconnected,
|
||||
/** b is a child of a */
|
||||
IsChild,
|
||||
/** b is a parent of a */
|
||||
IsParent,
|
||||
/** a === b */
|
||||
IsSame,
|
||||
}
|
||||
|
||||
/**
|
||||
* Test tree is (or will be after debt week 2020-03) the standard collection
|
||||
* for test trees. Internally it indexes tests by their extension ID in
|
||||
* a map.
|
||||
*/
|
||||
export class TestTree<T extends OwnedCollectionTestItem> {
|
||||
private readonly map = new Map<string, T>();
|
||||
private readonly _roots = new Set<T>();
|
||||
public readonly roots: ReadonlySet<T> = this._roots;
|
||||
|
||||
/**
|
||||
* Gets the size of the tree.
|
||||
*/
|
||||
public get size() {
|
||||
return this.map.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new test to the tree if it doesn't exist.
|
||||
* @throws if a duplicate item is inserted
|
||||
*/
|
||||
public add(test: T) {
|
||||
if (this.map.has(test.actual.id)) {
|
||||
throw new Error(`Attempted to insert a duplicate test item ID ${test.actual.id}`);
|
||||
}
|
||||
|
||||
this.map.set(test.actual.id, test);
|
||||
if (!test.parent) {
|
||||
this._roots.add(test);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the test exists in the tree.
|
||||
*/
|
||||
public has(testId: string) {
|
||||
return this.map.has(testId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a test ID from the tree. This is NOT recursive.
|
||||
*/
|
||||
public delete(testId: string) {
|
||||
const existing = this.map.get(testId);
|
||||
if (!existing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.map.delete(testId);
|
||||
this._roots.delete(existing);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a test item by ID from the tree.
|
||||
*/
|
||||
public get(testId: string) {
|
||||
return this.map.get(testId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the positions of the two items in the test tree.
|
||||
*/
|
||||
public comparePositions(aOrId: T | string, bOrId: T | string) {
|
||||
const a = typeof aOrId === 'string' ? this.map.get(aOrId) : aOrId;
|
||||
const b = typeof bOrId === 'string' ? this.map.get(bOrId) : bOrId;
|
||||
if (!a || !b) {
|
||||
return TestPosition.Disconnected;
|
||||
}
|
||||
|
||||
if (a === b) {
|
||||
return TestPosition.IsSame;
|
||||
}
|
||||
|
||||
for (let p = this.map.get(b.parent!); p; p = this.map.get(p.parent!)) {
|
||||
if (p === a) {
|
||||
return TestPosition.IsChild;
|
||||
}
|
||||
}
|
||||
|
||||
for (let p = this.map.get(a.parent!); p; p = this.map.get(p.parent!)) {
|
||||
if (p === b) {
|
||||
return TestPosition.IsParent;
|
||||
}
|
||||
}
|
||||
|
||||
return TestPosition.Disconnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all test in the tree.
|
||||
*/
|
||||
[Symbol.iterator]() {
|
||||
return this.map.values();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maintains tests created and registered for a single set of hierarchies
|
||||
* for a workspace or document.
|
||||
|
@ -154,15 +44,13 @@ export class SingleUseTestCollection extends Disposable {
|
|||
private readonly diffOpEmitter = this._register(new Emitter<TestsDiff>());
|
||||
private _resolveHandler?: (item: TestItemRaw) => Promise<void> | void;
|
||||
|
||||
public readonly root = new TestItemImpl(`${this.controllerId}Root`, this.controllerId, undefined);
|
||||
public readonly tree = new TestTree<OwnedCollectionTestItem>();
|
||||
public readonly root = new TestItemRootImpl(this.controllerId, this.controllerId);
|
||||
public readonly tree = new Map</* full test id */string, OwnedCollectionTestItem>();
|
||||
protected diff: TestsDiff = [];
|
||||
|
||||
constructor(
|
||||
private readonly controllerId: string,
|
||||
) {
|
||||
constructor(private readonly controllerId: string) {
|
||||
super();
|
||||
this.upsertItem(this.root, null);
|
||||
this.upsertItem(this.root, undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,7 +58,7 @@ export class SingleUseTestCollection extends Disposable {
|
|||
*/
|
||||
public set resolveHandler(handler: undefined | ((item: TestItemRaw) => void)) {
|
||||
this._resolveHandler = handler;
|
||||
for (const test of this.tree) {
|
||||
for (const test of this.tree.values()) {
|
||||
this.updateExpandability(test);
|
||||
}
|
||||
}
|
||||
|
@ -244,24 +132,23 @@ export class SingleUseTestCollection extends Disposable {
|
|||
}
|
||||
|
||||
public override dispose() {
|
||||
for (const item of this.tree) {
|
||||
for (const item of this.tree.values()) {
|
||||
getPrivateApiFor(item.actual).listener = undefined;
|
||||
}
|
||||
|
||||
this.tree.clear();
|
||||
this.diff = [];
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private onTestItemEvent(internal: OwnedCollectionTestItem, evt: ExtHostTestItemEvent) {
|
||||
const extId = internal?.actual.id;
|
||||
|
||||
switch (evt.op) {
|
||||
case ExtHostTestItemEventOp.Invalidated:
|
||||
this.pushDiff([TestDiffOpType.Retire, extId]);
|
||||
this.pushDiff([TestDiffOpType.Retire, internal.fullId.toString()]);
|
||||
break;
|
||||
|
||||
case ExtHostTestItemEventOp.RemoveChild:
|
||||
this.removeItem(evt.id);
|
||||
this.removeItem(TestId.joinToString(internal.fullId, evt.id));
|
||||
break;
|
||||
|
||||
case ExtHostTestItemEventOp.Upsert:
|
||||
|
@ -276,6 +163,7 @@ export class SingleUseTestCollection extends Disposable {
|
|||
|
||||
case ExtHostTestItemEventOp.SetProp:
|
||||
const { key, value } = evt;
|
||||
const extId = internal.fullId.toString();
|
||||
switch (key) {
|
||||
case 'canResolveChildren':
|
||||
this.updateExpandability(internal);
|
||||
|
@ -296,35 +184,43 @@ export class SingleUseTestCollection extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
private upsertItem(actual: TestItemRaw, parent: OwnedCollectionTestItem | null) {
|
||||
private upsertItem(actual: TestItemRaw, parent: OwnedCollectionTestItem | undefined) {
|
||||
if (!(actual instanceof TestItemImpl)) {
|
||||
throw new Error(`TestItems provided to the VS Code API must extend \`vscode.TestItem\`, but ${actual.id} did not`);
|
||||
}
|
||||
|
||||
const fullId = TestId.fromExtHostTestItem(actual, this.root.id, parent?.actual);
|
||||
|
||||
// If the item already exists under a different parent, remove it.
|
||||
let internal = this.tree.get(actual.id);
|
||||
if (internal && internal.parent !== parent?.actual.id) {
|
||||
(internal.actual.parent ?? this.root).children.delete(actual.id);
|
||||
internal = undefined;
|
||||
// If this test item exists elsewhere in the tree already (exists at an
|
||||
// old ID with an existing parent), remove that old item.
|
||||
const privateApi = getPrivateApiFor(actual);
|
||||
if (privateApi.parent && privateApi.parent !== parent?.actual) {
|
||||
privateApi.parent.children.delete(actual.id);
|
||||
}
|
||||
|
||||
let internal = this.tree.get(fullId.toString());
|
||||
// Case 1: a brand new item
|
||||
if (!internal) {
|
||||
const parentId = parent ? parent.actual.id : null;
|
||||
// always expand root node to know if there are tests (and whether to show the welcome view)
|
||||
const pExpandLvls = parent ? parent.expandLevels : 1;
|
||||
internal = {
|
||||
fullId,
|
||||
actual,
|
||||
parent: parentId,
|
||||
parent: parent ? fullId.parentId : null,
|
||||
expandLevels: pExpandLvls /* intentionally undefined or 0 */ ? pExpandLvls - 1 : undefined,
|
||||
expand: TestItemExpandState.NotExpandable, // updated by `connectItemAndChildren`
|
||||
};
|
||||
|
||||
this.tree.add(internal);
|
||||
this.tree.set(internal.fullId.toString(), internal);
|
||||
this.setItemParent(actual, parent);
|
||||
this.pushDiff([
|
||||
TestDiffOpType.Add,
|
||||
{ parent: parentId, controllerId: this.controllerId, expand: internal.expand, item: Convert.TestItem.from(actual) },
|
||||
{
|
||||
parent: internal.parent && internal.parent.toString(),
|
||||
controllerId: this.controllerId,
|
||||
expand: internal.expand,
|
||||
item: Convert.TestItem.from(actual, this.root.id),
|
||||
},
|
||||
]);
|
||||
|
||||
this.connectItemAndChildren(actual, internal, parent);
|
||||
|
@ -351,24 +247,27 @@ export class SingleUseTestCollection extends Disposable {
|
|||
|
||||
this.connectItemAndChildren(actual, internal, parent);
|
||||
|
||||
// Remove any children still referencing the old parent that aren't
|
||||
// included in the new one. Note that children might have moved to a new
|
||||
// parent, so the parent ID check is done.
|
||||
// Remove any orphaned children.
|
||||
for (const child of oldChildren) {
|
||||
if (!actual.children.get(child.id) && this.tree.get(child.id)?.parent === actual.id) {
|
||||
this.removeItem(child.id);
|
||||
if (!actual.children.get(child.id)) {
|
||||
this.removeItem(TestId.joinToString(fullId, child.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private connectItem(actual: TestItemImpl, internal: OwnedCollectionTestItem, parent: OwnedCollectionTestItem | null) {
|
||||
private setItemParent(actual: TestItemImpl, parent: OwnedCollectionTestItem | undefined) {
|
||||
getPrivateApiFor(actual).parent = parent && parent.actual !== this.root ? parent.actual : undefined;
|
||||
}
|
||||
|
||||
private connectItem(actual: TestItemImpl, internal: OwnedCollectionTestItem, parent: OwnedCollectionTestItem | undefined) {
|
||||
this.setItemParent(actual, parent);
|
||||
const api = getPrivateApiFor(actual);
|
||||
api.parent = parent && parent.actual !== this.root ? parent.actual : undefined;
|
||||
api.parent = parent?.actual;
|
||||
api.listener = evt => this.onTestItemEvent(internal, evt);
|
||||
this.updateExpandability(internal);
|
||||
}
|
||||
|
||||
private connectItemAndChildren(actual: TestItemImpl, internal: OwnedCollectionTestItem, parent: OwnedCollectionTestItem | null) {
|
||||
private connectItemAndChildren(actual: TestItemImpl, internal: OwnedCollectionTestItem, parent: OwnedCollectionTestItem | undefined) {
|
||||
this.connectItem(actual, internal, parent);
|
||||
|
||||
// Discover any existing children that might have already been added
|
||||
|
@ -401,7 +300,7 @@ export class SingleUseTestCollection extends Disposable {
|
|||
}
|
||||
|
||||
internal.expand = newState;
|
||||
this.pushDiff([TestDiffOpType.Update, { extId: internal.actual.id, expand: newState }]);
|
||||
this.pushDiff([TestDiffOpType.Update, { extId: internal.fullId.toString(), expand: newState }]);
|
||||
|
||||
if (newState === TestItemExpandState.Expandable && internal.expandLevels !== undefined) {
|
||||
this.resolveChildren(internal);
|
||||
|
@ -419,7 +318,7 @@ export class SingleUseTestCollection extends Disposable {
|
|||
}
|
||||
|
||||
const asyncChildren = internal.actual.children.all
|
||||
.map(c => this.expand(c.id, levels))
|
||||
.map(c => this.expand(TestId.joinToString(internal.fullId, c.id), levels))
|
||||
.filter(isThenable);
|
||||
|
||||
if (asyncChildren.length) {
|
||||
|
@ -467,7 +366,7 @@ export class SingleUseTestCollection extends Disposable {
|
|||
}
|
||||
|
||||
private pushExpandStateUpdate(internal: OwnedCollectionTestItem) {
|
||||
this.pushDiff([TestDiffOpType.Update, { extId: internal.actual.id, expand: internal.expand }]);
|
||||
this.pushDiff([TestDiffOpType.Update, { extId: internal.fullId.toString(), expand: internal.expand }]);
|
||||
}
|
||||
|
||||
private removeItem(childId: string) {
|
||||
|
@ -486,9 +385,9 @@ export class SingleUseTestCollection extends Disposable {
|
|||
}
|
||||
|
||||
getPrivateApiFor(item.actual).listener = undefined;
|
||||
this.tree.delete(item.actual.id);
|
||||
this.tree.delete(item.fullId.toString());
|
||||
for (const child of item.actual.children.all) {
|
||||
queue.push(this.tree.get(child.id));
|
||||
queue.push(this.tree.get(TestId.joinToString(item.fullId, child.id)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,12 +50,6 @@ export interface ITestRunProfile {
|
|||
hasConfigurationHandler: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the path to a test, as a list of test IDs. The last element of the
|
||||
* array is the test ID, and the predecessors are its parents, in order.
|
||||
*/
|
||||
export type TestIdPath = string[];
|
||||
|
||||
/**
|
||||
* A fully-resolved request to run tests, passsed between the main thread
|
||||
* and extension host.
|
||||
|
|
159
src/vs/workbench/contrib/testing/common/testId.ts
Normal file
159
src/vs/workbench/contrib/testing/common/testId.ts
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const enum TestIdPathParts {
|
||||
/** Delimiter for path parts in test IDs */
|
||||
Delimiter = '\0',
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum for describing relative positions of tests. Similar to
|
||||
* `node.compareDocumentPosition` in the DOM.
|
||||
*/
|
||||
export const enum TestPosition {
|
||||
/** a === b */
|
||||
IsSame,
|
||||
/** Neither a nor b are a child of one another. They may share a common parent, though. */
|
||||
Disconnected,
|
||||
/** b is a child of a */
|
||||
IsChild,
|
||||
/** b is a parent of a */
|
||||
IsParent,
|
||||
}
|
||||
|
||||
type TestItemLike = { id: string; parent?: TestItemLike };
|
||||
|
||||
/**
|
||||
* The test ID is a stringifiable client that
|
||||
*/
|
||||
export class TestId {
|
||||
private stringifed?: string;
|
||||
|
||||
/**
|
||||
* Creates a test ID from an ext host test item.
|
||||
*/
|
||||
public static fromExtHostTestItem(item: TestItemLike, rootId: string, parent = item.parent) {
|
||||
if (item.id === rootId) {
|
||||
return new TestId([rootId]);
|
||||
}
|
||||
|
||||
let path = [item.id];
|
||||
for (let i = parent; i && i.id !== rootId; i = i.parent) {
|
||||
path.push(i.id);
|
||||
}
|
||||
path.push(rootId);
|
||||
|
||||
return new TestId(path.reverse());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test ID from a serialized TestId instance.
|
||||
*/
|
||||
public static fromString(idString: string) {
|
||||
return new TestId(idString.split(TestIdPathParts.Delimiter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID resulting from adding b to the base ID.
|
||||
*/
|
||||
public static join(base: TestId, b: string) {
|
||||
return new TestId([...base.path, b]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string ID resulting from adding b to the base ID.
|
||||
*/
|
||||
public static joinToString(base: string | TestId, b: string) {
|
||||
return base.toString() + TestIdPathParts.Delimiter + b;
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly path: readonly string[],
|
||||
private readonly viewEnd = path.length,
|
||||
) {
|
||||
if (path.length === 0 || viewEnd < 1) {
|
||||
throw new Error('cannot create test with empty path');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the parent test.
|
||||
*/
|
||||
public get parentId(): TestId {
|
||||
return this.viewEnd > 1 ? new TestId(this.path, this.viewEnd - 1) : this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local ID of the current full test ID.
|
||||
*/
|
||||
public get localId() {
|
||||
return this.path[this.viewEnd - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this ID refers to the root.
|
||||
*/
|
||||
public get isRoot() {
|
||||
return this.viewEnd === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable that yields IDs of all parent items down to and
|
||||
* including the current item.
|
||||
*/
|
||||
public *idsFromRoot() {
|
||||
let built = this.path[0];
|
||||
yield built;
|
||||
|
||||
for (let i = 1; i < this.viewEnd; i++) {
|
||||
built += TestIdPathParts.Delimiter;
|
||||
built += this.path[i];
|
||||
yield built;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the other test ID with this one.
|
||||
*/
|
||||
public compare(other: TestId) {
|
||||
for (let i = 0; i < other.viewEnd && i < this.viewEnd; i++) {
|
||||
if (other.path[i] !== this.path[i]) {
|
||||
return TestPosition.Disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
if (other.viewEnd > this.viewEnd) {
|
||||
return TestPosition.IsChild;
|
||||
}
|
||||
|
||||
if (other.viewEnd < this.viewEnd) {
|
||||
return TestPosition.IsParent;
|
||||
}
|
||||
|
||||
return TestPosition.IsSame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the ID.
|
||||
*/
|
||||
public toJSON() {
|
||||
return this.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the ID to a string.
|
||||
*/
|
||||
public toString() {
|
||||
if (!this.stringifed) {
|
||||
this.stringifed = this.path[0];
|
||||
for (let i = 1; i < this.viewEnd; i++) {
|
||||
this.stringifed += TestIdPathParts.Delimiter;
|
||||
this.stringifed += this.path[i];
|
||||
}
|
||||
}
|
||||
|
||||
return this.stringifed;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ import { localize } from 'vs/nls';
|
|||
import { TestResultState } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IComputedStateAccessor, refreshComputedState } from 'vs/workbench/contrib/testing/common/getComputedState';
|
||||
import { IObservableValue, MutableObservableValue, staticObservableValue } from 'vs/workbench/contrib/testing/common/observableValue';
|
||||
import { ISerializedTestResults, ITestItem, ITestMessage, ITestRunTask, ITestTaskState, ResolvedTestRunRequest, TestIdPath, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { ISerializedTestResults, ITestItem, ITestMessage, ITestRunTask, ITestTaskState, ResolvedTestRunRequest, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestCoverage } from 'vs/workbench/contrib/testing/common/testCoverage';
|
||||
import { maxPriority, statesInOrder } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
|
||||
|
@ -86,15 +86,6 @@ export const resultItemParents = function* (results: ITestResult, item: TestResu
|
|||
}
|
||||
};
|
||||
|
||||
export const getPathForTestInResult = (test: TestResultItem, results: ITestResult): TestIdPath => {
|
||||
const path: TestIdPath = [];
|
||||
for (const node of resultItemParents(results, test)) {
|
||||
path.unshift(node.item.extId);
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
/**
|
||||
* Count of the number of tests in each run state.
|
||||
*/
|
||||
|
|
|
@ -11,8 +11,9 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IObservableValue } from 'vs/workbench/contrib/testing/common/observableValue';
|
||||
import { AbstractIncrementalTestCollection, IncrementalTestCollectionItem, InternalTestItem, ITestIdWithSrc, ResolvedTestRunRequest, RunTestForControllerRequest, TestIdPath, TestItemExpandState, TestRunProfileBitset, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { AbstractIncrementalTestCollection, IncrementalTestCollectionItem, InternalTestItem, ITestIdWithSrc, ResolvedTestRunRequest, RunTestForControllerRequest, TestItemExpandState, TestRunProfileBitset, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestExclusions } from 'vs/workbench/contrib/testing/common/testExclusions';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { ITestResult } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
|
||||
export const ITestService = createDecorator<ITestService>('testService');
|
||||
|
@ -82,18 +83,12 @@ export const testCollectionIsEmpty = (collection: IMainThreadTestCollection) =>
|
|||
!Iterable.some(collection.rootItems, r => r.children.size > 0);
|
||||
|
||||
/**
|
||||
* Ensures the test with the given path exists in the collection, if possible.
|
||||
* Ensures the test with the given ID exists in the collection, if possible.
|
||||
* If cancellation is requested, or the test cannot be found, it will return
|
||||
* undefined.
|
||||
*/
|
||||
export const getTestByPath = async (collection: IMainThreadTestCollection, idPath: TestIdPath, ct = CancellationToken.None) => {
|
||||
// Expand all direct children since roots might well have different IDs, but
|
||||
// children should start matching.
|
||||
await expandFirstLevel(collection);
|
||||
|
||||
if (ct.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
export const expandAndGetTestById = async (collection: IMainThreadTestCollection, id: string, ct = CancellationToken.None) => {
|
||||
const idPath = [...TestId.fromString(id).idsFromRoot()];
|
||||
|
||||
let expandToLevel = 0;
|
||||
for (let i = idPath.length - 1; !ct.isCancellationRequested && i >= expandToLevel;) {
|
||||
|
|
|
@ -155,7 +155,9 @@ export class TestService extends Disposable implements ITestService {
|
|||
group => this.testControllers.get(group.controllerId)?.runTests(
|
||||
{
|
||||
runId: result.id,
|
||||
excludeExtIds: req.exclude!.filter(t => t.controllerId === group.controllerId).map(t => t.testId),
|
||||
excludeExtIds: req.exclude!
|
||||
.filter(t => t.controllerId === group.controllerId && !group.testIds.includes(t.testId))
|
||||
.map(t => t.testId),
|
||||
profileId: group.profileId,
|
||||
controllerId: group.controllerId,
|
||||
testIds: group.testIds,
|
||||
|
|
|
@ -7,6 +7,7 @@ import * as assert from 'assert';
|
|||
import { Emitter } from 'vs/base/common/event';
|
||||
import { HierarchicalByLocationProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation';
|
||||
import { TestDiffOpType, TestItemExpandState, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { TestResultState } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { Convert, TestItemImpl } from 'vs/workbench/contrib/testing/common/testStubs';
|
||||
|
@ -44,7 +45,7 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
|
|||
|
||||
test('expands children', async () => {
|
||||
harness.flush();
|
||||
harness.tree.expand(harness.projection.getElementByTestId('id-a')!);
|
||||
harness.tree.expand(harness.projection.getElementByTestId(new TestId(['ctrlId', 'id-a']).toString())!);
|
||||
assert.deepStrictEqual(harness.flush(), [
|
||||
{ e: 'a', children: [{ e: 'aa' }, { e: 'ab' }] }, { e: 'b' }
|
||||
]);
|
||||
|
@ -54,10 +55,10 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
|
|||
harness.flush();
|
||||
harness.pushDiff([
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrl2', parent: null, expand: TestItemExpandState.Expanded, item: Convert.TestItem.from(new TestItemImpl('c', 'c', undefined)) },
|
||||
{ controllerId: 'ctrl2', parent: null, expand: TestItemExpandState.Expanded, item: Convert.TestItem.from(new TestItemImpl('c', 'c', undefined), 'ctrl2') },
|
||||
], [
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrl2', parent: 'c', expand: TestItemExpandState.NotExpandable, item: Convert.TestItem.from(new TestItemImpl('c-a', 'ca', undefined)) },
|
||||
{ controllerId: 'ctrl2', parent: new TestId(['ctrl2', 'c']).toString(), expand: TestItemExpandState.NotExpandable, item: Convert.TestItem.from(new TestItemImpl('c-a', 'ca', undefined), 'ctrl2') },
|
||||
]);
|
||||
|
||||
assert.deepStrictEqual(harness.flush(), [
|
||||
|
@ -68,7 +69,7 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
|
|||
|
||||
test('updates nodes if they add children', async () => {
|
||||
harness.flush();
|
||||
harness.tree.expand(harness.projection.getElementByTestId('id-a')!);
|
||||
harness.tree.expand(harness.projection.getElementByTestId(new TestId(['ctrlId', 'id-a']).toString())!);
|
||||
|
||||
assert.deepStrictEqual(harness.flush(), [
|
||||
{ e: 'a', children: [{ e: 'aa' }, { e: 'ab' }] },
|
||||
|
@ -85,7 +86,7 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
|
|||
|
||||
test('updates nodes if they remove children', async () => {
|
||||
harness.flush();
|
||||
harness.tree.expand(harness.projection.getElementByTestId('id-a')!);
|
||||
harness.tree.expand(harness.projection.getElementByTestId(new TestId(['ctrlId', 'id-a']).toString())!);
|
||||
|
||||
assert.deepStrictEqual(harness.flush(), [
|
||||
{ e: 'a', children: [{ e: 'aa' }, { e: 'ab' }] },
|
||||
|
@ -105,7 +106,7 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
|
|||
resultsService.getStateById = () => [undefined, resultInState(TestResultState.Failed)];
|
||||
|
||||
const resultInState = (state: TestResultState): TestResultItem => ({
|
||||
item: Convert.TestItem.from(harness.c.tree.get('id-a')!.actual),
|
||||
item: Convert.TestItem.from(harness.c.tree.get(new TestId(['ctrlId', 'id-a']).toString())!.actual, 'ctrlId'),
|
||||
parent: 'id-root',
|
||||
tasks: [],
|
||||
retired: false,
|
||||
|
|
|
@ -7,6 +7,7 @@ import * as assert from 'assert';
|
|||
import { Emitter } from 'vs/base/common/event';
|
||||
import { HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName';
|
||||
import { TestDiffOpType, TestItemExpandState } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { TestResultItemChange } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { Convert, TestItemImpl } from 'vs/workbench/contrib/testing/common/testStubs';
|
||||
import { TestTreeTestHarness } from 'vs/workbench/contrib/testing/test/browser/testObjectTree';
|
||||
|
@ -42,10 +43,10 @@ suite('Workbench - Testing Explorer Hierarchal by Name Projection', () => {
|
|||
harness.flush();
|
||||
harness.pushDiff([
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrl2', parent: null, expand: TestItemExpandState.Expanded, item: Convert.TestItem.from(new TestItemImpl('c', 'root2', undefined)) },
|
||||
{ controllerId: 'ctrl2', parent: null, expand: TestItemExpandState.Expanded, item: Convert.TestItem.from(new TestItemImpl('c', 'root2', undefined), 'ctrl2') },
|
||||
], [
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrl2', parent: 'c', expand: TestItemExpandState.NotExpandable, item: Convert.TestItem.from(new TestItemImpl('c-a', 'c', undefined)) },
|
||||
{ controllerId: 'ctrl2', parent: new TestId(['ctrl2', 'c']).toString(), expand: TestItemExpandState.NotExpandable, item: Convert.TestItem.from(new TestItemImpl('c-a', 'c', undefined), 'ctrl2') },
|
||||
]);
|
||||
|
||||
assert.deepStrictEqual(harness.flush(), [
|
||||
|
|
|
@ -12,8 +12,9 @@ import { NullLogService } from 'vs/platform/log/common/log';
|
|||
import { SingleUseTestCollection } from 'vs/workbench/contrib/testing/common/ownedTestCollection';
|
||||
import { ITestTaskState, ResolvedTestRunRequest, TestResultItem, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestProfileService } from 'vs/workbench/contrib/testing/common/testConfigurationService';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { TestResultState } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { getPathForTestInResult, HydratedTestResult, LiveOutputController, LiveTestResult, makeEmptyCounts, resultItemParents, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { HydratedTestResult, LiveOutputController, LiveTestResult, makeEmptyCounts, resultItemParents, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { TestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { InMemoryResultStorage, ITestResultStorage } from 'vs/workbench/contrib/testing/common/testResultStorage';
|
||||
import { Convert, getInitializedMainTestCollection, testStubs } from 'vs/workbench/contrib/testing/common/testStubs';
|
||||
|
@ -63,15 +64,15 @@ suite('Workbench - Test Results Service', () => {
|
|||
|
||||
tests = testStubs.nested();
|
||||
await tests.expand(tests.root.id, Infinity);
|
||||
r.addTestChainToRun('ctrl', [
|
||||
Convert.TestItem.from(tests.root),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!.children.get('id-aa')!),
|
||||
r.addTestChainToRun('ctrlId', [
|
||||
Convert.TestItem.from(tests.root, 'ctrlId'),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!, 'ctrlId'),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!.children.get('id-aa')!, 'ctrlId'),
|
||||
]);
|
||||
|
||||
r.addTestChainToRun('ctrl', [
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!.children.get('id-ab')!),
|
||||
r.addTestChainToRun('ctrlId', [
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!, 'ctrlId'),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!.children.get('id-ab')!, 'ctrlId'),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -122,8 +123,8 @@ suite('Workbench - Test Results Service', () => {
|
|||
[TestResultState.Failed]: 3,
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(r.getStateById('id-a')?.ownComputedState, TestResultState.Failed);
|
||||
assert.deepStrictEqual(r.getStateById('id-a')?.tasks[0].state, TestResultState.Failed);
|
||||
assert.deepStrictEqual(r.getStateById(new TestId(['ctrlId', 'id-a']).toString())?.ownComputedState, TestResultState.Failed);
|
||||
assert.deepStrictEqual(r.getStateById(new TestId(['ctrlId', 'id-a']).toString())?.tasks[0].state, TestResultState.Failed);
|
||||
assert.deepStrictEqual(getChangeSummary(), [
|
||||
{ label: 'a', reason: TestResultItemChangeReason.OwnStateChange },
|
||||
{ label: 'aa', reason: TestResultItemChangeReason.OwnStateChange },
|
||||
|
@ -134,14 +135,14 @@ suite('Workbench - Test Results Service', () => {
|
|||
|
||||
test('updateState', () => {
|
||||
changed.clear();
|
||||
r.updateState('id-aa', 't', TestResultState.Running);
|
||||
r.updateState(new TestId(['ctrlId', 'id-a', 'id-aa']).toString(), 't', TestResultState.Running);
|
||||
assert.deepStrictEqual(r.counts, {
|
||||
...makeEmptyCounts(),
|
||||
[TestResultState.Unset]: 2,
|
||||
[TestResultState.Running]: 1,
|
||||
[TestResultState.Queued]: 1,
|
||||
});
|
||||
assert.deepStrictEqual(r.getStateById('id-aa')?.ownComputedState, TestResultState.Running);
|
||||
assert.deepStrictEqual(r.getStateById(new TestId(['ctrlId', 'id-a', 'id-aa']).toString())?.ownComputedState, TestResultState.Running);
|
||||
// update computed state:
|
||||
assert.deepStrictEqual(r.getStateById(tests.root.id)?.computedState, TestResultState.Running);
|
||||
assert.deepStrictEqual(getChangeSummary(), [
|
||||
|
@ -153,7 +154,7 @@ suite('Workbench - Test Results Service', () => {
|
|||
|
||||
test('retire', () => {
|
||||
changed.clear();
|
||||
r.retire('id-a');
|
||||
r.retire(new TestId(['ctrlId', 'id-a']).toString());
|
||||
assert.deepStrictEqual(getChangeSummary(), [
|
||||
{ label: 'a', reason: TestResultItemChangeReason.Retired },
|
||||
{ label: 'aa', reason: TestResultItemChangeReason.ParentRetired },
|
||||
|
@ -161,24 +162,24 @@ suite('Workbench - Test Results Service', () => {
|
|||
]);
|
||||
|
||||
changed.clear();
|
||||
r.retire('id-a');
|
||||
r.retire(new TestId(['ctrlId', 'id-a']).toString());
|
||||
assert.strictEqual(changed.size, 0);
|
||||
});
|
||||
|
||||
test('ignores outside run', () => {
|
||||
changed.clear();
|
||||
r.updateState('id-b', 't', TestResultState.Running);
|
||||
r.updateState(new TestId(['ctrlId', 'id-b']).toString(), 't', TestResultState.Running);
|
||||
assert.deepStrictEqual(r.counts, {
|
||||
...makeEmptyCounts(),
|
||||
[TestResultState.Queued]: 2,
|
||||
[TestResultState.Unset]: 2,
|
||||
});
|
||||
assert.deepStrictEqual(r.getStateById('id-b'), undefined);
|
||||
assert.deepStrictEqual(r.getStateById(new TestId(['ctrlId', 'id-b']).toString()), undefined);
|
||||
});
|
||||
|
||||
test('markComplete', () => {
|
||||
r.setAllToState(TestResultState.Queued, 't', () => true);
|
||||
r.updateState('id-aa', 't', TestResultState.Passed);
|
||||
r.updateState(new TestId(['ctrlId', 'id-a', 'id-aa']).toString(), 't', TestResultState.Passed);
|
||||
changed.clear();
|
||||
|
||||
r.markComplete();
|
||||
|
@ -190,7 +191,7 @@ suite('Workbench - Test Results Service', () => {
|
|||
});
|
||||
|
||||
assert.deepStrictEqual(r.getStateById(tests.root.id)?.ownComputedState, TestResultState.Unset);
|
||||
assert.deepStrictEqual(r.getStateById('id-aa')?.ownComputedState, TestResultState.Passed);
|
||||
assert.deepStrictEqual(r.getStateById(new TestId(['ctrlId', 'id-a', 'id-aa']).toString())?.ownComputedState, TestResultState.Passed);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -214,7 +215,7 @@ suite('Workbench - Test Results Service', () => {
|
|||
|
||||
test('serializes and re-hydrates', async () => {
|
||||
results.push(r);
|
||||
r.updateState('id-aa', 't', TestResultState.Passed);
|
||||
r.updateState(new TestId(['ctrlId', 'id-a', 'id-aa']).toString(), 't', TestResultState.Passed);
|
||||
r.markComplete();
|
||||
await timeout(10); // allow persistImmediately async to happen
|
||||
|
||||
|
@ -235,7 +236,7 @@ suite('Workbench - Test Results Service', () => {
|
|||
delete expected.item.description;
|
||||
expected.item.uri = actual.item.uri;
|
||||
|
||||
assert.deepStrictEqual(actual, { ...expected, src: undefined, retired: true, children: ['id-a'] });
|
||||
assert.deepStrictEqual(actual, { ...expected, src: undefined, retired: true, children: [new TestId(['ctrlId', 'id-a']).toString()] });
|
||||
assert.deepStrictEqual(rehydrated.counts, r.counts);
|
||||
assert.strictEqual(typeof rehydrated.completedAt, 'number');
|
||||
});
|
||||
|
@ -278,7 +279,7 @@ suite('Workbench - Test Results Service', () => {
|
|||
name: 'hello world',
|
||||
request: defaultOpts([]),
|
||||
items: [{
|
||||
...(await getInitializedMainTestCollection()).getNodeById('id-a')!,
|
||||
...(await getInitializedMainTestCollection()).getNodeById(new TestId(['ctrlId', 'id-a']).toString())!,
|
||||
tasks: [{ state, duration: 0, messages: [] }],
|
||||
computedState: state,
|
||||
ownComputedState: state,
|
||||
|
@ -312,22 +313,14 @@ suite('Workbench - Test Results Service', () => {
|
|||
});
|
||||
|
||||
test('resultItemParents', () => {
|
||||
assert.deepStrictEqual([...resultItemParents(r, r.getStateById('id-aa')!)], [
|
||||
r.getStateById('id-aa'),
|
||||
r.getStateById('id-a'),
|
||||
r.getStateById(tests.root.id),
|
||||
assert.deepStrictEqual([...resultItemParents(r, r.getStateById(new TestId(['ctrlId', 'id-a', 'id-aa']).toString())!)], [
|
||||
r.getStateById(new TestId(['ctrlId', 'id-a', 'id-aa']).toString()),
|
||||
r.getStateById(new TestId(['ctrlId', 'id-a']).toString()),
|
||||
r.getStateById(new TestId(['ctrlId']).toString()),
|
||||
]);
|
||||
|
||||
assert.deepStrictEqual([...resultItemParents(r, r.getStateById(tests.root.id)!)], [
|
||||
r.getStateById(tests.root.id),
|
||||
]);
|
||||
});
|
||||
|
||||
test('getPathForTestInResult', () => {
|
||||
assert.deepStrictEqual([...getPathForTestInResult(r.getStateById('id-aa')!, r)], [
|
||||
tests.root.id,
|
||||
'id-a',
|
||||
'id-aa',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import * as assert from 'assert';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { ITestResult, LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { InMemoryResultStorage, RETAIN_MAX_RESULTS } from 'vs/workbench/contrib/testing/common/testResultStorage';
|
||||
import { Convert, testStubs } from 'vs/workbench/contrib/testing/common/testStubs';
|
||||
|
@ -26,14 +27,14 @@ suite('Workbench - Test Result Storage', () => {
|
|||
t.addTask({ id: 't', name: undefined, running: true });
|
||||
const tests = testStubs.nested();
|
||||
tests.expand(tests.root.id, Infinity);
|
||||
t.addTestChainToRun('ctrl', [
|
||||
Convert.TestItem.from(tests.root),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!.children.get('id-aa')!),
|
||||
t.addTestChainToRun('ctrlId', [
|
||||
Convert.TestItem.from(tests.root, 'ctrlId'),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!, 'ctrlId'),
|
||||
Convert.TestItem.from(tests.root.children.get('id-a')!.children.get('id-aa')!, 'ctrlId'),
|
||||
]);
|
||||
|
||||
if (addMessage) {
|
||||
t.appendMessage('id-a', 't', {
|
||||
t.appendMessage(new TestId(['ctrlId', 'id-a']).toString(), 't', {
|
||||
message: addMessage,
|
||||
actualOutput: undefined,
|
||||
expectedOutput: undefined,
|
||||
|
@ -75,7 +76,8 @@ suite('Workbench - Test Result Storage', () => {
|
|||
test('limits stored result by budget', async () => {
|
||||
const r = range(100).map(() => makeResult('a'.repeat(2048)));
|
||||
await storage.persist(r);
|
||||
assert.strictEqual(true, (await storage.read()).length < 50);
|
||||
const length = (await storage.read()).length;
|
||||
assert.strictEqual(true, length < 50);
|
||||
});
|
||||
|
||||
test('always stores the min number of results', async () => {
|
||||
|
|
|
@ -13,6 +13,7 @@ import { TestRunProfileImpl, TestRunCoordinator, TestRunDto } from 'vs/workbench
|
|||
import * as convert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { TestMessage, TestResultState, TestRunProfileGroup } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { TestDiffOpType, TestItemExpandState } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { TestItemImpl, testStubs } from 'vs/workbench/contrib/testing/common/testStubs';
|
||||
import { TestSingleUseCollection } from 'vs/workbench/contrib/testing/test/common/ownedTestCollection';
|
||||
import type { TestItem, TestRunRequest } from 'vscode';
|
||||
|
@ -73,18 +74,20 @@ suite('ExtHost Testing', () => {
|
|||
suite('OwnedTestCollection', () => {
|
||||
test('adds a root recursively', async () => {
|
||||
await single.expand(single.root.id, Infinity);
|
||||
const a = single.root.children.get('id-a')!;
|
||||
const b = single.root.children.get('id-b')!;
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: null, expand: TestItemExpandState.BusyExpanding, item: { ...convert.TestItem.from(single.root) } }
|
||||
{ controllerId: 'ctrlId', parent: null, expand: TestItemExpandState.BusyExpanding, item: { ...convert.TestItem.from(single.root, 'ctrlId') } }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: single.root.id, expand: TestItemExpandState.Expandable, item: { ...convert.TestItem.from(single.tree.get('id-a')!.actual) } }
|
||||
{ controllerId: 'ctrlId', parent: single.root.id, expand: TestItemExpandState.Expandable, item: { ...convert.TestItem.from(a, 'ctrlId') } }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: single.root.id, expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(single.tree.get('id-b')!.actual) }
|
||||
{ controllerId: 'ctrlId', parent: single.root.id, expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(b, 'ctrlId') }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
|
@ -92,19 +95,19 @@ suite('ExtHost Testing', () => {
|
|||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-a', expand: TestItemExpandState.BusyExpanding }
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.BusyExpanding }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: 'id-a', expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(single.tree.get('id-aa')!.actual) }
|
||||
{ controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(a.children.get('id-aa')!, 'ctrlId') }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: 'id-a', expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(single.tree.get('id-ab')!.actual) }
|
||||
{ controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(a.children.get('id-ab')!, 'ctrlId') }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-a', expand: TestItemExpandState.Expanded }
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.Expanded }
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
@ -132,7 +135,7 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-a', item: { description: 'Hello world' } }],
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), item: { description: 'Hello world' } }],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -142,9 +145,12 @@ suite('ExtHost Testing', () => {
|
|||
single.root.children.delete('id-a');
|
||||
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[TestDiffOpType.Remove, 'id-a'],
|
||||
[TestDiffOpType.Remove, new TestId(['ctrlId', 'id-a']).toString()],
|
||||
]);
|
||||
assert.deepStrictEqual([...single.tree].map(n => n.actual.id).sort(), [single.root.id, 'id-b']);
|
||||
assert.deepStrictEqual(
|
||||
[...single.tree.keys()].sort(),
|
||||
[single.root.id, new TestId(['ctrlId', 'id-b']).toString()],
|
||||
);
|
||||
assert.strictEqual(single.tree.size, 2);
|
||||
});
|
||||
|
||||
|
@ -157,13 +163,13 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[TestDiffOpType.Add, {
|
||||
controllerId: 'ctrlId',
|
||||
parent: 'id-a',
|
||||
parent: new TestId(['ctrlId', 'id-a']).toString(),
|
||||
expand: TestItemExpandState.NotExpandable,
|
||||
item: convert.TestItem.from(child),
|
||||
item: convert.TestItem.from(child, 'ctrlId'),
|
||||
}],
|
||||
]);
|
||||
assert.deepStrictEqual(
|
||||
[...single.tree].map(n => n.actual.id).sort(),
|
||||
[...single.tree.values()].map(n => n.actual.id).sort(),
|
||||
[single.root.id, 'id-a', 'id-aa', 'id-ab', 'id-ac', 'id-b'],
|
||||
);
|
||||
assert.strictEqual(single.tree.size, 6);
|
||||
|
@ -184,7 +190,7 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-a', expand: TestItemExpandState.Expanded, item: { label: 'Hello world' } },
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.Expanded, item: { label: 'Hello world' } },
|
||||
],
|
||||
]);
|
||||
|
||||
|
@ -192,7 +198,7 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-a', item: { label: 'still connected' } }
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), item: { label: 'still connected' } }
|
||||
],
|
||||
]);
|
||||
|
||||
|
@ -215,11 +221,11 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-a', expand: TestItemExpandState.Expanded },
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.Expanded },
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-ab', item: { label: 'Hello world' } },
|
||||
{ extId: TestId.fromExtHostTestItem(oldAB, 'ctrlId').toString(), item: { label: 'Hello world' } },
|
||||
],
|
||||
]);
|
||||
|
||||
|
@ -229,11 +235,11 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-aa', item: { label: 'still connected1' } }
|
||||
{ extId: new TestId(['ctrlId', 'id-a', 'id-aa']).toString(), item: { label: 'still connected1' } }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-ab', item: { label: 'still connected2' } }
|
||||
{ extId: new TestId(['ctrlId', 'id-a', 'id-ab']).toString(), item: { label: 'still connected2' } }
|
||||
],
|
||||
]);
|
||||
|
||||
|
@ -250,11 +256,11 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Remove,
|
||||
'id-b',
|
||||
new TestId(['ctrlId', 'id-b']).toString(),
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: 'id-a', expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(single.tree.get('id-b')!.actual) }
|
||||
{ controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(b, 'ctrlId') }
|
||||
],
|
||||
]);
|
||||
|
||||
|
@ -262,7 +268,7 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: 'id-b', item: { label: 'still connected' } }
|
||||
{ extId: new TestId(['ctrlId', 'id-a', 'id-b']).toString(), item: { label: 'still connected' } }
|
||||
],
|
||||
]);
|
||||
|
||||
|
@ -469,7 +475,7 @@ suite('ExtHost Testing', () => {
|
|||
assert.strictEqual(tracker.isRunning, true);
|
||||
assert.deepStrictEqual(proxy.$startedExtensionTestRun.args, [
|
||||
[{
|
||||
config: { group: 2, id: 42 },
|
||||
profile: { group: 2, id: 42 },
|
||||
controllerId: 'ctrl',
|
||||
id: tracker.id,
|
||||
include: [single.root.id],
|
||||
|
@ -504,9 +510,9 @@ suite('ExtHost Testing', () => {
|
|||
'ctrl',
|
||||
tracker.id,
|
||||
[
|
||||
convert.TestItem.from(single.root),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!.children.get('id-aa')!),
|
||||
convert.TestItem.from(single.root, 'ctrlId'),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!, 'ctrlId'),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!.children.get('id-aa')!, 'ctrlId'),
|
||||
]
|
||||
]);
|
||||
assert.deepStrictEqual(proxy.$addTestsToRun.args, expectedArgs);
|
||||
|
@ -517,8 +523,8 @@ suite('ExtHost Testing', () => {
|
|||
'ctrl',
|
||||
tracker.id,
|
||||
[
|
||||
convert.TestItem.from(single.root.children.get('id-a')!),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!.children.get('id-ab')!),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!, 'ctrlId'),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!.children.get('id-ab')!, 'ctrlId'),
|
||||
],
|
||||
]);
|
||||
assert.deepStrictEqual(proxy.$addTestsToRun.args, expectedArgs);
|
||||
|
@ -543,13 +549,12 @@ suite('ExtHost Testing', () => {
|
|||
test('excludes tests outside tree or explicitly excluded', () => {
|
||||
single.expand(single.root.id, Infinity);
|
||||
|
||||
const task = c.createTestRun('ctrl', single, {
|
||||
const task = c.createTestRun('ctrlId', single, {
|
||||
profile: configuration,
|
||||
include: [single.root.children.get('id-a')!],
|
||||
exclude: [single.root.children.get('id-a')!.children.get('id-aa')!],
|
||||
}, 'hello world', false);
|
||||
|
||||
task.setState(single.root.children.get('b')!, TestResultState.Passed);
|
||||
task.setState(single.root.children.get('id-a')!.children.get('id-aa')!, TestResultState.Passed);
|
||||
task.setState(single.root.children.get('id-a')!.children.get('id-ab')!, TestResultState.Passed);
|
||||
|
||||
|
@ -558,7 +563,7 @@ suite('ExtHost Testing', () => {
|
|||
assert.deepStrictEqual(proxy.$updateTestStateInRun.args, [[
|
||||
args[0],
|
||||
args[1],
|
||||
'id-ab',
|
||||
new TestId(['ctrlId', 'id-a', 'id-ab']).toString(),
|
||||
TestResultState.Passed,
|
||||
undefined,
|
||||
]]);
|
||||
|
|
Loading…
Reference in a new issue