Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
Merge pull request #80 from dannymcgee/organize-tests-by-labels-ignor…
Browse files Browse the repository at this point in the history
…e-directory-structure

Fix #79 | Add "Flatten Tests in Explorer" option
  • Loading branch information
rossknudsen authored Aug 10, 2020
2 parents d1dbd09 + 484f5d9 commit c1bebce
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 4 deletions.
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@
"type": "boolean",
"default": true
},
"jestTestExplorer.flattenExplorer": {
"description": "When true, tests in the Test Explorer will be grouped only by `describe` labels instead of file/folder structure.",
"scope": "resource",
"title": "Flatten Tests in Explorer",
"type": "boolean",
"default": false
},
"jestTestExplorer.featureToggles": {
"description": "A list of feature toggles to enable experimental features.",
"scope": "window",
Expand Down
43 changes: 40 additions & 3 deletions src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ import {
RetireEvent,
TestAdapter,
TestEvent,
TestInfo,
TestLoadFinishedEvent,
TestLoadStartedEvent,
TestRunFinishedEvent,
TestRunStartedEvent,
TestSuiteEvent,
TestSuiteInfo,
} from "vscode-test-adapter-api";
import { Log } from "vscode-test-adapter-util";
import { EXTENSION_CONFIGURATION_NAME } from './constants';
import { emitTestCompleteRootNode, emitTestRunningRootNode } from "./helpers/emitTestCompleteRootNode";
import { filterTree } from "./helpers/filterTree";
import { mapIdToString, mapStringToId } from "./helpers/idMaps";
import { mapJestTestResultsToTestEvents } from "./helpers/mapJestTestResultsToTestEvents";
import { mapTestIdsToTestFilter } from "./helpers/mapTestIdsToTestFilter";
import { mapWorkspaceRootToSuite } from "./helpers/mapTreeToSuite";
import { flatMapWorkspaceRootToSuite, mapWorkspaceRootToSuite } from "./helpers/mapTreeToSuite";
import mergeRuntimeResults from "./helpers/mergeRuntimeResults";
import { createWorkspaceRootNode, ProjectRootNode, WorkspaceRootNode } from "./helpers/tree";
import JestManager, { JestTestAdapterOptions } from "./JestManager";
Expand Down Expand Up @@ -88,7 +91,17 @@ export default class JestTestAdapter implements TestAdapter {

const state = await this.projectManager.getTestState();
this.tree = state.suite;
const suite = mapWorkspaceRootToSuite(this.tree);

const flattenExplorer = vscode.workspace
.getConfiguration(EXTENSION_CONFIGURATION_NAME, null)
.get<boolean>("flattenExplorer", false);

const suite = flattenExplorer
? flatMapWorkspaceRootToSuite(this.tree)
: mapWorkspaceRootToSuite(this.tree);

this.log.info("Results:");
this.logSuite(suite);

this.testsEmitter.fire({ suite, type: "finished" });
} catch (error) {
Expand Down Expand Up @@ -221,7 +234,14 @@ export default class JestTestAdapter implements TestAdapter {
this.testsEmitter.fire({ type: "started" });

this.tree = event.suite;
const suite = mapWorkspaceRootToSuite(this.tree);

const flattenExplorer = vscode.workspace
.getConfiguration(EXTENSION_CONFIGURATION_NAME, null)
.get<boolean>("flattenExplorer", false);

const suite = flattenExplorer
? flatMapWorkspaceRootToSuite(this.tree)
: mapWorkspaceRootToSuite(this.tree);

switch (event.type) {
case "projectAdded":
Expand Down Expand Up @@ -262,4 +282,21 @@ export default class JestTestAdapter implements TestAdapter {
private retireAllTests() {
this.retireEmitter.fire({});
}

private logSuite(suiteOrTest?: TestSuiteInfo|TestInfo, depth: number = 0): void {
if (_.isNil(suiteOrTest)) { return; }

const indent = (inDepth: number): string => Array(inDepth).fill(" ").join("");

if (suiteOrTest.label) {
this.log.info(`${indent(depth)}${suiteOrTest.label} (${suiteOrTest.type})`);
}

const suite = suiteOrTest as TestSuiteInfo;
if (suite.children?.length > 0) {
for (const child of suite.children) {
this.logSuite(child, depth + 1);
}
}
}
}
55 changes: 54 additions & 1 deletion src/helpers/mapTreeToSuite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
FileNode,
FileWithParseErrorNode,
FolderNode,
isFolderNode,
isProjectRootNode,
ProjectRootNode,
TestNode,
WorkspaceRootNode,
Expand Down Expand Up @@ -39,6 +41,57 @@ const mapWorkspaceRootToSuite = (rootNode: WorkspaceRootNode): TestSuiteInfo | u
};
};

const flatMapWorkspaceRootToSuite = ({ projects, id, label }: WorkspaceRootNode): TestSuiteInfo | undefined => {
if (!projects.length) {
return undefined;
}

const suite = projects.reduce<TestSuiteInfo>((results, project) => {
// Get an array of only the describe blocks in the current project.
const describeBlocks = findDescribeBlocksInNode(project);

// Map the describe blocks to a tree of suites, nested suites, and tests.
const currentChildren = describeBlocks.map(mapDescribeBlockToTestSuite);

// Merge this project's suites into the results.
const children = results.children.concat(currentChildren);

return { ...results, children };
}, {
children: [],
id,
label,
type: "suite",
});

// If the final children array is empty, return undefined to prevent the empty project from appearing in the list.
if (suite.children.length === 0) {
return undefined;
}

return suite;
};

/**
* Recursively performs a deep search of the given node, returning a flat array of DescribeNodes
*
* @param node The node to begin searching
* @param results Accumulated results so far (only relevant for recursive iterations)
*/
const findDescribeBlocksInNode = (
node: ProjectRootNode | FolderNode | FileNode | FileWithParseErrorNode,
results: DescribeNode[] = [],
): DescribeNode[] => {
if (isProjectRootNode(node) || isFolderNode(node)) {
const describesInFolders = _.flatMap(node.folders, (folder) => findDescribeBlocksInNode(folder, results));
const describesInFiles = _.flatMap(node.files, (file) => findDescribeBlocksInNode(file, results));

return describesInFolders.concat(describesInFiles).concat(results);
} else {
return node.describeBlocks.concat(results);
}
};

const shouldHideEmptyProjects = () =>
vscode.workspace.getConfiguration(EXTENSION_CONFIGURATION_NAME, null).get<boolean>("hideEmptyProjects") ?? true;

Expand Down Expand Up @@ -100,4 +153,4 @@ const mapTestToTestInfo = (test: TestNode): TestInfo => ({
type: "test",
});

export { mapWorkspaceRootToSuite, mapFileNodeToTestSuite, mapDescribeBlockToTestSuite, mapTestToTestInfo };
export { mapWorkspaceRootToSuite, mapFileNodeToTestSuite, mapDescribeBlockToTestSuite, mapTestToTestInfo, flatMapWorkspaceRootToSuite };
8 changes: 8 additions & 0 deletions src/helpers/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ export interface NodeVisitor {
visitTestNode: (test: TestNode) => void;
}

export const isProjectRootNode = (node: { type: string }): node is ProjectRootNode => {
return node.type === "projectRootNode";
}

export const isFolderNode = (node: { type: string }): node is FolderNode => {
return node.type === "folder";
}

export const createWorkspaceRootNode = (): WorkspaceRootNode => {
return {
id: "root",
Expand Down

0 comments on commit c1bebce

Please sign in to comment.