/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Components/Testing/gen/UITestGenerator.cs
143 строки
6 KB
Javier Calvarro Nelson
[Blazor] Migrate Components.Testing from xUnit v3 to MSTest on MTP (#67083)
10 авг 2026, 11:47
Не верифицирован
10 авг 2026, 11:47
1d5f6d8
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Text; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.AspNetCore.Components.Testing.Generators; /// <summary> /// Emits the MSTest binding for E2E UI tests into the consumer test assembly so the shipping /// library itself needs no test-framework dependency. /// </summary> [Generator] internal sealed class UITestGenerator : IIncrementalGenerator { private const string UITestAttributeMetadataName = "Microsoft.AspNetCore.Components.Testing.Playwright.UITestAttribute"; private const string TestContextMetadataName = "Microsoft.VisualStudio.TestTools.UnitTesting.TestContext"; public void Initialize(IncrementalGeneratorInitializationContext context) { // True only when the consuming compilation references MSTest. All MSTest-specific // output is gated on this so referencing the package from a non-test project is inert. var hasMSTest = context.CompilationProvider.Select( static (compilation, _) => compilation.GetTypeByMetadataName(TestContextMetadataName) is not null); var classes = context.SyntaxProvider.ForAttributeWithMetadataName( UITestAttributeMetadataName, predicate: static (node, _) => node is ClassDeclarationSyntax, transform: static (ctx, _) => GetUITestClass(ctx)) .Where(static c => c is not null); context.RegisterSourceOutput(classes.Combine(hasMSTest), static (spc, pair) => { if (pair.Right && pair.Left is UITestClass target) { spc.AddSource($"{target.HintName}.g.cs", EmitClassBinding(target)); } }); } private static UITestClass? GetUITestClass(GeneratorAttributeSyntaxContext context) { if (context.TargetSymbol is not INamedTypeSymbol type) { return null; } var ns = type.ContainingNamespace is { IsGlobalNamespace: false } n ? n.ToDisplayString() : null; var hintName = (ns is null ? type.Name : ns + "." + type.Name) + ".UITest"; return new UITestClass(ns, type.Name, hintName); } private static string EmitClassBinding(UITestClass target) { var sb = new StringBuilder(); sb.AppendLine("// <auto-generated/>"); sb.AppendLine("#nullable enable"); sb.AppendLine("using System;"); sb.AppendLine("using System.Collections.Generic;"); sb.AppendLine("using System.IO;"); sb.AppendLine("using Microsoft.AspNetCore.Components.Testing.Infrastructure;"); sb.AppendLine("using Microsoft.VisualStudio.TestTools.UnitTesting;"); sb.AppendLine(); if (target.Namespace is not null) { sb.Append("namespace ").Append(target.Namespace).AppendLine(";"); sb.AppendLine(); } sb.Append("[TestClass]").AppendLine(); sb.Append("partial class ").Append(target.Name).AppendLine(" : ITestArtifactManager"); sb.AppendLine("{"); sb.AppendLine(" private bool __uiTestCleanupFailed;"); sb.AppendLine(); sb.AppendLine(" /// <summary>The MSTest test context for the current test (injected by MSTest).</summary>"); sb.AppendLine(" public TestContext TestContext { get; set; } = null!;"); sb.AppendLine(); sb.AppendLine(" bool ITestArtifactManager.ShouldSaveArtifacts()"); sb.AppendLine(" => __uiTestCleanupFailed ||"); sb.AppendLine(" TestContext.CurrentTestOutcome is not (UnitTestOutcome.Passed or UnitTestOutcome.Inconclusive);"); sb.AppendLine(); sb.AppendLine(" string ITestArtifactManager.CreateArtifactDirectory(string category)"); sb.AppendLine(" => Path.Combine("); sb.AppendLine(" TestArtifactDirectory.GetPath(TestContext.TestName ?? \"unknown\"),"); sb.AppendLine(" category,"); sb.AppendLine(" Guid.NewGuid().ToString(\"N\"));"); sb.AppendLine(); sb.AppendLine(" void ITestArtifactManager.AddArtifacts(IReadOnlyList<string> paths)"); sb.AppendLine(" {"); sb.AppendLine(" foreach (var path in paths)"); sb.AppendLine(" {"); sb.AppendLine(" TestContext.AddResultFile(path);"); sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine(); sb.AppendLine(" [TestInitialize]"); sb.AppendLine(" public global::System.Threading.Tasks.Task __UITestInitializeAsync()"); sb.AppendLine(" => InitializeCoreAsync();"); sb.AppendLine(); sb.AppendLine(" [TestCleanup]"); sb.AppendLine(" public async global::System.Threading.Tasks.Task __UITestCleanupAsync()"); sb.AppendLine(" {"); sb.AppendLine(" try"); sb.AppendLine(" {"); sb.AppendLine(" await CleanupCoreAsync().ConfigureAwait(false);"); sb.AppendLine(" }"); sb.AppendLine(" catch"); sb.AppendLine(" {"); sb.AppendLine(" __uiTestCleanupFailed = true;"); sb.AppendLine(" throw;"); sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private sealed record UITestClass { public UITestClass(string? @namespace, string name, string hintName) { Namespace = @namespace; Name = name; HintName = hintName; } public string? Namespace { get; } public string Name { get; } public string HintName { get; } } }