Skip to content

Commit

Permalink
Initial checkin to enable Test Explorer view
Browse files Browse the repository at this point in the history
For microsoft#4272

- Enables the Test Activity in VS Code
- Adds a single view
- Adds a single command (no icon)
- Adds dummy tree view data
  • Loading branch information
d3r3kk committed Feb 5, 2019
1 parent 11bbf52 commit 2afaa8a
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 2 deletions.
16 changes: 15 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,12 @@
"category": "Python",
"when": "python.datascience.haveinteractive && python.datascience.featureenabled"
}
],
"view/title": [
{
"command": "python.runtests",
"group": "navigation"
}
]
},
"debuggers": [
Expand Down Expand Up @@ -1867,7 +1873,15 @@
"fileMatch": "meta.yaml",
"url": "./schemas/conda-meta.json"
}
]
],
"views": {
"test": [
{
"id": "python_tests",
"name": "PYTHON"
}
]
}
},
"scripts": {
"package": "gulp clean && gulp prePublishBundle && vsce package",
Expand Down
5 changes: 4 additions & 1 deletion src/client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if ((Reflect as any).metadata === undefined) {
}

// Initialize source maps (this must never be moved up nor further down).
import {initialize } from './sourceMapSupport';
import { initialize } from './sourceMapSupport';
initialize(require('vscode'));

const durations: Record<string, number> = {};
Expand Down Expand Up @@ -93,6 +93,7 @@ import { ReplProvider } from './providers/replProvider';
import { registerTypes as providersRegisterTypes } from './providers/serviceRegistry';
import { activateSimplePythonRefactorProvider } from './providers/simpleRefactorProvider';
import { TerminalProvider } from './providers/terminalProvider';
import { PythonTestTreeViewProvider } from './providers/testTreeViewProvider';
import { ISortImportsEditingProvider } from './providers/types';
import { activateUpdateSparkLibraryProvider } from './providers/updateSparkLibraryProvider';
import { sendTelemetryEvent } from './telemetry';
Expand Down Expand Up @@ -206,6 +207,8 @@ async function activateUnsafe(context: ExtensionContext): Promise<IExtensionApi>

context.subscriptions.push(languages.registerCodeActionsProvider(PYTHON, new PythonCodeActionProvider(), { providedCodeActionKinds: [CodeActionKind.SourceOrganizeImports] }));

context.subscriptions.push(window.registerTreeDataProvider('python_tests', new PythonTestTreeViewProvider()));

serviceContainer.getAll<DebugConfigurationProvider>(IDebugConfigurationService).forEach(debugConfigProvider => {
context.subscriptions.push(debug.registerDebugConfigurationProvider(DebuggerTypeName, debugConfigProvider));
});
Expand Down
38 changes: 38 additions & 0 deletions src/client/providers/testTreeViewItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

'use strict';

import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { TestStatus } from '../unittests/common/types';

export enum PythonTestTreeItemType {
Root = 'Root',
Package = 'Package',
File = 'File',
Suite = 'Suite',
Function = 'Function'
}

export class PythonTestTreeItem extends TreeItem {

constructor(
private kind: PythonTestTreeItemType,
private myParent: PythonTestTreeItem,
private myChildren: PythonTestTreeItem[],
private runId: string,
private name: string,
private testStatus: TestStatus = TestStatus.Unknown) {

super(`[${kind}] ${name}`, kind === PythonTestTreeItemType.Function ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed);
}

public get children(): PythonTestTreeItem[] {
return this.myChildren;

}

public get parent(): PythonTestTreeItem {
return this.myParent;
}
}
108 changes: 108 additions & 0 deletions src/client/providers/testTreeViewProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

'use strict';

import {
Event, EventEmitter,
ProviderResult, TreeDataProvider
} from 'vscode';
import {
TestStatus
} from '../unittests/common/types';
import {
PythonTestTreeItem,
PythonTestTreeItemType
} from './testTreeViewItem';

export class PythonTestTreeViewProvider implements TreeDataProvider<PythonTestTreeItem> {
/**
* This will trigger the view to update the changed element/root and its children recursively (if shown).
* To signal that root has changed, do not pass any argument or pass `undefined` or `null`.
*/
public readonly onDidChangeTreeData: Event<PythonTestTreeItem | undefined>;

private _onDidChangeTreeData: EventEmitter<PythonTestTreeItem | undefined> = new EventEmitter<PythonTestTreeItem | undefined>();
private root: PythonTestTreeItem[];

constructor() {
this.onDidChangeTreeData = this._onDidChangeTreeData.event;
// set up some dummy data to just show that the test explorer loads.
this.root = this.getTestTree();
}

/**
* Get [TreeItem](#TreeItem) representation of the `element`
*
* @param element The element for which [TreeItem](#TreeItem) representation is asked for.
* @return [TreeItem](#TreeItem) representation of the element
*/
public async getTreeItem(element: PythonTestTreeItem): Promise<PythonTestTreeItem> {
return element;
}

/**
* Get the children of `element` or root if no element is passed.
*
* @param element The element from which the provider gets children. Can be `undefined`.
* @return Children of `element` or root if no element is passed.
*/
public getChildren(element?: PythonTestTreeItem): ProviderResult<PythonTestTreeItem[]> {
if (element === undefined) {
return this.root;
}
return element.children;
}

/**
* Optional method to return the parent of `element`.
* Return `null` or `undefined` if `element` is a child of root.
*
* **NOTE:** This method should be implemented in order to access [reveal](#TreeView.reveal) API.
*
* @param element The element for which the parent has to be returned.
* @return Parent of `element`.
*/
public getParent?(element: PythonTestTreeItem): ProviderResult<PythonTestTreeItem> {
return element.parent;
}

private getTestTree(): PythonTestTreeItem[] {
// create a sample tree just to get the feature up and running
const roots: PythonTestTreeItem[] = [];
const root1: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Root, undefined, [], '/test', '/test');
roots.push(root1);

const root1_pkg1: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Package, root1, [], '/test/module1', 'module1');
root1.children.push(root1_pkg1);

const root1_pkg1_file1: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.File, root1_pkg1, [], '/test/module1/test_file1.py', 'test_file1.py');
root1_pkg1.children.push(root1_pkg1_file1);

