-
Notifications
You must be signed in to change notification settings - Fork 673
improve TestExplorer test #8337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bschnurr
wants to merge
3
commits into
microsoft:main
Choose a base branch
from
bschnurr:fix-testexplorer-test
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+100
−59
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
| 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( | ||
|
|
@@ -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; | ||
| } | ||
|
|
||
|
|
@@ -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; | ||
| } | ||
|
|
||
|
|
@@ -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() | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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(); | ||
| } | ||
|
|
||
|
|
@@ -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); | ||
|
|
@@ -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); | ||
| } | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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