Add new feedback collection items (#6357)

* Add new feedback collection items
* Collect BinLogs for integration tests
* Log the Hive directory
* Ensure TextView has correct ContentType
* Ensure LSP Editor is Enabled
* Force Creation of experimental hive
This commit is contained in:
Ryan Brandenburg 2022-05-13 13:36:06 -07:00 коммит произвёл GitHub
Родитель 6fc30ca8b4
Коммит e716bf658b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
22 изменённых файлов: 514 добавлений и 324 удалений

Просмотреть файл

@ -197,6 +197,15 @@ stages:
name: Build name: Build
displayName: Build displayName: Build
condition: succeeded() condition: succeeded()
- task: PublishBuildArtifacts@1
displayName: Upload Build BinLog
condition: always()
continueOnError: true
inputs:
pathtoPublish: artifacts/log/$(_BuildConfig)/Build.binlog
artifactName: $(Agent.Os)_$(Agent.JobName) BuildBinLog
artifactType: Container
parallel: true
- script: eng\cibuild.cmd - script: eng\cibuild.cmd
-configuration $(_BuildConfig) -configuration $(_BuildConfig)
-msbuildEngine vs -msbuildEngine vs
@ -213,6 +222,15 @@ stages:
name: Build_Vsix name: Build_Vsix
displayName: Build and Deploy Vsix displayName: Build and Deploy Vsix
condition: succeeded() condition: succeeded()
- task: PublishBuildArtifacts@1
displayName: Upload Build VSIX BinLog
condition: always()
continueOnError: true
inputs:
pathtoPublish: artifacts/log/$(_BuildConfig)/Build.binlog
artifactName: $(Agent.Os)_$(Agent.JobName) BuildVSIXBinLog
artifactType: Container
parallel: true
- script: eng\CIBuild.cmd - script: eng\CIBuild.cmd
-configuration $(_BuildConfig) -configuration $(_BuildConfig)
-prepareMachine -prepareMachine
@ -222,23 +240,15 @@ stages:
name: Run_Tests name: Run_Tests
displayName: Run Unit and Integration tests displayName: Run Unit and Integration tests
condition: succeeded() condition: succeeded()
# - task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
# displayName: Update Integration Tests Data displayName: Upload Run tests BinLog
# condition: always() condition: always()
# continueOnError: true continueOnError: true
# inputs: inputs:
# pathtoPublish: artifacts/log/$(_BuildConfig)/Screenshots/ pathtoPublish: artifacts/log/$(_BuildConfig)/Build.binlog
# artifactName: $(Agent.Os)_$(Agent.JobName) IntegrationTestsData $(_BuildConfig) artifactName: $(Agent.Os)_$(Agent.JobName) RunTestsBinLog
# artifactType: Container artifactType: Container
# parallel: true parallel: true
# Run VSCode functional tests
# - powershell: |
# . ../../../../activate.ps1
# yarn test -- --ci --configuration $(_BuildConfig) --no-restore
# deactivate
# workingDirectory: $(Build.SourcesDirectory)/src/Razor/test/VSCode.FunctionalTest
# displayName: Run VSCode Tests
# condition: and(succeeded(), ne(variables['_BuildConfig'], 'Release')) # Temporary: Don't run on Release
- powershell: ./eng/scripts/FinishDumpCollectionForHangingBuilds.ps1 artifacts/log/$(_BuildConfig) - powershell: ./eng/scripts/FinishDumpCollectionForHangingBuilds.ps1 artifacts/log/$(_BuildConfig)
displayName: Finish background dump collection displayName: Finish background dump collection
continueOnError: true continueOnError: true
@ -252,14 +262,6 @@ stages:
workingDirectory: $(Build.SourcesDirectory)/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension workingDirectory: $(Build.SourcesDirectory)/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension
failOnStderr: true failOnStderr: true
condition: and(succeeded(), eq(variables['_BuildConfig'], 'Release')) condition: and(succeeded(), eq(variables['_BuildConfig'], 'Release'))
# - task: PublishTestResults@2
# displayName: Publish Integration Test Results
# condition: always()
# continueOnError: true
# inputs:
# testResultsFormat: 'VSTest'
# testResultsFiles: '*.trx'
# searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
displayName: Upload Test Results displayName: Upload Test Results
condition: always() condition: always()

Просмотреть файл

@ -15,6 +15,18 @@ steps:
inputs: inputs:
versionSpec: 10.x versionSpec: 10.x
# We explicitly pass the VS install directory in azure-pipelines-integration-dartlab.yml
- powershell: |
& "C:\\Test\\VisualStudio\\Common7\\IDE\\devenv.exe" /rootsuffix RoslynDev /updateConfiguration
if(Test-Path -Path $env:LocalAppData\Microsoft\VisualStudio\17.0*RoslynDev)
{
Write-Host "The hive 'RoslynDev' exists"
}
else{
throw "Failed to create hive"
}
displayName: Create and Verify hive
- script: eng\cibuild.cmd - script: eng\cibuild.cmd
-configuration ${{ parameters.configuration }} -configuration ${{ parameters.configuration }}
-msbuildEngine vs -msbuildEngine vs
@ -27,6 +39,16 @@ steps:
displayName: Build displayName: Build
condition: succeeded() condition: succeeded()
- task: PublishBuildArtifacts@1
displayName: Upload Build BinLog
condition: always()
continueOnError: true
inputs:
pathtoPublish: artifacts/log/${{ parameters.configuration }}/Build.binlog
artifactName: $(Agent.Os)_$(Agent.JobName) BuildBinLog
artifactType: Container
parallel: true
- script: eng\cibuild.cmd - script: eng\cibuild.cmd
-configuration ${{ parameters.configuration }} -configuration ${{ parameters.configuration }}
-msbuildEngine vs -msbuildEngine vs
@ -37,6 +59,16 @@ steps:
displayName: Build and Deploy VSIX displayName: Build and Deploy VSIX
condition: succeeded() condition: succeeded()
- task: PublishBuildArtifacts@1
displayName: Upload Build VSIX BinLog
condition: always()
continueOnError: true
inputs:
pathtoPublish: artifacts/log/${{ parameters.configuration }}/Build.binlog
artifactName: $(Agent.Os)_$(Agent.JobName) BuildVSIXBinLog
artifactType: Container
parallel: true
- script: eng\cibuild.cmd - script: eng\cibuild.cmd
-configuration ${{ parameters.configuration }} -configuration ${{ parameters.configuration }}
-msbuildEngine vs -msbuildEngine vs
@ -47,6 +79,16 @@ steps:
displayName: Run Integration Tests displayName: Run Integration Tests
condition: succeeded() condition: succeeded()
- task: PublishBuildArtifacts@1
displayName: Upload Run tests BinLog
condition: always()
continueOnError: true
inputs:
pathtoPublish: artifacts/log/${{ parameters.configuration }}/Build.binlog
artifactName: $(Agent.Os)_$(Agent.JobName) RunTestsBinLog
artifactType: Container
parallel: true
- task: PublishTestResults@2 - task: PublishTestResults@2
displayName: Publish xUnit Test Results displayName: Publish xUnit Test Results
inputs: inputs:

Просмотреть файл

@ -3,6 +3,7 @@
using System; using System;
using System.Composition; using System.Composition;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.Internal.VisualStudio.Shell.Interop; using Microsoft.Internal.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Editor.Razor; using Microsoft.VisualStudio.Editor.Razor;
@ -28,8 +29,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
private readonly Lazy<IVsUIShellOpenDocument> _vsUIShellOpenDocument; private readonly Lazy<IVsUIShellOpenDocument> _vsUIShellOpenDocument;
private readonly Lazy<bool> _useLegacyEditor; private readonly Lazy<bool> _useLegacyEditor;
private readonly RazorLogger _logger;
[ImportingConstructor] [ImportingConstructor]
public VisualStudioWindowsLSPEditorFeatureDetector(AggregateProjectCapabilityResolver projectCapabilityResolver) public VisualStudioWindowsLSPEditorFeatureDetector(AggregateProjectCapabilityResolver projectCapabilityResolver, RazorLogger logger)
{ {
_projectCapabilityResolver = projectCapabilityResolver; _projectCapabilityResolver = projectCapabilityResolver;
_vsUIShellOpenDocument = new Lazy<IVsUIShellOpenDocument>(() => _vsUIShellOpenDocument = new Lazy<IVsUIShellOpenDocument>(() =>
@ -55,6 +58,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
var useLegacyEditor = settingsManager.GetValueOrDefault<bool>(UseLegacyASPNETCoreEditorSetting); var useLegacyEditor = settingsManager.GetValueOrDefault<bool>(UseLegacyASPNETCoreEditorSetting);
return useLegacyEditor; return useLegacyEditor;
}); });
_logger = logger;
} }
[Obsolete("Test constructor")] [Obsolete("Test constructor")]
@ -66,13 +71,16 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
public override bool IsLSPEditorAvailable(string documentMoniker, object hierarchy) public override bool IsLSPEditorAvailable(string documentMoniker, object hierarchy)
{ {
_logger.LogVerbose("Checking if LSP Editor is available");
if (documentMoniker is null) if (documentMoniker is null)
{ {
_logger.LogWarning($"LSP Editor not available because {nameof(documentMoniker)} is null");
return false; return false;
} }
if (!IsLSPEditorAvailable()) if (!IsLSPEditorAvailable())
{ {
_logger.LogVerbose($"Using Legacy editor because the option was set to true");
return false; return false;
} }
@ -80,6 +88,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
if (!ProjectSupportsLSPEditor(documentMoniker, ivsHierarchy)) if (!ProjectSupportsLSPEditor(documentMoniker, ivsHierarchy))
{ {
// Current project hierarchy doesn't support the LSP Razor editor // Current project hierarchy doesn't support the LSP Razor editor
_logger.LogVerbose($"Using Legacy editor because the current project does not support LSP Editor");
return false; return false;
} }
@ -105,6 +114,15 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
hierarchy = uiHierarchy; hierarchy = uiHierarchy;
if (!ErrorHandler.Succeeded(hr) || hierarchy is null) if (!ErrorHandler.Succeeded(hr) || hierarchy is null)
{ {
if (!ErrorHandler.Succeeded(hr))
{
_logger.LogWarning($"Project does not support LSP Editor beccause {nameof(_vsUIShellOpenDocument.Value.IsDocumentInAProject)} failed with exit code {hr}");
}
else if (hierarchy is null)
{
_logger.LogWarning($"Project does not support LSP Editor because {nameof(hierarchy)} is null");
}
return false; return false;
} }
} }
@ -114,6 +132,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
// those types of scenarios for the new .NET Core Razor editor. // those types of scenarios for the new .NET Core Razor editor.
if (_projectCapabilityResolver.HasCapability(documentMoniker, hierarchy, LegacyRazorEditorCapability)) if (_projectCapabilityResolver.HasCapability(documentMoniker, hierarchy, LegacyRazorEditorCapability))
{ {
_logger.LogVerbose($"Project does not support LSP Editor because '{documentMoniker}' has Capability {LegacyRazorEditorCapability}");
// CPS project that requires the legacy editor // CPS project that requires the legacy editor
return false; return false;
} }
@ -124,6 +143,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
return true; return true;
} }
_logger.LogVerbose($"Project {documentMoniker} does not support LSP Editor because it does not have the {DotNetCoreCSharpCapability} capability.");
// Not a C# .NET Core project. This typically happens for legacy Razor scenarios // Not a C# .NET Core project. This typically happens for legacy Razor scenarios
return false; return false;
} }