const root1_pkg1_file1_fn1: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Function, root1_pkg1_file1, undefined, '/test/module1/test_file1.py::test_function_1', 'test_function_1');
root1_pkg1_file1.children.push(root1_pkg1_file1_fn1);

const root1_pkg1_file1_fn2: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Function, root1_pkg1_file1, undefined, '/test/module1/test_file1.py::test_function_2', 'test_function_2');
root1_pkg1_file1.children.push(root1_pkg1_file1_fn2);

const root1_pkg1_file1_suite1: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Suite, root1_pkg1_file1, [], '/test/module1/test_file1.py::TestSuite1', 'TestSuite1');
root1_pkg1_file1.children.push(root1_pkg1_file1_suite1);

const root1_pkg1_file1_suite1_fn1: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Function, root1_pkg1_file1_suite1, undefined, '/test/module1/test_file1.py::TestSuite1::test_suite1_fn1', 'test_suite1_fn1');
root1_pkg1_file1_suite1.children.push(root1_pkg1_file1_suite1_fn1);

const root1_pkg1_file1_suite1_fn2: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Function, root1_pkg1_file1_suite1, undefined, '/test/module1/test_file1.py::TestSuite1::test_suite1_fn2', 'test_suite1_fn2');
root1_pkg1_file1_suite1.children.push(root1_pkg1_file1_suite1_fn2);

const root1_pkg1_file1_suite2: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Suite, root1_pkg1_file1, [], '/test/module1/test_file1.py::TestSuite2', 'TestSuite2');
root1_pkg1_file1.children.push(root1_pkg1_file1_suite2);

const root1_pkg1_file1_suite2_fn1: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Function, root1_pkg1_file1_suite2, undefined, '/test/module1/test_file1.py::TestSuite2::test_suite2_fn1', 'test_suite2_fn1');
root1_pkg1_file1_suite2.children.push(root1_pkg1_file1_suite2_fn1);

const root1_pkg1_file1_suite2_fn2: PythonTestTreeItem = new PythonTestTreeItem(PythonTestTreeItemType.Function, root1_pkg1_file1_suite2, undefined, '/test/module1/test_file1.py::TestSuite2::test_suite2_fn2', 'test_suite2_fn2');
root1_pkg1_file1_suite2.children.push(root1_pkg1_file1_suite2_fn2);

return roots;
}
}

0 comments on commit 2afaa8a

Please sign in to comment.