diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/CompletionIntegrationTests.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/CompletionIntegrationTests.cs
index 2c38985a94a..495d10db1c4 100644
--- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/CompletionIntegrationTests.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/CompletionIntegrationTests.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
+using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Roslyn.Test.Utilities;
@@ -212,7 +213,8 @@ private void IncrementCount()
""",
search: "",
stringsToType: ["{ENTER}", "{ENTER}", "<", "s", "p", "a"],
- commitChar: '>');
+ commitChar: '>',
+ "span");
}
[IdeFact]
@@ -253,7 +255,7 @@ private void IncrementCount()
stringsToType: ["{ENTER}", "{ENTER}", "m", "y", "C", "u", "r"]);
}
- private async Task VerifyTypeAndCommitCompletionAsync(string input, string output, string search, string[] stringsToType, char? commitChar = null)
+ private async Task VerifyTypeAndCommitCompletionAsync(string input, string output, string search, string[] stringsToType, char? commitChar = null, string? expectedSelectedItemLabel = null)
{
await TestServices.SolutionExplorer.AddFileAsync(
RazorProjectConstants.BlazorProjectName,
@@ -270,7 +272,14 @@ await TestServices.SolutionExplorer.AddFileAsync(
TestServices.Input.Send(stringToType);
}
- await CommitCompletionAndVerifyAsync(output, commitChar);
+ if (expectedSelectedItemLabel is not null)
+ {
+ await CommitCompletionAndVerifyAsync(output, expectedSelectedItemLabel, commitChar);
+ }
+ else
+ {
+ await CommitCompletionAndVerifyAsync(output, commitChar);
+ }
}
[IdeFact]
@@ -457,4 +466,41 @@ private async Task CommitCompletionAndVerifyAsync(string expected, char? commitC
// tests allow for it as long as the content is correct
AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, text);
}
+
+ private async Task CommitCompletionAndVerifyAsync(string expected, string expectedSelectedItemLabel, char? commitChar = null)
+ {
+ // Actually open completion UI and wait for it have selected item we are interested in
+ var session = await TestServices.Editor.OpenCompletionSessionAndWaitForItemAsync(TimeSpan.FromSeconds(10), expectedSelectedItemLabel, HangMitigatingCancellationToken);
+
+ Assert.NotNull(session);
+ if (commitChar.HasValue)
+ {
+ // Commit using the specified commit character
+ session.Commit(commitChar.Value, HangMitigatingCancellationToken);
+
+ // session.Commit call above commits as if the commit character was typed,
+ // but doesn't actually insert the character into the buffer.
+ // So we still need to insert the character into the buffer ourselves.
+ TestServices.Input.Send(commitChar.Value.ToString());
+ }
+ else
+ {
+ Assert.True(session.CommitIfUnique(HangMitigatingCancellationToken));
+ }
+
+ var textView = await TestServices.Editor.GetActiveTextViewAsync(HangMitigatingCancellationToken);
+
+ var stopwatch = new Stopwatch();
+ string text;
+ while ((text = textView.TextBuffer.CurrentSnapshot.GetText()) != expected && stopwatch.ElapsedMilliseconds < 10000)
+ {
+ // Text might get updated *after* completion by something like auto-insert, so wait for the desired text
+ await Task.Delay(100);
+ }
+
+ // Snippets may have slight whitespace differences due to line endings. These
+ // tests allow for it as long as the content is correct
+ Assert.Equal(expected, text);
+ }
+
}
diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Completion.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Completion.cs
index 838e2eb79e8..10f9aef9634 100644
--- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Completion.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Completion.cs
@@ -55,4 +55,43 @@ public async Task DismissCompletionSessionsAsync(CancellationToken cancellationT
return session;
}
+
+ ///
+ /// Open completion pop-up window UI and wait for the specified item to be present selected
+ ///
+ ///
+ ///
+ ///
+ /// Completion session that has matching selected item, or null otherwise
+ public async Task OpenCompletionSessionAndWaitForItemAsync(TimeSpan timeOut, string selectedItemLabel, CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ // Returns completion session that might or might not be visible in the IDE
+ var session = await WaitForCompletionSessionAsync(timeOut, cancellationToken);
+
+ if (session is null)
+ {
+ return null;
+ }
+
+ var textView = await GetActiveTextViewAsync(cancellationToken);
+ var stopWatch = Stopwatch.StartNew();
+
+ // Actually open the completion pop-up window and force visible items to be computed or re-computed
+ session.OpenOrUpdate(new CompletionTrigger(CompletionTriggerReason.Insertion, textView.TextSnapshot), textView.Caret.Position.BufferPosition, cancellationToken);
+ while (session.GetComputedItems(cancellationToken).SelectedItem?.DisplayText != selectedItemLabel)
+ {
+ if (stopWatch.ElapsedMilliseconds >= timeOut.TotalMilliseconds)
+ {
+ return null;
+ }
+
+ await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
+
+ session.OpenOrUpdate(new CompletionTrigger(CompletionTriggerReason.Insertion, textView.TextSnapshot), textView.Caret.Position.BufferPosition, cancellationToken);
+ }
+
+ return session;
+ }
}