Просмотреть файл

@ -7,10 +7,9 @@
In general this project should not be deployed (F5'd) by itself as it only includes In general this project should not be deployed (F5'd) by itself as it only includes
extra dependencies + codebases that may not be present in public VS installs. extra dependencies + codebases that may not be present in public VS installs.
--> -->
<TargetFramework>net472</TargetFramework> <TargetFramework>net472</TargetFramework>
<!-- Use the RoslynDev Experimental instance so we can mingle with local builds of Roslyn -->
<VSSDKTargetPlatformRegRootSuffix>RoslynDev</VSSDKTargetPlatformRegRootSuffix> <VSSDKTargetPlatformRegRootSuffix>RoslynDev</VSSDKTargetPlatformRegRootSuffix>
<IsShipping>false</IsShipping> <IsShipping>false</IsShipping>

Просмотреть файл

@ -2,7 +2,6 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net472</TargetFramework> <TargetFramework>net472</TargetFramework>
<!-- Use the RoslynDev Experimental instance so we can mingle with local builds of Roslyn -->
<VSSDKTargetPlatformRegRootSuffix>RoslynDev</VSSDKTargetPlatformRegRootSuffix> <VSSDKTargetPlatformRegRootSuffix>RoslynDev</VSSDKTargetPlatformRegRootSuffix>
<!-- Required to run the project localy --> <!-- Required to run the project localy -->

Просмотреть файл

@ -5,10 +5,9 @@
It ensures that a single F5 command will build and deploy the independent MS.VS.RazorExtension vsix and MS.VS.RazorExtension.Dependencies vsix. It ensures that a single F5 command will build and deploy the independent MS.VS.RazorExtension vsix and MS.VS.RazorExtension.Dependencies vsix.
We rely on launch settings to run devenv with the appropriate hive that the vsixes have been deployed to. We rely on launch settings to run devenv with the appropriate hive that the vsixes have been deployed to.
--> -->
<TargetFramework>net472</TargetFramework> <TargetFramework>net472</TargetFramework>
<!-- Use the RoslynDev Experimental instance so we can mingle with local builds of Roslyn -->
<VSSDKTargetPlatformRegRootSuffix>RoslynDev</VSSDKTargetPlatformRegRootSuffix> <VSSDKTargetPlatformRegRootSuffix>RoslynDev</VSSDKTargetPlatformRegRootSuffix>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

Просмотреть файл

