Refactor tests#7702
Conversation
|
Kudos, SonarCloud Quality Gate passed! |
|
🔒 Automated review in progress — @rchiodo is auto-reviewing this PR. |
There was a problem hiding this comment.
Pull request overview
This PR refactors parts of the UI test utilities to make Solution Explorer interactions and project loading more robust, primarily by adjusting solution-node identification, adding UI-thread helpers for IVs* interactions, and hardening TreeView node-name comparisons.
Changes:
- Simplifies how the solution root node text is computed for Solution Explorer interactions.
- Updates
VisualStudioApp.OpenProjectto route more IVs* API calls through new UI-thread helper methods. - Sanitizes
AutomationElement.NamePropertyvalues during Solution Explorer tree traversal to handle non-printable characters.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| Common/Tests/Utilities.UI/UI/VisualStudioInstance.cs | Changes solution root node label construction used for Solution Explorer lookups. |
| Common/Tests/Utilities.UI/UI/VisualStudioApp.cs | Refactors project/solution open flow and adds UI-thread helper methods for IVs* calls. |
| Common/Tests/Utilities.UI/UI/TreeView.cs | Sanitizes node names (regex) before comparing path segments. |
| Common/Tests/Utilities.UI/TestUtilities.UI.csproj | Adds a project reference to VSCommon. |
| .vscode/settings.json | Adds a VS Code workspace setting for a specific extension. |
| var solutionName = Path.GetFileNameWithoutExtension(_solution.Filename); | ||
| return $"Solution '{solutionName}'"; |
| var name = (node.GetCurrentPropertyValue(AutomationElement.NameProperty) as string); | ||
|
|
||
| // Sometimes AutomationElement.NameProperty contains non-printable characters that mess up the | ||
| // string compare, so get rid of those. | ||
| // See https://stackoverflow.com/questions/40564692/c-sharp-regex-to-remove-non-printable-characters-and-control-characters-in-a | ||
| name = Regex.Replace(name, @"\p{C}+", string.Empty).Trim(); |
| using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
| using Microsoft.VisualStudio.Threading; | ||
| using Microsoft.VisualStudioTools; | ||
| using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; |
| t = CreateTaskOnUIThread(async () => | ||
| { | ||
| ErrorHandler.ThrowOnFailure(solution.OpenSolutionFile((uint)0, fullPath)); | ||
| }); |
| t = CreateTaskOnUIThread(async () => | ||
| { | ||
| Guid guidNull = Guid.Empty; | ||
| Guid iidUnknown = Guid.Empty; | ||
| IntPtr projPtr; |
| object o; | ||
| ErrorHandler.ThrowOnFailure(vsProject.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out o)); | ||
| var project = (Project)o; |
| { | ||
| "marquee.widgets.npm-stats.packageNames": [ | ||
| "ptvs" | ||
| ] | ||
| } No newline at end of file |
|
@copilot resolve the merge conflicts in this pull request |
| while (!t.Wait(1000, cts.Token)) { | ||
| while (!t.Wait(1000, cts.Token)) | ||
| { | ||
| ErrorHandler.ThrowOnFailure(uiShell.GetDialogOwnerHwnd(out hwnd)); |
There was a problem hiding this comment.
The threading fix is incomplete: the new comment states "everything from the IVs* APIs need to run on the UI thread," but IVsUIShell.GetDialogOwnerHwnd here — and vsProject.GetProperty at ~1057 — still run on the calling background thread while their neighbors (GetSolutionInfo, EnumerateLoadedProjects, GetGuidOfProject, ReloadProject) were wrapped in RunOnUIThread. Off-thread IVs* calls can throw RPC_E_WRONG_THREAD or silently COM-marshal. Either wrap these in RunOnUIThread too, or narrow the "everything" wording to match reality.
| { | ||
| try | ||
| { | ||
| if (!t.Wait(1000, cts.Token)) |
There was a problem hiding this comment.
CreateTaskOnUIThread returns the raw .Task from a JoinableTask, and the caller blocks with t.Wait(1000, cts.Token). Extracting and blocking on JoinableTask.Task bypasses JTF's joinable-collection deadlock mitigation. It's safe today only because OpenProject runs off the UI thread and the lambda bodies are synchronous; if OpenProject is ever invoked on the UI thread, the scheduled main-thread continuation can't run while Wait() blocks that thread, deadlocking until the 30s CTS fires. Prefer returning the JoinableTask and driving the dialog-poll loop via Join()/JoinAsync.
| "marquee.widgets.npm-stats.packageNames": [ | ||
| "ptvs" | ||
| ] | ||
| } No newline at end of file |
There was a problem hiding this comment.
This file appears to be unrelated scope creep in a "Refactor tests" PR — it only sets a personal Marquee npm-stats widget config and is unrelated to test reliability. Consider dropping it from the change. (It is also missing a trailing newline.)
| else | ||
| { | ||
| t = CreateTaskOnUIThread(async () => | ||
| { |
There was a problem hiding this comment.
These async () => { ... } lambdas contain no await, producing CS1998 ("runs synchronously"). Harmless at runtime since the body executes on the UI thread after SwitchToMainThreadAsync() inside the helper, but if the harness project sets TreatWarningsAsErrors the build breaks. Drop the async keyword (return Task.CompletedTask) to silence the warning.
|
Solid test-reliability refactor. A few non-blocking notes: the UI-thread marshaling is applied inconsistently (a couple of IVs* calls remain off-thread), the JTF |
rchiodo
left a comment
There was a problem hiding this comment.
Approved via Review Center.
|
|
||
| var solutionName = Path.GetFileNameWithoutExtension(_solution.Filename); | ||
| return $"Solution '{solutionName}'"; | ||
| } |
There was a problem hiding this comment.
Collapsing SolutionNodeText to $"Solution '{solutionName}'" drops the (N of N projects) suffix and no longer consults _solution.Projects. This may be correct if a newer VS version removed the count from the solution root node, but it's an unexplained behavioral change. A one-line comment citing the VS-version behavior that motivated it would help; any consumer/FindNode match still expecting the old count text would silently mismatch.
|
Overall this looks fine to merge. A couple of non-blocking notes: the UI-thread wrapping is applied inconsistently across the IVs* calls, and there's an unrelated .vscode/settings.json change that should probably be dropped from a test-refactor PR. |
rchiodo
left a comment
There was a problem hiding this comment.
Approved via Review Center.








No description provided.