diff --git a/Directory.Packages.props b/Directory.Packages.props
index bb6f569f4f9..da98047b43b 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -12,7 +12,6 @@
<_MicrosoftExtensionsPackageVersion>9.0.0
<_BasicReferenceAssembliesVersion>1.7.2
<_BenchmarkDotNetPackageVersion>0.13.5.2136
- <_MicrosoftVisualStudioExtensibilityTestingVersion>0.1.800-beta
<_MicrosoftVisualStudioLanguageServicesPackageVersion>$(MicrosoftVisualStudioLanguageServicesPackageVersion)
<_XunitPackageVersion>2.9.2
<_MicrosoftBuildPackageVersion>17.15.0-preview-25357-08
@@ -65,8 +64,8 @@
-
-
+
+
diff --git a/eng/Version.Details.props b/eng/Version.Details.props
index 50bf16848db..e728fc18493 100644
--- a/eng/Version.Details.props
+++ b/eng/Version.Details.props
@@ -26,6 +26,8 @@ This file should be imported by eng/Versions.props
5.3.0-2.25630.5
5.3.0-2.25630.5
5.3.0-2.25630.5
+ 5.3.0-2.25630.5
+ 5.3.0-2.25630.5
5.3.0-2.25630.5
5.3.0-2.25630.5
@@ -59,6 +61,8 @@ This file should be imported by eng/Versions.props
$(MicrosoftCodeAnalysisWorkspacesMSBuildPackageVersion)
$(MicrosoftCommonLanguageServerProtocolFrameworkPackageVersion)
$(MicrosoftNetCompilersToolsetPackageVersion)
+ $(MicrosoftVisualStudioExtensibilityTestingXunitPackageVersion)
+ $(MicrosoftVisualStudioExtensibilityTestingSourceGeneratorPackageVersion)
$(MicrosoftVisualStudioLanguageServicesPackageVersion)
$(RoslynDiagnosticsAnalyzersPackageVersion)
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index aaae815b9eb..d5d74ee8012 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -62,6 +62,14 @@
https://github.com/dotnet/roslyn
635d2b812121ef9fafe0de223b09be64e5a4a291
+
+ https://github.com/dotnet/roslyn
+ 635d2b812121ef9fafe0de223b09be64e5a4a291
+
+
+ https://github.com/dotnet/roslyn
+ 635d2b812121ef9fafe0de223b09be64e5a4a291
+
https://github.com/dotnet/roslyn
635d2b812121ef9fafe0de223b09be64e5a4a291
diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Caret.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Caret.cs
index b9434a10034..0194f09ae8e 100644
--- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Caret.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Caret.cs
@@ -13,26 +13,14 @@ namespace Microsoft.VisualStudio.Extensibility.Testing;
internal partial class EditorInProcess
{
- public async Task MoveCaretAsync(int position, CancellationToken cancellationToken)
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
-
- var view = await GetActiveTextViewAsync(cancellationToken);
-
- var subjectBuffer = view.GetBufferContainingCaret();
- Assumes.Present(subjectBuffer);
-
- var point = new SnapshotPoint(subjectBuffer.CurrentSnapshot, position);
-
- view.Caret.MoveTo(point);
- }
-
public async Task PlaceCaretAsync(int position, CancellationToken cancellationToken)
{
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
var view = await GetActiveTextViewAsync(cancellationToken);
view.Caret.MoveTo(new SnapshotPoint(view.GetBufferContainingCaret()!.CurrentSnapshot, position));
+
+ await ActivateAsync(cancellationToken);
}
public Task PlaceCaretAsync(string marker, int charsOffset, CancellationToken cancellationToken)
diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Commands.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Commands.cs
index b6ba9a1c68a..dc443b2c582 100644
--- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Commands.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Commands.cs
@@ -6,6 +6,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Razor.Threading;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Razor.IntegrationTests.InProcess;
using Microsoft.VisualStudio.Shell;
@@ -56,13 +57,7 @@ public async Task InvokeRenameAsync(CancellationToken cancellationToken)
{
var commandGuid = typeof(VSStd2KCmdID).GUID;
var commandId = VSStd2KCmdID.RENAME;
-
- // Rename seems to be extra-succeptable to COM exceptions
- await Helper.RetryAsync(async (cancellationToken) =>
- {
- await ExecuteCommandAsync(commandGuid, (uint)commandId, cancellationToken);
- return true;
- }, TimeSpan.FromSeconds(1), cancellationToken);
+ await ExecuteCommandAsync(commandGuid, (uint)commandId, cancellationToken);
}
public async Task CloseCodeFileAsync(string projectName, string relativeFilePath, bool saveFile, CancellationToken cancellationToken)
@@ -88,7 +83,34 @@ private async Task ExecuteCommandAsync(Guid commandGuid, uint commandId, Cancell
{
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
- var dispatcher = await GetRequiredGlobalServiceAsync(cancellationToken);
+ var dispatcher = await TestServices.Shell.GetRequiredGlobalServiceAsync(cancellationToken);
+
+ // Before we execute the command, lets wait until it's enabled and available. Unfortunately this is an annoying COM pattern.
+
+ // Set up the data for the API to fill in. We set command id, it sets the status in "cmdf"
+ var cmds = new OLECMD[1];
+ cmds[0].cmdID = commandId;
+ cmds[0].cmdf = 0;
+
+ await Helper.RetryAsync(ct =>
+ {
+ // The return value here is just whether the QueryStatus call worked, not whether the command is enabled.
+ ErrorHandler.ThrowOnFailure(dispatcher.QueryStatus(ref commandGuid, 1, cmds, IntPtr.Zero));
+
+ // Now check the status flags that were filled in for the command we asked about.
+ var status = (OLECMDF)cmds[0].cmdf;
+ if (status.HasFlag(OLECMDF.OLECMDF_ENABLED) &&
+ status.HasFlag(OLECMDF.OLECMDF_SUPPORTED))
+ {
+ // Returning non-default from RetryAsync stops the retry loop.
+ return SpecializedTasks.True;
+ }
+
+ // Returning default means it will try again.
+ return SpecializedTasks.False;
+ }, TimeSpan.FromMilliseconds(100), cancellationToken);
+
+ // Now we can be reasonably sure the command is available, so execute it.
ErrorHandler.ThrowOnFailure(dispatcher.Exec(commandGuid, commandId, (uint)OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT, IntPtr.Zero, IntPtr.Zero));
}
diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/ShellInProcess.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/ShellInProcess.cs
index a29d90297e3..e81d8074e49 100644
--- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/ShellInProcess.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/ShellInProcess.cs
@@ -6,9 +6,11 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.VisualStudio.OperationProgress;
using Microsoft.VisualStudio.Razor;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.TextManager.Interop;
+using Microsoft.VisualStudio.Threading;
using Xunit;
namespace Microsoft.VisualStudio.Extensibility.Testing;
@@ -110,4 +112,11 @@ internal async Task CloseActiveDocumentWindowsAsync(CancellationToken cancellati
window.CloseFrame((uint)__FRAMECLOSE.FRAMECLOSE_NoSave);
}
}
+
+ public async Task WaitForOperationProgressAsync(CancellationToken cancellationToken)
+ {
+ var operationProgressStatus = await GetRequiredGlobalServiceAsync(cancellationToken);
+ var stageStatus = operationProgressStatus.GetStageStatus(CommonOperationProgressStageIds.Intellisense);
+ await stageStatus.WaitForCompletionAsync().WithCancellation(cancellationToken);
+ }
}
diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RazorCodeActionsTests.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RazorCodeActionsTests.cs
index 3a1dcab5399..40ad2ee4acf 100644
--- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RazorCodeActionsTests.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RazorCodeActionsTests.cs
@@ -20,8 +20,8 @@ public async Task RazorCodeActions_AddUsing()
// Open the file
await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
- await TestServices.Editor.SetTextAsync("", ControlledHangMitigatingCancellationToken);
- await TestServices.Editor.MoveCaretAsync(3, ControlledHangMitigatingCancellationToken);
+ var position = await TestServices.Editor.SetTextAsync("", ControlledHangMitigatingCancellationToken);
+ await TestServices.Editor.PlaceCaretAsync(position, ControlledHangMitigatingCancellationToken);
// Act
var codeActions = await TestServices.Editor.InvokeCodeActionListAsync(ControlledHangMitigatingCancellationToken);
diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs
index 3ef2044aa5b..87c927388b0 100644
--- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/RenameTests.cs
@@ -1,7 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
+using System.Threading;
using System.Threading.Tasks;
+using Microsoft.VisualStudio.Razor.IntegrationTests.Extensions;
+using Microsoft.VisualStudio.Razor.IntegrationTests.InProcess;
+using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Xunit;
using Xunit.Abstractions;
@@ -212,21 +217,23 @@ await TestServices.SolutionExplorer.AddFileAsync(RazorProjectConstants.BlazorPro
await TestServices.Editor.PlaceCaretAsync(position, ControlledHangMitigatingCancellationToken);
- await Task.Delay(500);
+ // For some reason, this particular rename exercise is particularly flaky so we have a few hail marys to recite
+ await TestServices.Shell.WaitForOperationProgressAsync(ControlledHangMitigatingCancellationToken);
+ await WaitForRoslynRenameReadyAsync(ControlledHangMitigatingCancellationToken);
// Act
await TestServices.Editor.InvokeRenameAsync(ControlledHangMitigatingCancellationToken);
+
+ // Even though we waited for the command to be ready and available, it can still be a bit slow to come up
+ await Task.Delay(500);
+
TestServices.Input.Send("ZooperDooper{ENTER}");
await TestServices.Editor.WaitForCurrentLineTextAsync("public class ZooperDooper : ComponentBase", ControlledHangMitigatingCancellationToken);
- // The rename operation updates the editor as the new name is being typed, so waiting for the line in the editor can trigger before the rename
- // actually occurs, and then moving tabs cancels it. So we have to wait a beat.
- await Task.Delay(500);
-
// Assert
await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, "MyPage.razor", ControlledHangMitigatingCancellationToken);
- await TestServices.Editor.VerifyTextContainsAsync("", ControlledHangMitigatingCancellationToken);
+ await TestServices.Editor.WaitForTextContainsAsync("", ControlledHangMitigatingCancellationToken);
}
[IdeFact]
@@ -351,4 +358,23 @@ public class MyComponent : ComponentBase
await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, "MyComponent.cs", ControlledHangMitigatingCancellationToken);
await TestServices.Editor.VerifyTextContainsAsync("public class ZooperDooper : ComponentBase", ControlledHangMitigatingCancellationToken);
}
+
+ private async Task WaitForRoslynRenameReadyAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await TestServices.Editor.GetActiveTextViewAsync(cancellationToken);
+ var buffer = view.GetBufferContainingCaret();
+
+ var commandArgs = new RenameCommandArgs(view, buffer);
+
+ // We don't have EA from this project, so we have to resort to reflection. Fortunately it's pretty simple
+ var roslynHandler = Type.GetType("Microsoft.CodeAnalysis.Editor.Implementation.InlineRename.AbstractRenameCommandHandler, Microsoft.CodeAnalysis.EditorFeatures");
+ var canRename = roslynHandler.GetMethod("CanRename", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
+
+ await Helper.RetryAsync(ct =>
+ {
+ return Task.FromResult((bool)canRename.Invoke(null, [commandArgs]));
+ }, TimeSpan.FromMilliseconds(100), cancellationToken);
+ }
}