Skip to content

Commit

Permalink
Updated icons and tooltip in test explorer indicating status of test …
Browse files Browse the repository at this point in the history
…files/suites
  • Loading branch information
Kartik Raj committed Mar 5, 2019
1 parent 15b21d1 commit f101221
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 11 deletions.
1 change: 1 addition & 0 deletions news/1 Enhancements/4583.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update icons and tooltip in test explorer indicating status of test files/suites
4 changes: 3 additions & 1 deletion resources/dark/status-error.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion resources/dark/status-ok.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion resources/light/status-ok.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 69 additions & 3 deletions src/client/unittests/common/services/testResultsService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { inject, injectable, named } from 'inversify';
import { TestDataItem } from '../../types';
import { visitParentsRecursive } from '../testVisitors/visitor';
import { ITestResultsService, ITestVisitor, TestFile, TestFolder, Tests, TestStatus, TestSuite } from './../types';

@injectable()
Expand All @@ -12,19 +14,57 @@ export class TestResultsService implements ITestResultsService {
}
public updateResults(tests: Tests): void {
tests.testFiles.forEach(test => this.updateTestFileResults(test));
tests.testFolders.forEach(folder => this.updateTestFolderResults(folder));
tests.rootTestFolders.forEach(folder => this.updateTestFolderResults(folder));
// List items should be updated in order
[true, false, undefined].forEach(item => this.updateParentStatusIcons(tests, item));
}
private updateTestSuiteResults(test: TestSuite): void {
this.updateTestSuiteAndFileResults(test);
}
private updateTestFileResults(test: TestFile): void {
this.updateTestSuiteAndFileResults(test);
}
private updateParentStatusIcons(tests: Tests, pass?: boolean): void {
let status: TestStatus;
switch (pass) {
case true: {
status = TestStatus.Pass;
break;
}
case false: {
status = TestStatus.Fail;
break;
}
default: {
status = TestStatus.Unknown;
}
}
const visitor = (item: TestDataItem) => {
item.status = status;
};
tests.testFiles.forEach(item => {
switch (pass) {
case undefined:
if (typeof item.passed !== 'boolean') {
// Test is skipped, update parent status to Unknown
visitParentsRecursive(tests, item, visitor);
}
break;
default: {
if (pass ? item.passed : !item.passed) {
visitParentsRecursive(tests, item, visitor);
}
}
}
});
}
private updateTestFolderResults(testFolder: TestFolder): void {
let totalTime = 0;
let allFilesPassed = true;
let allFilesRan = true;

testFolder.testFiles.forEach(fl => {
totalTime += fl.time;
if (allFilesPassed && typeof fl.passed === 'boolean') {
if (!fl.passed) {
allFilesPassed = false;
Expand All @@ -35,12 +75,20 @@ export class TestResultsService implements ITestResultsService {

testFolder.functionsFailed! += fl.functionsFailed!;
testFolder.functionsPassed! += fl.functionsPassed!;
if (typeof fl.passed === 'boolean') {
if (fl.passed) {
testFolder.childrenPassed! += 1;
} else {
testFolder.childrenFailed! += 1;
}
}
});

let allFoldersPassed = true;
let allFoldersRan = true;

testFolder.folders.forEach(folder => {
totalTime += folder.time;
this.updateTestFolderResults(folder);
if (allFoldersPassed && typeof folder.passed === 'boolean') {
if (!folder.passed) {
Expand All @@ -52,11 +100,19 @@ export class TestResultsService implements ITestResultsService {

testFolder.functionsFailed! += folder.functionsFailed!;
testFolder.functionsPassed! += folder.functionsPassed!;
if (typeof folder.passed === 'boolean') {
if (folder.passed) {
testFolder.childrenPassed! += 1;
} else {
testFolder.childrenFailed! += 1;
}
}
});

testFolder.time = totalTime;
if (allFilesRan && allFoldersRan) {
testFolder.passed = allFilesPassed && allFoldersPassed;
testFolder.status = testFolder.passed ? TestStatus.Idle : TestStatus.Fail;
testFolder.status = testFolder.passed ? TestStatus.Pass : TestStatus.Fail;
} else {
testFolder.passed = undefined;
testFolder.status = TestStatus.Unknown;
Expand All @@ -72,8 +128,10 @@ export class TestResultsService implements ITestResultsService {
if (typeof fn.passed === 'boolean') {
if (fn.passed) {
test.functionsPassed! += 1;
test.childrenPassed! += 1;
} else {
test.functionsFailed! += 1;
test.childrenFailed! += 1;
allFunctionsPassed = false;
}
} else {
Expand All @@ -97,12 +155,20 @@ export class TestResultsService implements ITestResultsService {

test.functionsFailed! += suite.functionsFailed!;
test.functionsPassed! += suite.functionsPassed!;

if (typeof suite.passed === 'boolean') {
if (suite.passed) {
test.childrenPassed! += 1;
} else {
test.childrenFailed! += 1;
}
}
});

test.time = totalTime;
if (allSuitesRan && allFunctionsRan) {
test.passed = allFunctionsPassed && allSuitesPassed;
test.status = test.passed ? TestStatus.Idle : TestStatus.Error;
test.status = test.passed ? TestStatus.Pass : TestStatus.Error;
} else {
test.passed = undefined;
test.status = TestStatus.Unknown;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class TestResultResetVisitor implements ITestVisitor {
testFunction.status = TestStatus.Unknown;
testFunction.functionsFailed = 0;
testFunction.functionsPassed = 0;
testFunction.childrenFailed = 0;
testFunction.childrenPassed = 0;
testFunction.functionsDidNotRun = 0;
}
public visitTestSuite(testSuite: TestSuite): void {
Expand All @@ -19,6 +21,8 @@ export class TestResultResetVisitor implements ITestVisitor {
testSuite.status = TestStatus.Unknown;
testSuite.functionsFailed = 0;
testSuite.functionsPassed = 0;
testSuite.childrenFailed = 0;
testSuite.childrenPassed = 0;
testSuite.functionsDidNotRun = 0;
}
public visitTestFile(testFile: TestFile): void {
Expand All @@ -27,12 +31,16 @@ export class TestResultResetVisitor implements ITestVisitor {
testFile.status = TestStatus.Unknown;
testFile.functionsFailed = 0;
testFile.functionsPassed = 0;
testFile.childrenFailed = 0;
testFile.childrenPassed = 0;
testFile.functionsDidNotRun = 0;
}
public visitTestFolder(testFolder: TestFolder) {
testFolder.functionsDidNotRun = 0;
testFolder.functionsFailed = 0;
testFolder.functionsPassed = 0;
testFolder.childrenFailed = 0;
testFolder.childrenPassed = 0;
testFolder.passed = undefined;
testFolder.status = TestStatus.Unknown;
}
Expand Down
2 changes: 2 additions & 0 deletions src/client/unittests/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export type TestResult = Node & {
functionsPassed?: number;
functionsFailed?: number;
functionsDidNotRun?: number;
childrenPassed?: number;
childrenFailed?: number;
};

export type Node = {
Expand Down
30 changes: 30 additions & 0 deletions src/client/unittests/explorer/testTreeViewItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export abstract class TestTreeItem extends TreeItem {
case TestStatus.Running: {
return getIcon(Icons.discovering);
}
case TestStatus.Idle:
case TestStatus.Unknown: {
return getIcon(Icons.unknown);
}
default: {
switch (this.testType) {
case TestType.testFile: {
Expand All @@ -75,6 +79,32 @@ export abstract class TestTreeItem extends TreeItem {
return this.parentData;
}

public get tooltip(): string {
if (!this.data) {
return '';
}
if (this.testType === TestType.testFunction) {
switch (this.data.status) {
case TestStatus.Error:
case TestStatus.Fail: {
return `Failed in ${this.data.time} seconds`;
}
case TestStatus.Pass: {
return `Passed in ${this.data.time} seconds`;
}
case TestStatus.Discovering:
case TestStatus.Running: {
return 'Loading...';
}
default: {
return 'Not known';
}
}
} else {
return `${this.data.childrenFailed} failed, ${this.data.childrenPassed} passed in ${this.data.time} seconds`;
}
}

/**
* Tooltip for our tree nodes is the test status
*/
Expand Down
10 changes: 5 additions & 5 deletions src/client/unittests/nosetest/services/parserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class TestsParser implements ITestsParser {
const fullyQualifiedName = path.isAbsolute(fileName) ? fileName : path.resolve(rootDirectory, fileName);
testFile = {
functions: [], suites: [], name: fileName, nameToRun: fileName,
xmlName: currentPackage, time: 0, functionsFailed: 0, functionsPassed: 0,
xmlName: currentPackage, time: 0, functionsFailed: 0, functionsPassed: 0, childrenFailed: 0, childrenPassed: 0,
fullPath: fullyQualifiedName
};
testFiles.push(testFile);
Expand All @@ -97,7 +97,7 @@ export class TestsParser implements ITestsParser {
const testSuite: TestSuite = {
name: clsName, nameToRun: `${fileName}:${clsName}`,
functions: [], suites: [], xmlName: name, time: 0, isUnitTest: false,
isInstance: false, functionsFailed: 0, functionsPassed: 0
isInstance: false, functionsFailed: 0, functionsPassed: 0, childrenFailed: 0, childrenPassed: 0
};
testFile.suites.push(testSuite);
return;
Expand All @@ -107,7 +107,7 @@ export class TestsParser implements ITestsParser {
const testSuite: TestSuite = {
name: path.extname(name).substring(1), nameToRun: `${fileName}:.${name}`,
functions: [], suites: [], xmlName: name, time: 0, isUnitTest: false,
isInstance: false, functionsFailed: 0, functionsPassed: 0
isInstance: false, functionsFailed: 0, functionsPassed: 0, childrenFailed: 0, childrenPassed: 0
};
testFile.suites.push(testSuite);
return;
Expand All @@ -118,7 +118,7 @@ export class TestsParser implements ITestsParser {
const clsName = path.basename(name, path.extname(name));
const fn: TestFunction = {
name: fnName, nameToRun: `${fileName}:${clsName}.${fnName}`,
time: 0, functionsFailed: 0, functionsPassed: 0
time: 0, functionsFailed: 0, functionsPassed: 0, childrenFailed: 0, childrenPassed: 0
};

const cls = testFile.suites.find(suite => suite.name === clsName);
Expand All @@ -131,7 +131,7 @@ export class TestsParser implements ITestsParser {
const name = extractBetweenDelimiters(line, 'nose.selector: DEBUG: wantFunction <function ', ' at ');
const fn: TestFunction = {
name: name, nameToRun: `${fileName}:${name}`,
time: 0, functionsFailed: 0, functionsPassed: 0
time: 0, functionsFailed: 0, functionsPassed: 0, childrenFailed: 0, childrenPassed: 0
};
testFile.functions.push(fn);
return;
Expand Down

0 comments on commit f101221

Please sign in to comment.