@ -3,7 +3,9 @@
#nullable disable #nullable disable
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Shell.Interop;
using Moq;
using Xunit; using Xunit;
namespace Microsoft.VisualStudio.LanguageServices.Razor namespace Microsoft.VisualStudio.LanguageServices.Razor
@ -14,7 +16,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
public void IsLSPEditorAvailable_ProjectSupported_ReturnsTrue() public void IsLSPEditorAvailable_ProjectSupported_ReturnsTrue()
{ {
// Arrange // Arrange
var featureDetector = new TestLSPEditorFeatureDetector() var logger = GetRazorLogger();
var featureDetector = new TestLSPEditorFeatureDetector(logger)
{ {
ProjectSupportsLSPEditorValue = true, ProjectSupportsLSPEditorValue = true,
}; };
@ -30,7 +33,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
public void IsLSPEditorAvailable_LegacyEditorEnabled_ReturnsFalse() public void IsLSPEditorAvailable_LegacyEditorEnabled_ReturnsFalse()
{ {
// Arrange // Arrange
var featureDetector = new TestLSPEditorFeatureDetector() var logger = GetRazorLogger();
var featureDetector = new TestLSPEditorFeatureDetector(logger)
{ {
UseLegacyEditor = true, UseLegacyEditor = true,
ProjectSupportsLSPEditorValue = true, ProjectSupportsLSPEditorValue = true,
@ -47,7 +51,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
public void IsLSPEditorAvailable_IsVSRemoteClient_ReturnsTrue() public void IsLSPEditorAvailable_IsVSRemoteClient_ReturnsTrue()
{ {
// Arrange // Arrange
var featureDetector = new TestLSPEditorFeatureDetector() var logger = GetRazorLogger();
var featureDetector = new TestLSPEditorFeatureDetector(logger)
{ {
IsVSRemoteClientValue = true, IsVSRemoteClientValue = true,
ProjectSupportsLSPEditorValue = true, ProjectSupportsLSPEditorValue = true,
@ -64,7 +69,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
public void IsLSPEditorAvailable_UnsupportedProject_ReturnsFalse() public void IsLSPEditorAvailable_UnsupportedProject_ReturnsFalse()
{ {
// Arrange // Arrange
var featureDetector = new TestLSPEditorFeatureDetector() var logger = GetRazorLogger();
var featureDetector = new TestLSPEditorFeatureDetector(logger)
{ {
ProjectSupportsLSPEditorValue = false, ProjectSupportsLSPEditorValue = false,
}; };
@ -80,7 +86,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
public void IsRemoteClient_VSRemoteClient_ReturnsTrue() public void IsRemoteClient_VSRemoteClient_ReturnsTrue()
{ {
// Arrange // Arrange
var featureDetector = new TestLSPEditorFeatureDetector() var logger = GetRazorLogger();
var featureDetector = new TestLSPEditorFeatureDetector(logger)
{ {
IsVSRemoteClientValue = true, IsVSRemoteClientValue = true,
}; };
@ -96,7 +103,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
public void IsRemoteClient_LiveShareGuest_ReturnsTrue() public void IsRemoteClient_LiveShareGuest_ReturnsTrue()
{ {
// Arrange // Arrange
var featureDetector = new TestLSPEditorFeatureDetector() var logger = GetRazorLogger();
var featureDetector = new TestLSPEditorFeatureDetector(logger)
{ {
IsLiveShareGuestValue = true, IsLiveShareGuestValue = true,
}; };
@ -112,7 +120,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
public void IsRemoteClient_UnknownEnvironment_ReturnsFalse() public void IsRemoteClient_UnknownEnvironment_ReturnsFalse()
{ {
// Arrange // Arrange
var featureDetector = new TestLSPEditorFeatureDetector(); var logger = GetRazorLogger();
var featureDetector = new TestLSPEditorFeatureDetector(logger);
// Act // Act
var result = featureDetector.IsRemoteClient(); var result = featureDetector.IsRemoteClient();
@ -121,9 +130,21 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
Assert.False(result); Assert.False(result);
} }
private static RazorLogger GetRazorLogger()
{
var mock = new Mock<RazorLogger>(MockBehavior.Strict);
mock.Setup(l => l.LogVerbose(It.IsAny<string>()));
return mock.Object;
}
#pragma warning disable CS0618 // Type or member is obsolete (Test constructor) #pragma warning disable CS0618 // Type or member is obsolete (Test constructor)
private class TestLSPEditorFeatureDetector : VisualStudioWindowsLSPEditorFeatureDetector private class TestLSPEditorFeatureDetector : VisualStudioWindowsLSPEditorFeatureDetector
{ {
public TestLSPEditorFeatureDetector(RazorLogger logger) : base(projectCapabilityResolver: null, logger)
{
}
public bool UseLegacyEditor { get; set; } public bool UseLegacyEditor { get; set; }
public bool IsLiveShareGuestValue { get; set; } public bool IsLiveShareGuestValue { get; set; }

Просмотреть файл

@ -38,9 +38,9 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
RazorDebug.AssertNotNull(_projectTemplate); RazorDebug.AssertNotNull(_projectTemplate);
RazorDebug.AssertNotNull(_projectName); RazorDebug.AssertNotNull(_projectName);
await TestServices.SolutionExplorer.CreateSolutionAsync(_solutionName, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.CreateSolutionAsync(_solutionName, ControlledHangMitigatingCancellationToken);
await TestServices.SolutionExplorer.AddProjectAsync(_projectName, _projectTemplate, LanguageName, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.AddProjectAsync(_projectName, _projectTemplate, LanguageName, ControlledHangMitigatingCancellationToken);
await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(ProjectName, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(ProjectName, ControlledHangMitigatingCancellationToken);
} }
} }
} }

Просмотреть файл

@ -2,6 +2,7 @@
// Licensed under the MIT license. See License.txt in the project root for license information. // Licensed under the MIT license. See License.txt in the project root for license information.
using System; using System;
using System.Threading;
using Microsoft.VisualStudio.Extensibility.Testing; using Microsoft.VisualStudio.Extensibility.Testing;
using Xunit; using Xunit;
using Xunit.Sdk; using Xunit.Sdk;
@ -30,6 +31,11 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
protected const string ProjectName = "TestProj"; protected const string ProjectName = "TestProj";
protected const string SolutionName = "TestSolution"; protected const string SolutionName = "TestSolution";
private readonly static TimeSpan s_shortHangMitigatingTimeout = new(hours: 0, minutes: 1, seconds: 0);
private readonly CancellationTokenSource _shortHangMitigatingCancellationTokenSource = new(s_shortHangMitigatingTimeout);
protected CancellationToken ControlledHangMitigatingCancellationToken => HangMitigatingCancellationToken;
public override async Task InitializeAsync() public override async Task InitializeAsync()
{ {
await base.InitializeAsync(); await base.InitializeAsync();

Просмотреть файл

@ -2,204 +2,76 @@
// Licensed under the MIT license. See License.txt in the project root for license information. // Licensed under the MIT license. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Internal.VisualStudio.Shell.Embeddable.Feedback; using Microsoft.Internal.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Razor.IntegrationTests.InProcess; using Microsoft.VisualStudio.Razor.IntegrationTests.InProcess;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Xunit.Harness; using Xunit.Harness;
namespace Microsoft.VisualStudio.Razor.IntegrationTests namespace Microsoft.VisualStudio.Razor.IntegrationTests
{ {
public abstract class AbstractRazorEditorTest : AbstractEditorTest public abstract class AbstractRazorEditorTest : AbstractEditorTest
{ {
internal const string BlazorProjectName = "BlazorProject"; private const string LegacyRazorEditorFeatureFlag = "Razor.LSP.LegacyEditor";
private const string UseLegacyASPNETCoreEditorSetting = "TextEditor.HTML.Specific.UseLegacyASPNETCoreRazorEditor";
private static readonly string s_pagesDir = Path.Combine("Pages");
private static readonly string s_sharedDir = Path.Combine("Shared");
internal static readonly string FetchDataRazorFile = Path.Combine(s_pagesDir, "FetchData.razor");
internal static readonly string CounterRazorFile = Path.Combine(s_pagesDir, "Counter.razor");
internal static readonly string IndexRazorFile = Path.Combine(s_pagesDir, "Index.razor");
internal static readonly string ModifiedIndexRazorFile = Path.Combine(s_pagesDir, "ModifiedIndex.razor");
internal static readonly string SemanticTokensFile = Path.Combine(s_pagesDir, "SemanticTokens.razor");
internal static readonly string MainLayoutFile = Path.Combine(s_sharedDir, "MainLayout.razor");
internal static readonly string ErrorCshtmlFile = Path.Combine(s_pagesDir, "Error.cshtml");
internal static readonly string ImportsRazorFile = "_Imports.razor";
internal static readonly string IndexPageContent = @"@page ""/""
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title=""How is Blazor working for you?"" />";
internal static readonly string MainLayoutContent = @"@inherits LayoutComponentBase
<PageTitle>BlazorApp</PageTitle>
<div class=""page"">
<div class=""sidebar"">
<NavMenu />
</div>
<main>
<div class=""top-row px-4"">
<a href=""https://docs.microsoft.com/aspnet/"" target=""_blank"">About</a>
</div>
<article class=""content px-4"">
@Body
</article>
</main>
</div>
";
private const string RazorComponentElementClassification = "RazorComponentElement"; private const string RazorComponentElementClassification = "RazorComponentElement";
private const string RazorOutputLogId = "RazorOutputLog";
private const string LogHubLogId = "RazorLogHub";
protected override string LanguageName => LanguageNames.Razor; protected override string LanguageName => LanguageNames.Razor;
private static bool s_customLoggersAdded = false;
public override async Task InitializeAsync() public override async Task InitializeAsync()
{ {
await base.InitializeAsync(); await base.InitializeAsync();
// Add custom logs on failure if they haven't already been. VisualStudioLogging.AddCustomLoggers();
if (!s_customLoggersAdded)
{
DataCollectionService.RegisterCustomLogger(RazorOutputPaneLogger, RazorOutputLogId, "log");
DataCollectionService.RegisterCustomLogger(RazorLogHubLogger, LogHubLogId, "zip");
s_customLoggersAdded = true; await TestServices.SolutionExplorer.CreateSolutionAsync("BlazorSolution", ControlledHangMitigatingCancellationToken);
} await TestServices.SolutionExplorer.AddProjectAsync("BlazorProject", WellKnownProjectTemplates.BlazorProject, groupId: WellKnownProjectTemplates.GroupIdentifiers.Server, templateId: null, LanguageName, ControlledHangMitigatingCancellationToken);
await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(ControlledHangMitigatingCancellationToken);
await TestServices.Workspace.WaitForProjectSystemAsync(ControlledHangMitigatingCancellationToken);
await TestServices.SolutionExplorer.CreateSolutionAsync("BlazorSolution", HangMitigatingCancellationToken); await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.LanguageServer, ControlledHangMitigatingCancellationToken);
await TestServices.SolutionExplorer.AddProjectAsync("BlazorProject", WellKnownProjectTemplates.BlazorProject, groupId: WellKnownProjectTemplates.GroupIdentifiers.Server, templateId: null, LanguageName, HangMitigatingCancellationToken);
await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken);
await TestServices.Workspace.WaitForProjectSystemAsync(HangMitigatingCancellationToken);
await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.LanguageServer, HangMitigatingCancellationToken);
// We open the Index.razor file, and wait for 3 RazorComponentElement's to be classified, as that // We open the Index.razor file, and wait for 3 RazorComponentElement's to be classified, as that
// way we know the LSP server is up, running, and has processed both local and library-sourced Components // way we know the LSP server is up, running, and has processed both local and library-sourced Components
await TestServices.SolutionExplorer.AddFileAsync(BlazorProjectName, ModifiedIndexRazorFile, IndexPageContent, open: true, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.AddFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.ModifiedIndexRazorFile, RazorProjectConstants.IndexPageContent, open: true, ControlledHangMitigatingCancellationToken);
// Razor extension doesn't launch until a razor file is opened, so wait for it to equalize // Razor extension doesn't launch until a razor file is opened, so wait for it to equalize
await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.LanguageServer, HangMitigatingCancellationToken); await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.LanguageServer, ControlledHangMitigatingCancellationToken);
await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.Workspace, HangMitigatingCancellationToken); await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.Workspace, ControlledHangMitigatingCancellationToken);
await TestServices.Workspace.WaitForProjectSystemAsync(HangMitigatingCancellationToken); await TestServices.Workspace.WaitForProjectSystemAsync(ControlledHangMitigatingCancellationToken);
await EnsureExtensionInstalledAsync(HangMitigatingCancellationToken); EnsureLSPEditorEnabled();
await EnsureTextViewRolesAsync(ControlledHangMitigatingCancellationToken);
await EnsureExtensionInstalledAsync(ControlledHangMitigatingCancellationToken);
try await TestServices.Editor.WaitForClassificationAsync(ControlledHangMitigatingCancellationToken, expectedClassification: RazorComponentElementClassification, count: 3);
{
await TestServices.Editor.WaitForClassificationAsync(HangMitigatingCancellationToken, expectedClassification: RazorComponentElementClassification, count: 3);
}
catch (OperationCanceledException)
{
// DataCollectionService does not fire in the case that errors or exceptions are thrown during Initialization.
// Let's capture some of the things we care about most manually.
var logHubFilePath = CreateLogFileName(LogHubLogId, "zip");
RazorLogHubLogger(logHubFilePath);
var outputPaneFilePath = CreateLogFileName(RazorOutputLogId, "log");
RazorOutputPaneLogger(outputPaneFilePath);
throw;
}
// Close the file we opened, just in case, so the test can start with a clean slate // Close the file we opened, just in case, so the test can start with a clean slate
await TestServices.Editor.CloseDocumentWindowAsync(HangMitigatingCancellationToken); await TestServices.Editor.CloseDocumentWindowAsync(ControlledHangMitigatingCancellationToken);
}
static void RazorLogHubLogger(string filePath) private static void EnsureLSPEditorEnabled()
{ {
var componentModel = GlobalServiceProvider.ServiceProvider.GetService<SComponentModel, IComponentModel>(); var settingsManager = (ISettingsManager)ServiceProvider.GlobalProvider.GetService(typeof(SVsSettingsPersistenceManager));
if (componentModel is null) Assumes.Present(settingsManager);
{ var featureFlags = (IVsFeatureFlags)AsyncPackage.GetGlobalService(typeof(SVsFeatureFlags));
// Unable to get componentModel var legacyEditorFeatureFlagEnabled = featureFlags.IsFeatureEnabled(LegacyRazorEditorFeatureFlag, defaultValue: false);
return; Assert.AreEqual(false, legacyEditorFeatureFlagEnabled, "Expected Legacy Editor Feature Flag to be disabled, but it was enabled");
}
var feedbackFileProviders = componentModel.GetExtensions<IFeedbackDiagnosticFileProvider>(); var useLegacyEditor = settingsManager.GetValueOrDefault<bool>(UseLegacyASPNETCoreEditorSetting);
Assert.AreEqual(false, useLegacyEditor, "Expected the Legacy Razor Editor to be disabled, but it was enabled");
}
// Collect all the file names first since they can kick of file creation events that might need extra time to resolve. private async Task EnsureTextViewRolesAsync(CancellationToken cancellationToken)
var files = new List<string>(); {
foreach (var feedbackFileProvider in feedbackFileProviders) var textView = await TestServices.Editor.GetActiveTextViewAsync(cancellationToken);
{ var contentType = textView.TextSnapshot.ContentType;
files.AddRange(feedbackFileProvider.GetFiles()); Assert.AreEqual("Razor", contentType.TypeName);
}
_ = CollectLogHubAsync(files, filePath);
}
static async Task CollectLogHubAsync(IEnumerable<string> files, string destination)
{
// What's important in this weird threading stuff is ensuring we vacate the thread RazorLogHubLogger was called on
// because if we don't it ends up blocking the thread that creates the zip file we need.
await ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
foreach (var file in files)
{
var name = Path.GetFileName(file);
// Only caputre loghub
if (name.Contains("LogHub") && Path.GetExtension(file) == ".zip")
{
await Task.Run(() =>
{
WaitForFileExistsAsync(file);
if (File.Exists(file))
{
File.Copy(file, destination);
}
});
}
}
});
}
static void RazorOutputPaneLogger(string filePath)
{
// JoinableTaskFactory.Run isn't an option because we might be disposing already.
// Don't use ThreadHelper.JoinableTaskFactory in test methods, but it's correct here.
#pragma warning disable VSTHRD103 // Call async methods when in an async method
ThreadHelper.JoinableTaskFactory.Run(async () =>
#pragma warning restore VSTHRD103 // Call async methods when in an async method
{
try
{
var testServices = await Extensibility.Testing.TestServices.CreateAsync(ThreadHelper.JoinableTaskFactory);
var paneContent = await testServices.Output.GetRazorOutputPaneContentAsync(CancellationToken.None);
File.WriteAllText(filePath, paneContent);
}
catch (Exception)
{
// Eat any errors so we don't block further collection
}
});
}
static void WaitForFileExistsAsync(string file)
{
const int MaxRetries = 50;
var retries = 0;
while (!File.Exists(file) && retries < MaxRetries)
{
retries++;
// Free your thread
Thread.Yield();
// Wait a bit
Thread.Sleep(100);
}
}
} }
private async Task EnsureExtensionInstalledAsync(CancellationToken cancellationToken) private async Task EnsureExtensionInstalledAsync(CancellationToken cancellationToken)
@ -249,21 +121,5 @@ Welcome to your new app.
} }
} }
} }
// We use reflection to get at a couple of the internals of DataCollectionService so that we use the propper LogDirectory.
private static string CreateLogFileName(string logId, string extension)
{
var dataCollectionServiceType = typeof(DataCollectionService);
var getLogDirectoryMethod = dataCollectionServiceType.GetMethod("GetLogDirectory", BindingFlags.Static | BindingFlags.NonPublic);
var logDirectory = getLogDirectoryMethod.Invoke(obj: null, new object[] { });
var createLogFileNameMethod = dataCollectionServiceType.GetMethod("CreateLogFileName", BindingFlags.Static | BindingFlags.NonPublic);
var timestamp = DateTimeOffset.UtcNow;
var testName = "TestInitialization";
var errorId = "InitializationError";
var @params = new object[] { logDirectory, timestamp, testName, errorId, logId, extension };
var logFileName = (string)createLogFileNameMethod.Invoke(obj: null, @params);
return logFileName;
}
} }
} }

Просмотреть файл

@ -12,23 +12,23 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task SetBreakpoint_FirstCharacter_SpanAdjusts() public async Task SetBreakpoint_FirstCharacter_SpanAdjusts()
{ {
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
// Wait for classifications to indicate Razor LSP is up and running // Wait for classifications to indicate Razor LSP is up and running
await TestServices.Editor.WaitForClassificationAsync(HangMitigatingCancellationToken); await TestServices.Editor.WaitForClassificationAsync(ControlledHangMitigatingCancellationToken);
await TestServices.Editor.SetTextAsync("<p>@{ var abc = 123; }</p>", HangMitigatingCancellationToken); await TestServices.Editor.SetTextAsync("<p>@{ var abc = 123; }</p>", ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Debugger.SetBreakpointAsync(CounterRazorFile, line: 1, character: 1, HangMitigatingCancellationToken); await TestServices.Debugger.SetBreakpointAsync(RazorProjectConstants.CounterRazorFile, line: 1, character: 1, ControlledHangMitigatingCancellationToken);
// Assert // Assert
await TestServices.Debugger.VerifyBreakpointAsync(CounterRazorFile, line: 1, character: 7, HangMitigatingCancellationToken); await TestServices.Debugger.VerifyBreakpointAsync(RazorProjectConstants.CounterRazorFile, line: 1, character: 7, ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
public async Task SetBreakpoint_FirstCharacter_InvalidLine() public async Task SetBreakpoint_FirstCharacter_InvalidLine()
{ {
var version = await TestServices.Shell.GetVersionAsync(HangMitigatingCancellationToken); var version = await TestServices.Shell.GetVersionAsync(ControlledHangMitigatingCancellationToken);
if (version < new System.Version(17, 3, 32412, 127)) if (version < new System.Version(17, 3, 32412, 127))
{ {
// Functionality under test was added in v17.3-Preview1 (17.3.32412.127) so this test will // Functionality under test was added in v17.3-Preview1 (17.3.32412.127) so this test will
@ -39,16 +39,16 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
} }
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
// Wait for classifications to indicate Razor LSP is up and running // Wait for classifications to indicate Razor LSP is up and running
await TestServices.Editor.WaitForClassificationAsync(HangMitigatingCancellationToken); await TestServices.Editor.WaitForClassificationAsync(ControlledHangMitigatingCancellationToken);
await TestServices.Editor.SetTextAsync(@"<p>@{ await TestServices.Editor.SetTextAsync(@"<p>@{
var abc = 123; var abc = 123;
}</p>", HangMitigatingCancellationToken); }</p>", ControlledHangMitigatingCancellationToken);
// Act // Act
var result = await TestServices.Debugger.SetBreakpointAsync(CounterRazorFile, line: 1, character: 1, HangMitigatingCancellationToken); var result = await TestServices.Debugger.SetBreakpointAsync(RazorProjectConstants.CounterRazorFile, line: 1, character: 1, ControlledHangMitigatingCancellationToken);
// Assert // Assert
Assert.False(result); Assert.False(result);
@ -58,19 +58,19 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task SetBreakpoint_FirstCharacter_ValidLine() public async Task SetBreakpoint_FirstCharacter_ValidLine()
{ {
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
// Wait for classifications to indicate Razor LSP is up and running // Wait for classifications to indicate Razor LSP is up and running
await TestServices.Editor.WaitForClassificationAsync(HangMitigatingCancellationToken); await TestServices.Editor.WaitForClassificationAsync(ControlledHangMitigatingCancellationToken);
await TestServices.Editor.SetTextAsync(@"<p>@{ await TestServices.Editor.SetTextAsync(@"<p>@{
var abc = 123; var abc = 123;
}</p>", HangMitigatingCancellationToken); }</p>", ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Debugger.SetBreakpointAsync(CounterRazorFile, line: 2, character: 1, HangMitigatingCancellationToken); await TestServices.Debugger.SetBreakpointAsync(RazorProjectConstants.CounterRazorFile, line: 2, character: 1, ControlledHangMitigatingCancellationToken);
// Assert // Assert
await TestServices.Debugger.VerifyBreakpointAsync(CounterRazorFile, line: 2, character: 4, HangMitigatingCancellationToken); await TestServices.Debugger.VerifyBreakpointAsync(RazorProjectConstants.CounterRazorFile, line: 2, character: 4, ControlledHangMitigatingCancellationToken);
} }
} }
} }

Просмотреть файл

@ -22,7 +22,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
private async Task AssertFoldableBlocksAsync(params string[] blockTexts) private async Task AssertFoldableBlocksAsync(params string[] blockTexts)
{ {
var textView = await TestServices.Editor.GetActiveTextViewAsync(HangMitigatingCancellationToken); var textView = await TestServices.Editor.GetActiveTextViewAsync(ControlledHangMitigatingCancellationToken);
var text = textView.TextBuffer.CurrentSnapshot.GetText(); var text = textView.TextBuffer.CurrentSnapshot.GetText();
var foldableSpans = blockTexts.Select(blockText => var foldableSpans = blockTexts.Select(blockText =>
@ -43,8 +43,8 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
var outlines = new ICollapsible[0]; var outlines = new ICollapsible[0];
while (tries++ < MaxTries) while (tries++ < MaxTries)
{ {
textView = await TestServices.Editor.GetActiveTextViewAsync(HangMitigatingCancellationToken); textView = await TestServices.Editor.GetActiveTextViewAsync(ControlledHangMitigatingCancellationToken);
outlines = await TestServices.Editor.GetOutlineRegionsAsync(textView, HangMitigatingCancellationToken); outlines = await TestServices.Editor.GetOutlineRegionsAsync(textView, ControlledHangMitigatingCancellationToken);
(missingLines, var extraLines) = GetOutlineDiff(outlines, foldableSpans, textView); (missingLines, var extraLines) = GetOutlineDiff(outlines, foldableSpans, textView);
if (missingLines.Length == 0) if (missingLines.Length == 0)
@ -122,7 +122,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task CodeFolding_CodeBlock() public async Task CodeFolding_CodeBlock()
{ {
await TestServices.SolutionExplorer.AddFileAsync( await TestServices.SolutionExplorer.AddFileAsync(
BlazorProjectName, RazorProjectConstants.BlazorProjectName,
"Test.razor", "Test.razor",
@" @"
@page ""/Test"" @page ""/Test""
@ -140,7 +140,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
} }
}", }",
open: true, open: true,
HangMitigatingCancellationToken); ControlledHangMitigatingCancellationToken);
await AssertFoldableBlocksAsync( await AssertFoldableBlocksAsync(
@"@code { @"@code {
@ -161,7 +161,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task CodeFolding_IfBlock() public async Task CodeFolding_IfBlock()
{ {
await TestServices.SolutionExplorer.AddFileAsync( await TestServices.SolutionExplorer.AddFileAsync(
BlazorProjectName, RazorProjectConstants.BlazorProjectName,
"Test.razor", "Test.razor",
@" @"
@page ""/Test"" @page ""/Test""
@ -183,7 +183,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
} }
", ",
open: true, open: true,
HangMitigatingCancellationToken); ControlledHangMitigatingCancellationToken);
await AssertFoldableBlocksAsync( await AssertFoldableBlocksAsync(
@"@if(true) @"@if(true)
@ -206,7 +206,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task CodeFolding_ForEach() public async Task CodeFolding_ForEach()
{ {
await TestServices.SolutionExplorer.AddFileAsync( await TestServices.SolutionExplorer.AddFileAsync(
BlazorProjectName, RazorProjectConstants.BlazorProjectName,
"Test.razor", "Test.razor",
@" @"
@page ""/Test"" @page ""/Test""
@ -225,7 +225,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
} }
", ",
open: true, open: true,
HangMitigatingCancellationToken); ControlledHangMitigatingCancellationToken);
await AssertFoldableBlocksAsync( await AssertFoldableBlocksAsync(
@"@foreach (var s in GetStuff()) @"@foreach (var s in GetStuff())
@ -241,7 +241,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task CodeFolding_CodeBlock_Region() public async Task CodeFolding_CodeBlock_Region()
{ {
await TestServices.SolutionExplorer.AddFileAsync( await TestServices.SolutionExplorer.AddFileAsync(
BlazorProjectName, RazorProjectConstants.BlazorProjectName,
"Test.razor", "Test.razor",
@" @"
@page ""/Test"" @page ""/Test""
@ -258,7 +258,7 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
} }
", ",
open: true, open: true,
HangMitigatingCancellationToken); ControlledHangMitigatingCancellationToken);
await AssertFoldableBlocksAsync( await AssertFoldableBlocksAsync(
@"#region Methods @"#region Methods

Просмотреть файл

@ -0,0 +1,192 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Internal.VisualStudio.Shell.Embeddable.Feedback;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Shell;
using Xunit.Harness;
namespace Microsoft.VisualStudio.Razor.IntegrationTests
{
internal static class VisualStudioLogging
{
private static bool s_customLoggersAdded = false;
public const string RazorOutputLogId = "RazorOutputLog";
public const string LogHubLogId = "RazorLogHub";
public const string ServiceHubLogId = "ServiceHubLog";
public const string ComponentModelCacheId = "ComponentModelCache";
public const string ExtensionDirectoryId = "ExtensionDirectory";
private static readonly object s_lockObj = new();
public static void AddCustomLoggers()
{
lock (s_lockObj)
{
// Add custom logs on failure if they haven't already been.
if (!s_customLoggersAdded)
{
DataCollectionService.RegisterCustomLogger(RazorOutputPaneLogger, RazorOutputLogId, "log");
DataCollectionService.RegisterCustomLogger(RazorLogHubLogger, LogHubLogId, "zip");
DataCollectionService.RegisterCustomLogger(RazorServiceHubLogger, ServiceHubLogId, "zip");
DataCollectionService.RegisterCustomLogger(RazorComponentModelCacheLogger, ComponentModelCacheId, "zip");
DataCollectionService.RegisterCustomLogger(RazorExtensionExplorerLogger, ExtensionDirectoryId, "txt");
s_customLoggersAdded = true;
}
}
}
private static void RazorLogHubLogger(string filePath)
{
FeedbackLoggerInternal(filePath, "LogHub");
}
private static void RazorServiceHubLogger(string filePath)
{
FeedbackLoggerInternal(filePath, "ServiceHubLogs");
}
private static void RazorComponentModelCacheLogger(string filePath)
{
FeedbackLoggerInternal(filePath, "ComponentModelCache");
}
private static void FeedbackLoggerInternal(string filePath, string expectedFilePart)
{
var componentModel = GlobalServiceProvider.ServiceProvider.GetService<SComponentModel, IComponentModel>();
if (componentModel is null)
{
// Unable to get componentModel
return;
}
var feedbackFileProviders = componentModel.GetExtensions<IFeedbackDiagnosticFileProvider>();
// Collect all the file names first since they can kick of file creation events that might need extra time to resolve.
var files = new List<string>();
foreach (var feedbackFileProvider in feedbackFileProviders)
{
files.AddRange(feedbackFileProvider.GetFiles());
}
_ = CollectFeedbackItemsAsync(files, filePath, expectedFilePart);
}
private static void RazorExtensionExplorerLogger(string filePath)
{
var hiveDirectories = GetHiveDirectories();
var fileBuilder = new StringBuilder();
if (hiveDirectories.Count() != 1)
{
fileBuilder.Append("Expected 1 hive but found ");
fileBuilder.AppendLine(hiveDirectories.Count().ToString());
}
foreach (var hiveDirectory in hiveDirectories)
{
var extensionsDir = Path.Combine(hiveDirectory, "Extensions");
var compatListFile = Path.Combine(extensionsDir, "CompatibilityList.xml");
if (File.Exists(compatListFile))
{
var compatListContent = File.ReadAllText(compatListFile);
fileBuilder.AppendLine("CompatListContents:");
fileBuilder.AppendLine(compatListContent);
}
else
{
fileBuilder.AppendLine("Missing CompatList file");
}
var microsoftDir = Path.Combine(extensionsDir, "Microsoft");
var msExtensionFiles = Directory.EnumerateFiles(microsoftDir, "*", SearchOption.AllDirectories);
foreach (var msExtensionFile in msExtensionFiles)
{
fileBuilder.Append(" ");
fileBuilder.AppendLine(msExtensionFile);
}
}
File.WriteAllText(filePath, fileBuilder.ToString());
}
private static IEnumerable<string> GetHiveDirectories()
{
var localAppData = Environment.GetEnvironmentVariable("LocalAppData");
var vsLocalDir = Path.Combine(localAppData, "Microsoft", "VisualStudio");
var directories = Directory.GetDirectories(vsLocalDir, "17*RoslynDev", SearchOption.TopDirectoryOnly);
var hiveDirectories = directories.Where(d => !d.Contains("$"));
return hiveDirectories;
}
private static void RazorOutputPaneLogger(string filePath)
{
// JoinableTaskFactory.Run isn't an option because we might be disposing already.
// Don't use ThreadHelper.JoinableTaskFactory in test methods, but it's correct here.
#pragma warning disable VSTHRD103 // Call async methods when in an async method
ThreadHelper.JoinableTaskFactory.Run(async () =>
#pragma warning restore VSTHRD103 // Call async methods when in an async method
{
try
{
var testServices = await Extensibility.Testing.TestServices.CreateAsync(ThreadHelper.JoinableTaskFactory);
var paneContent = await testServices.Output.GetRazorOutputPaneContentAsync(CancellationToken.None);
File.WriteAllText(filePath, paneContent);
}
catch (Exception)
{
// Eat any errors so we don't block further collection
}
});
}
private static async Task CollectFeedbackItemsAsync(IEnumerable<string> files, string destination, string expectedFilePart)
{
// What's important in this weird threading stuff is ensuring we vacate the thread RazorLogHubLogger was called on
// because if we don't it ends up blocking the thread that creates the zip file we need.
await ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
foreach (var file in files)
{
var name = Path.GetFileName(file);
// Only caputre loghub
if (name.Contains(expectedFilePart) && Path.GetExtension(file) == ".zip")
{
await Task.Run(() =>
{
WaitForFileExists(file);
if (File.Exists(file))
{
File.Copy(file, destination);
}
});
}
}
});
}
private static void WaitForFileExists(string file)
{
const int MaxRetries = 50;
var retries = 0;
while (!File.Exists(file) && retries < MaxRetries)
{
retries++;
// Free your thread
Thread.Yield();
// Wait a bit
Thread.Sleep(100);
}
}
}
}

Просмотреть файл

@ -57,31 +57,31 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
// Open the file // Open the file
if (testFileName.EndsWith(".razor", StringComparison.OrdinalIgnoreCase)) if (testFileName.EndsWith(".razor", StringComparison.OrdinalIgnoreCase))
{ {
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
} }
else else
{ {
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, ErrorCshtmlFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.ErrorCshtmlFile, ControlledHangMitigatingCancellationToken);
} }
await TestServices.Editor.SetTextAsync(input, HangMitigatingCancellationToken); await TestServices.Editor.SetTextAsync(input, ControlledHangMitigatingCancellationToken);
// Wait for the document to settle // Wait for the document to settle
if (testFileName == "FormatAndUndo.cshtml") if (testFileName == "FormatAndUndo.cshtml")
{ {
// This doesn't have anything to outline so we'll wait for semantic colors // This doesn't have anything to outline so we'll wait for semantic colors
await TestServices.Editor.WaitForClassificationAsync(HangMitigatingCancellationToken, "method name"); await TestServices.Editor.WaitForClassificationAsync(ControlledHangMitigatingCancellationToken, "method name");
} }
else else
{ {
await TestServices.Editor.WaitForOutlineRegionsAsync(HangMitigatingCancellationToken); await TestServices.Editor.WaitForOutlineRegionsAsync(ControlledHangMitigatingCancellationToken);
} }
// Act // Act
await TestServices.Editor.InvokeFormatDocumentAsync(HangMitigatingCancellationToken); await TestServices.Editor.InvokeFormatDocumentAsync(ControlledHangMitigatingCancellationToken);
// Assert // Assert
var actual = await TestServices.Editor.WaitForTextChangeAsync(input, HangMitigatingCancellationToken); var actual = await TestServices.Editor.WaitForTextChangeAsync(input, ControlledHangMitigatingCancellationToken);
if (!TryGetResource(expectedResourceName, out var expected)) if (!TryGetResource(expectedResourceName, out var expected))
{ {

Просмотреть файл

@ -12,63 +12,63 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task GoToDefinition_MethodInSameFile() public async Task GoToDefinition_MethodInSameFile()
{ {
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.PlaceCaretAsync("IncrementCount", charsOffset: -1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("IncrementCount", charsOffset: -1, ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Editor.InvokeGoToDefinitionAsync(HangMitigatingCancellationToken); await TestServices.Editor.InvokeGoToDefinitionAsync(ControlledHangMitigatingCancellationToken);
// Assert // Assert
await TestServices.Editor.WaitForCurrentLineTextAsync("private void IncrementCount()", HangMitigatingCancellationToken); await TestServices.Editor.WaitForCurrentLineTextAsync("private void IncrementCount()", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
public async Task GoToDefinition_CSharpClass() public async Task GoToDefinition_CSharpClass()
{ {
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, IndexRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.IndexRazorFile, ControlledHangMitigatingCancellationToken);
// Change text to refer back to Program class // Change text to refer back to Program class
await TestServices.Editor.SetTextAsync(@"<SurveyPrompt Title=""@nameof(Program)", HangMitigatingCancellationToken); await TestServices.Editor.SetTextAsync(@"<SurveyPrompt Title=""@nameof(Program)", ControlledHangMitigatingCancellationToken);
await TestServices.Editor.PlaceCaretAsync("Program", charsOffset: -1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("Program", charsOffset: -1, ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Editor.InvokeGoToDefinitionAsync(HangMitigatingCancellationToken); await TestServices.Editor.InvokeGoToDefinitionAsync(ControlledHangMitigatingCancellationToken);
// Assert // Assert
await TestServices.Editor.WaitForActiveWindowAsync("Program.cs", HangMitigatingCancellationToken); await TestServices.Editor.WaitForActiveWindowAsync("Program.cs", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
public async Task GoToDefinition_Component() public async Task GoToDefinition_Component()
{ {
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, IndexRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.IndexRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.PlaceCaretAsync("SurveyPrompt", charsOffset: -1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("SurveyPrompt", charsOffset: -1, ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Editor.InvokeGoToDefinitionAsync(HangMitigatingCancellationToken); await TestServices.Editor.InvokeGoToDefinitionAsync(ControlledHangMitigatingCancellationToken);
// Assert // Assert
await TestServices.Editor.WaitForActiveWindowAsync("SurveyPrompt.razor", HangMitigatingCancellationToken); await TestServices.Editor.WaitForActiveWindowAsync("SurveyPrompt.razor", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
public async Task GoToDefinition_ComponentAttribute() public async Task GoToDefinition_ComponentAttribute()
{ {
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, IndexRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.IndexRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.PlaceCaretAsync("Title=", charsOffset: -1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("Title=", charsOffset: -1, ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Editor.InvokeGoToDefinitionAsync(HangMitigatingCancellationToken); await TestServices.Editor.InvokeGoToDefinitionAsync(ControlledHangMitigatingCancellationToken);
// Assert // Assert
await TestServices.Editor.WaitForActiveWindowAsync("SurveyPrompt.razor", HangMitigatingCancellationToken); await TestServices.Editor.WaitForActiveWindowAsync("SurveyPrompt.razor", ControlledHangMitigatingCancellationToken);
await TestServices.Editor.WaitForCurrentLineTextAsync("public string? Title { get; set; }", HangMitigatingCancellationToken); await TestServices.Editor.WaitForCurrentLineTextAsync("public string? Title { get; set; }", ControlledHangMitigatingCancellationToken);
} }
} }
} }

Просмотреть файл

@ -12,32 +12,32 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task GoToImplementation_SameFile() public async Task GoToImplementation_SameFile()
{ {
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.PlaceCaretAsync("IncrementCount", charsOffset: -1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("IncrementCount", charsOffset: -1, ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Editor.InvokeGoToImplementationAsync(HangMitigatingCancellationToken); await TestServices.Editor.InvokeGoToImplementationAsync(ControlledHangMitigatingCancellationToken);
// Assert // Assert
await TestServices.Editor.WaitForCurrentLineTextAsync("private void IncrementCount()", HangMitigatingCancellationToken); await TestServices.Editor.WaitForCurrentLineTextAsync("private void IncrementCount()", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
public async Task GoToImplementation_CSharpClass() public async Task GoToImplementation_CSharpClass()
{ {
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, IndexRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.IndexRazorFile, ControlledHangMitigatingCancellationToken);
// Change text to refer back to Program class // Change text to refer back to Program class
await TestServices.Editor.SetTextAsync(@"<SurveyPrompt Title=""@nameof(Program)", HangMitigatingCancellationToken); await TestServices.Editor.SetTextAsync(@"<SurveyPrompt Title=""@nameof(Program)", ControlledHangMitigatingCancellationToken);
await TestServices.Editor.PlaceCaretAsync("Program", charsOffset: -1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("Program", charsOffset: -1, ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Editor.InvokeGoToImplementationAsync(HangMitigatingCancellationToken); await TestServices.Editor.InvokeGoToImplementationAsync(ControlledHangMitigatingCancellationToken);
// Assert // Assert
await TestServices.Editor.WaitForActiveWindowAsync("Program.cs", HangMitigatingCancellationToken); await TestServices.Editor.WaitForActiveWindowAsync("Program.cs", ControlledHangMitigatingCancellationToken);
} }
} }
} }

Просмотреть файл

@ -16,7 +16,7 @@ public class OnEnterRulesTests : AbstractRazorEditorTest
<button class='classifier'></button> <button class='classifier'></button>
"); ");
// Act // Act
await TestServices.Editor.PlaceCaretAsync(">", charsOffset: 1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync(">", charsOffset: 1, ControlledHangMitigatingCancellationToken);
TestServices.Input.Send("{ENTER}"); TestServices.Input.Send("{ENTER}");
TestServices.Input.Send("A"); TestServices.Input.Send("A");
@ -25,7 +25,7 @@ public class OnEnterRulesTests : AbstractRazorEditorTest
<button class='classifier'> <button class='classifier'>
A A
</button> </button>
", HangMitigatingCancellationToken); ", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
@ -37,7 +37,7 @@ public class OnEnterRulesTests : AbstractRazorEditorTest
"); ");
// Act // Act
await TestServices.Editor.PlaceCaretAsync("</button>", charsOffset: 1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("</button>", charsOffset: 1, ControlledHangMitigatingCancellationToken);
TestServices.Input.Send("{ENTER}"); TestServices.Input.Send("{ENTER}");
TestServices.Input.Send("A"); TestServices.Input.Send("A");
@ -45,7 +45,7 @@ public class OnEnterRulesTests : AbstractRazorEditorTest
await TestServices.Editor.VerifyTextContainsAsync(@" await TestServices.Editor.VerifyTextContainsAsync(@"
<button stuff></button> <button stuff></button>
A A
", HangMitigatingCancellationToken); ", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
@ -57,7 +57,7 @@ A
"); ");
// Act // Act
await TestServices.Editor.PlaceCaretAsync("button", charsOffset: 1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("button", charsOffset: 1, ControlledHangMitigatingCancellationToken);
TestServices.Input.Send("{ENTER}"); TestServices.Input.Send("{ENTER}");
@ -65,7 +65,7 @@ A
await TestServices.Editor.VerifyTextContainsAsync(@" await TestServices.Editor.VerifyTextContainsAsync(@"
<button <button
class='thing' stuff></button> class='thing' stuff></button>
", HangMitigatingCancellationToken); ", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
@ -77,14 +77,14 @@ A
"); ");
// Act // Act
await TestServices.Editor.PlaceCaretAsync("stuff", charsOffset: 1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("stuff", charsOffset: 1, ControlledHangMitigatingCancellationToken);
TestServices.Input.Send("{ENTER}"); TestServices.Input.Send("{ENTER}");
// Assert // Assert
await TestServices.Editor.VerifyTextContainsAsync(@" await TestServices.Editor.VerifyTextContainsAsync(@"
<button class='someclass' @onclick='thing' stuff <button class='someclass' @onclick='thing' stuff
></button> ></button>
", HangMitigatingCancellationToken); ", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
@ -96,14 +96,14 @@ A
"); ");
// Act // Act
await TestServices.Editor.PlaceCaretAsync("button", charsOffset: 1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("button", charsOffset: 1, ControlledHangMitigatingCancellationToken);
TestServices.Input.Send("{ENTER}"); TestServices.Input.Send("{ENTER}");
// Assert // Assert
await TestServices.Editor.VerifyTextContainsAsync(@" await TestServices.Editor.VerifyTextContainsAsync(@"
<button <button
class=""someclass"" @onclick='thing' stuff ></button> class=""someclass"" @onclick='thing' stuff ></button>
", HangMitigatingCancellationToken); ", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
@ -115,14 +115,14 @@ A
"); ");
// Act // Act
await TestServices.Editor.PlaceCaretAsync("@onclick='thing'", charsOffset: 1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("@onclick='thing'", charsOffset: 1, ControlledHangMitigatingCancellationToken);
TestServices.Input.Send("{ENTER}"); TestServices.Input.Send("{ENTER}");
// Assert // Assert
await TestServices.Editor.VerifyTextContainsAsync(@" await TestServices.Editor.VerifyTextContainsAsync(@"
<button class='someclass' @onclick='thing' <button class='someclass' @onclick='thing'
stuff ></button> stuff ></button>
", HangMitigatingCancellationToken); ", ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
@ -134,21 +134,21 @@ A
"); ");
// Act // Act
await TestServices.Editor.PlaceCaretAsync("button", charsOffset: 1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("button", charsOffset: 1, ControlledHangMitigatingCancellationToken);
TestServices.Input.Send("{ENTER}"); TestServices.Input.Send("{ENTER}");
// Assert // Assert
await TestServices.Editor.VerifyTextContainsAsync(@" await TestServices.Editor.VerifyTextContainsAsync(@"
<button <button
class='thing' stuff class='thing' stuff
", HangMitigatingCancellationToken); ", ControlledHangMitigatingCancellationToken);
} }
private async Task PrepareDocumentAsync(string content) private async Task PrepareDocumentAsync(string content)
{ {
// Arrange // Arrange
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.SetTextAsync(content, HangMitigatingCancellationToken); await TestServices.Editor.SetTextAsync(content, ControlledHangMitigatingCancellationToken);
} }
} }

Просмотреть файл

@ -11,14 +11,14 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
[IdeFact] [IdeFact]
public async Task TypeScript_Semicolon() public async Task TypeScript_Semicolon()
{ {
var version = await TestServices.Shell.GetVersionAsync(HangMitigatingCancellationToken); var version = await TestServices.Shell.GetVersionAsync(ControlledHangMitigatingCancellationToken);
if (version < new System.Version(42, 42, 42, 42)) if (version < new System.Version(42, 42, 42, 42))
{ {
return; return;
} }
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, ErrorCshtmlFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.ErrorCshtmlFile, ControlledHangMitigatingCancellationToken);
// Change text to refer back to Program class // Change text to refer back to Program class
await TestServices.Editor.SetTextAsync(@" await TestServices.Editor.SetTextAsync(@"
@ -28,14 +28,14 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
var x = 3 var x = 3
} }
</script> </script>
", HangMitigatingCancellationToken); ", ControlledHangMitigatingCancellationToken);
await TestServices.Editor.PlaceCaretAsync("3", charsOffset: 1, HangMitigatingCancellationToken); await TestServices.Editor.PlaceCaretAsync("3", charsOffset: 1, ControlledHangMitigatingCancellationToken);
// Act // Act
TestServices.Input.Send(";"); TestServices.Input.Send(";");
// Assert // Assert
await TestServices.Editor.WaitForCurrentLineTextAsync("var x = 3;", HangMitigatingCancellationToken); await TestServices.Editor.WaitForCurrentLineTextAsync("var x = 3;", ControlledHangMitigatingCancellationToken);
} }
} }
} }

Просмотреть файл

@ -11,8 +11,8 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
[IdeFact] [IdeFact]
public async Task CreateFromTemplateAsync() public async Task CreateFromTemplateAsync()
{ {
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.SolutionExplorer.CloseSolutionAsync(HangMitigatingCancellationToken); await TestServices.SolutionExplorer.CloseSolutionAsync(ControlledHangMitigatingCancellationToken);
} }
} }
} }

Просмотреть файл

@ -12,26 +12,26 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public async Task RazorCodeActions_Show() public async Task RazorCodeActions_Show()
{ {
// Create Warnings by removing usings // Create Warnings by removing usings
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, ImportsRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.ImportsRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.SetTextAsync("", HangMitigatingCancellationToken); await TestServices.Editor.SetTextAsync("", ControlledHangMitigatingCancellationToken);
// Open the file // Open the file
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.SetTextAsync("<SurveyPrompt></SurveyPrompt>", HangMitigatingCancellationToken); await TestServices.Editor.SetTextAsync("<SurveyPrompt></SurveyPrompt>", ControlledHangMitigatingCancellationToken);
await TestServices.Editor.MoveCaretAsync(3, HangMitigatingCancellationToken); await TestServices.Editor.MoveCaretAsync(3, ControlledHangMitigatingCancellationToken);
// Act // Act
var codeActions = await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); var codeActions = await TestServices.Editor.InvokeCodeActionListAsync(ControlledHangMitigatingCancellationToken);
// Assert // Assert
var codeActionSet = Assert.Single(codeActions); var codeActionSet = Assert.Single(codeActions);
var usingString = $"@using {BlazorProjectName}.Shared"; var usingString = $"@using {RazorProjectConstants.BlazorProjectName}.Shared";
var codeAction = Assert.Single(codeActionSet.Actions, a => a.DisplayText.Equals(usingString)); var codeAction = Assert.Single(codeActionSet.Actions, a => a.DisplayText.Equals(usingString));
await TestServices.Editor.InvokeCodeActionAsync(codeAction, HangMitigatingCancellationToken); await TestServices.Editor.InvokeCodeActionAsync(codeAction, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.VerifyTextContainsAsync(usingString, HangMitigatingCancellationToken); await TestServices.Editor.VerifyTextContainsAsync(usingString, ControlledHangMitigatingCancellationToken);
} }
} }
} }

Просмотреть файл

@ -0,0 +1,54 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.IO;
namespace Microsoft.VisualStudio.Razor.IntegrationTests
{
public static class RazorProjectConstants
{
internal const string BlazorProjectName = "BlazorProject";
private static readonly string s_pagesDir = Path.Combine("Pages");
private static readonly string s_sharedDir = Path.Combine("Shared");
internal static readonly string FetchDataRazorFile = Path.Combine(s_pagesDir, "FetchData.razor");
internal static readonly string CounterRazorFile = Path.Combine(s_pagesDir, "Counter.razor");
internal static readonly string IndexRazorFile = Path.Combine(s_pagesDir, "Index.razor");
internal static readonly string ModifiedIndexRazorFile = Path.Combine(s_pagesDir, "ModifiedIndex.razor");
internal static readonly string SemanticTokensFile = Path.Combine(s_pagesDir, "SemanticTokens.razor");
internal static readonly string MainLayoutFile = Path.Combine(s_sharedDir, "MainLayout.razor");
internal static readonly string ErrorCshtmlFile = Path.Combine(s_pagesDir, "Error.cshtml");
internal static readonly string ImportsRazorFile = "_Imports.razor";
internal static readonly string IndexPageContent = @"@page ""/""
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title=""How is Blazor working for you?"" />";
internal static readonly string MainLayoutContent = @"@inherits LayoutComponentBase
<PageTitle>BlazorApp</PageTitle>
<div class=""page"">
<div class=""sidebar"">
<NavMenu />
</div>
<main>
<div class=""top-row px-4"">
<a href=""https://docs.microsoft.com/aspnet/"" target=""_blank"">About</a>
</div>
<article class=""content px-4"">
@Body
</article>
</main>
</div>
";
}
}

Просмотреть файл

@ -36,39 +36,39 @@ namespace Microsoft.VisualStudio.Razor.IntegrationTests
public override async Task InitializeAsync() public override async Task InitializeAsync()
{ {
await base.InitializeAsync(); await base.InitializeAsync();
await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.Classification, HangMitigatingCancellationToken); await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.Classification, ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
public async Task Components_AreColored() public async Task Components_AreColored()
{ {
// Arrange // Arrange
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, MainLayoutFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.MainLayoutFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.SetTextAsync(MainLayoutContent, HangMitigatingCancellationToken); await TestServices.Editor.SetTextAsync(RazorProjectConstants.MainLayoutContent, ControlledHangMitigatingCancellationToken);
// Act // Act
await TestServices.Editor.WaitForClassificationAsync(HangMitigatingCancellationToken, "RazorComponentElement", 3); await TestServices.Editor.WaitForClassificationAsync(ControlledHangMitigatingCancellationToken, "RazorComponentElement", 3);
// Assert // Assert
var expectedClassifications = await GetExpectedClassificationSpansAsync(nameof(Components_AreColored), HangMitigatingCancellationToken); var expectedClassifications = await GetExpectedClassificationSpansAsync(nameof(Components_AreColored), ControlledHangMitigatingCancellationToken);
await TestServices.Editor.VerifyGetClassificationsAsync(expectedClassifications, HangMitigatingCancellationToken); await TestServices.Editor.VerifyGetClassificationsAsync(expectedClassifications, ControlledHangMitigatingCancellationToken);
} }
[IdeFact] [IdeFact]
public async Task Directives_AreColored() public async Task Directives_AreColored()
{ {
// Arrange // Arrange
await TestServices.SolutionExplorer.OpenFileAsync(BlazorProjectName, CounterRazorFile, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.OpenFileAsync(RazorProjectConstants.BlazorProjectName, RazorProjectConstants.CounterRazorFile, ControlledHangMitigatingCancellationToken);
await TestServices.Editor.WaitForClassificationAsync(HangMitigatingCancellationToken); await TestServices.Editor.WaitForClassificationAsync(ControlledHangMitigatingCancellationToken);
// Act and Assert // Act and Assert
var expectedClassifications = await GetExpectedClassificationSpansAsync(nameof(Directives_AreColored), HangMitigatingCancellationToken); var expectedClassifications = await GetExpectedClassificationSpansAsync(nameof(Directives_AreColored), ControlledHangMitigatingCancellationToken);
await TestServices.Editor.VerifyGetClassificationsAsync(expectedClassifications, HangMitigatingCancellationToken); await TestServices.Editor.VerifyGetClassificationsAsync(expectedClassifications, ControlledHangMitigatingCancellationToken);
} }
private async Task<IEnumerable<ClassificationSpan>> GetExpectedClassificationSpansAsync(string testName, CancellationToken cancellationToken) private async Task<IEnumerable<ClassificationSpan>> GetExpectedClassificationSpansAsync(string testName, CancellationToken cancellationToken)
{ {
var snapshot = await TestServices.Editor.GetActiveSnapshotAsync(HangMitigatingCancellationToken); var snapshot = await TestServices.Editor.GetActiveSnapshotAsync(ControlledHangMitigatingCancellationToken);
if (GenerateBaselines) if (GenerateBaselines)
{ {