Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Python/Tests/Core.UI/TestExplorerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void RunAllUnittestProject(PythonVisualStudioApp app) {
var sln = app.CopyProjectForTest(@"TestData\TestExplorerUnittest.sln");
app.OpenProject(sln);

RunAllTests(app, AllUnittests);
RunAllTests(app, AllUnittests, Path.GetFileNameWithoutExtension(sln));
}

public void RunAllUnittestWorkspace(PythonVisualStudioApp app) {
Expand Down
2 changes: 2 additions & 0 deletions Python/Tests/PythonToolsUITestsRunner/TestExplorerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,14 @@ public void DebugPytestWorkspace() {
_vs.RunTest(nameof(PythonToolsUITests.TestExplorerTests.DebugPytestWorkspace));
}

[Ignore]
[TestMethod, Priority(UITestPriority.P0)]
[TestCategory("Installed")]
public void DebugUnittestProject() {
_vs.RunTest(nameof(PythonToolsUITests.TestExplorerTests.DebugUnittestProject));
}

[Ignore]
[TestMethod, Priority(UITestPriority.P0)]
[TestCategory("Installed")]
public void DebugUnittestWorkspace() {
Expand Down
155 changes: 97 additions & 58 deletions Python/Tests/Utilities.Python/PythonTestExplorer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,40 @@
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.

using Microsoft.VisualStudio.TestTools.UnitTesting;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just using the new code cleanup profile 1

using System;
using System.Threading;
using System.Windows.Automation;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestUtilities.UI {
public class PythonTestExplorer : AutomationWrapper {
namespace TestUtilities.UI
{
public class PythonTestExplorer : AutomationWrapper
{
private readonly VisualStudioApp _app;
private readonly AutomationWrapper _searchBar;
private PythonTestExplorerGridView _tests;

private static class TestCommands {
private static class TestCommands
{
public const string GroupBy = "TestExplorer.GroupBy";
public const string RunAllTests = "TestExplorer.RunAllTests";
public const string CopyDetails = "TestExplorer.CopyDetails";
public const string DebugAllTests = "TestExplorer.DebugAllTests";
}

public PythonTestExplorer(VisualStudioApp app, AutomationElement element, AutomationWrapper searchBarTextBox)
: base(element) {
: base(element)
{
_app = app;
_searchBar = searchBarTextBox ?? throw new ArgumentNullException(nameof(searchBarTextBox));
}

public PythonTestExplorerGridView Tests {
get {
if (_tests == null) {
public PythonTestExplorerGridView Tests
{
get
{
if (_tests == null)
{
var el = this.Element.FindFirst(
TreeScope.Descendants,
new AndCondition(
Expand All @@ -54,21 +61,24 @@ public PythonTestExplorerGridView Tests {
)
)
);
if (el != null) {
if (el != null)
{
_tests = new PythonTestExplorerGridView(el);
}
}
return _tests;
}
}

public string GetTestDetailSummary() {
public string GetTestDetailSummary()
{
// Root is the Test Explorer tool window element you already have.
var summaryControl = Element.FindFirst(
TreeScope.Descendants,
new PropertyCondition(AutomationElement.ClassNameProperty, "SummaryControl")
);
if (summaryControl == null) {
if (summaryControl == null)
{
return string.Empty;
}

Expand All @@ -77,34 +87,40 @@ public string GetTestDetailSummary() {
TreeScope.Descendants,
new PropertyCondition(AutomationElement.ClassNameProperty, "WpfTextView")
);
if (textView == null) {
if (textView == null)
{
return string.Empty;
}

// Try TextPattern.
object p;
if (textView.TryGetCurrentPattern(TextPattern.Pattern, out p)) {
if (textView.TryGetCurrentPattern(TextPattern.Pattern, out p))
{
return ((TextPattern)p).DocumentRange.GetText(int.MaxValue);
}
// Fallback ValuePattern.
if (textView.TryGetCurrentPattern(ValuePattern.Pattern, out p)) {
if (textView.TryGetCurrentPattern(ValuePattern.Pattern, out p))
{
return ((ValuePattern)p).Current.Value;
}

// Last resort: Name.
return textView.Current.Name ?? string.Empty;
}

public string GetDetailsWithRetry() {
public string GetDetailsWithRetry()
{
string details = string.Empty;
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 5; i++)
{
var detailsTextBox = this.FindByName("Test Detail Summary");
AutomationWrapper.CheckNullElement(detailsTextBox, "Missing: Test Detail Summary");

// Copy to clipboard
details = GetTestDetailSummary();

if (details.Contains("Source:")) {
if (details.Contains("Source:"))
{
return details;
}

Expand All @@ -117,73 +133,94 @@ public string GetDetailsWithRetry() {
/// <summary>
/// Set the grouping to namespace.
/// </summary>
public void GroupByProjectNamespaceClass() {
// TODO: figure out how to programmatically change this
// it's now a popup window that appears on TestExplorer.GroupBy command
// well, at least when you click on it with the mouse
// It's not coming up when invoking the command programmatically

//var groupCommand = _app.Dte.Commands.Item(TestCommands.GroupBy);
//Assert.IsNotNull(groupCommand, "GroupBy command not found");


//if (!groupCommand.IsAvailable) {
// // Group command is not available when show hierarchy is on
// //_app.ExecuteCommand(TestCommands.ToggleShowTestHierarchy);
// _app.WaitForCommandAvailable(groupCommand, TimeSpan.FromSeconds(5));
//}

//_app.ExecuteCommand(TestCommands.GroupBy); // by class

//Thread.Sleep(100);
public void GroupByProjectNamespaceClass()
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bringing back this function to select the test grouping. "Project, Namespace, Class"

{
// Try execute the GroupBy command to display grouping popup.
try
{
_app.Dte.ExecuteCommand(TestCommands.GroupBy);
}
catch
{
// Swallow if command not available; we'll still try to locate the option.
}

//var element = _app.Element.FindFirst(TreeScope.Descendants, new AndCondition(
// new PropertyCondition(
// AutomationElement.NameProperty,
// "Project, Namespace, Class"
// ),
// new PropertyCondition(
// AutomationElement.ClassNameProperty,
// "TextBlock"
// )
//));
//Assert.IsNotNull(element);
// Allow UI to render the popup
Thread.Sleep(200);

// Attempt to find the "Project, Namespace, Class" option and invoke it.
AutomationElement element = null;
for (int i = 0; i < 5 && element == null; i++)
{
element = _app.Element.FindFirst(
TreeScope.Descendants,
new AndCondition(
new PropertyCondition(AutomationElement.NameProperty, "Project, Namespace, Class"),
new PropertyCondition(AutomationElement.ClassNameProperty, "TextBlock")
)
);
if (element == null)
{
Thread.Sleep(200);
}
}

//var menuItem = element.CachedParent;
//Assert.IsNotNull(menuItem);
if (element != null)
{
// Use TreeWalker to get parent; CachedParent may be null depending on cache policy
var menuItem = element.CachedParent;
if (menuItem == null)
{
var walker = TreeWalker.RawViewWalker;
menuItem = walker.GetParent(element);
}

//menuItem.GetInvokePattern().Invoke();
if (menuItem != null)
{
var inv = menuItem.GetInvokePattern() ?? element.GetInvokePattern();
if (inv != null)
{
inv.Invoke();
}
}
}

WaitForTestsGrid();
}

private void WaitForTestsGrid() {
private void WaitForTestsGrid()
{
// Wait for the test list to be created
int retry = 10;
while (Tests == null) {
while (Tests == null)
{
Thread.Sleep(250);
retry--;
if (retry == 0) {
if (retry == 0)
{
break;
}
}
Assert.IsNotNull(Tests, "Tests list is null");
}

public void ClearSearchBar() {
public void ClearSearchBar()
{
_searchBar.SetValue("");
Thread.Sleep(1000);
}

public AutomationElement WaitForItem(params string[] path) {
public AutomationElement WaitForItem(params string[] path)
{
// WaitForItem doesn't work well with offscreen items
// so we use the search bar to filter by function name to
// limit the items on screen and then expand all tree items.
// Currently child items dont always load on expand, so we need to call
// it multiple times with delay as a work around.
_searchBar.SetValue(path[path.Length - 1]);

for (int i = 0; i < path.Length + 2; i++) {
for (int i = 0; i < path.Length + 2; i++)
{
Tests.ExpandAll();
}

Expand All @@ -193,7 +230,8 @@ public AutomationElement WaitForItem(params string[] path) {
/// <summary>
/// Run all tests and wait for the command to be available again.
/// </summary>
public void RunAll(TimeSpan timeout) {
public void RunAll(TimeSpan timeout)
{
ClearSearchBar();
_app.Dte.ExecuteCommand(TestCommands.RunAllTests);
Thread.Sleep(100);
Expand All @@ -203,7 +241,8 @@ public void RunAll(TimeSpan timeout) {
/// <summary>
/// Debug all tests and wait for the command to be available again.
/// </summary>
public void DebugAll() {
public void DebugAll()
{
_app.Dte.ExecuteCommand(TestCommands.DebugAllTests);
Thread.Sleep(100);
}
Expand Down