diff --git a/.azure/pipelines/blazor-daily-tests.yml b/.azure/pipelines/blazor-daily-tests.yml new file mode 100644 index 0000000000..537751bfed --- /dev/null +++ b/.azure/pipelines/blazor-daily-tests.yml @@ -0,0 +1,59 @@ +# Uses Scheduled Triggers, which aren't supported in YAML yet. +# https://docs.microsoft.com/en-us/azure/devops/pipelines/build/triggers?view=vsts&tabs=yaml#scheduled + +# Daily Tests for Blazor +# These use Sauce Labs resources, hence they run daily rather than per-commit. + +# We just need one Windows machine because all it does is trigger SauceLabs. +variables: + SAUCE_CONNECT_DOWNLOAD_ON_INSTALL: true + E2ETESTS_SauceTest: true + E2ETESTS_Sauce__TunnelIdentifier: 'blazor-e2e-sc-proxy-tunnel' + E2ETESTS_Sauce__HostName: 'sauce.local' +jobs: +- template: jobs/default-build.yml + parameters: + buildDirectory: src/Components + isTestingJob: true + agentOs: Windows + jobName: BlazorDailyTests + jobDisplayName: "Blazor Daily Tests" + afterBuild: + + # macOS/Safari + - script: 'dotnet test --filter "StandaloneAppTest"' + workingDirectory: 'src/Components/test/E2ETest' + displayName: 'Run Blazor tests - macOS/Safari' + condition: succeededOrFailed() + env: + # Secrets need to be explicitly mapped to env variables. + E2ETESTS_Sauce__Username: '$(asplab-sauce-labs-username)' + E2ETESTS_Sauce__AccessKey: '$(asplab-sauce-labs-access-key)' + # Set platform/browser configuration. + E2ETESTS_Sauce__TestName: 'Blazor Daily Tests - macOS/Safari' + E2ETESTS_Sauce__PlatformName: 'macOS 10.14' + E2ETESTS_Sauce__BrowserName: 'Safari' + # Need to explicitly set version here because some older versions don't support timeouts in Safari. + E2ETESTS_Sauce__SeleniumVersion: '3.4.0' + + # Android/Chrome + - script: 'dotnet test --filter "StandaloneAppTest"' + workingDirectory: 'src/Components/test/E2ETest' + displayName: 'Run Blazor tests - Android/Chrome' + condition: succeededOrFailed() + env: + # Secrets need to be explicitly mapped to env variables. + E2ETESTS_Sauce__Username: '$(asplab-sauce-labs-username)' + E2ETESTS_Sauce__AccessKey: '$(asplab-sauce-labs-access-key)' + # Set platform/browser configuration. + E2ETESTS_Sauce__TestName: 'Blazor Daily Tests - Android/Chrome' + E2ETESTS_Sauce__PlatformName: 'Android' + E2ETESTS_Sauce__PlatformVersion: '10.0' + E2ETESTS_Sauce__BrowserName: 'Chrome' + E2ETESTS_Sauce__DeviceName: 'Android GoogleAPI Emulator' + E2ETESTS_Sauce__DeviceOrientation: 'portrait' + E2ETESTS_Sauce__AppiumVersion: '1.9.1' + artifacts: + - name: Windows_Logs + path: ../../artifacts/log/ + publishOnError: true \ No newline at end of file diff --git a/eng/Baseline.Designer.props b/eng/Baseline.Designer.props index 78f2952da7..67c2badad5 100644 --- a/eng/Baseline.Designer.props +++ b/eng/Baseline.Designer.props @@ -18,6 +18,13 @@ 3.1.4 + + + 3.2.0 + + + + 3.1.4 @@ -240,6 +247,49 @@ + + + 3.2.0 + + + + + + + + + + + 3.2.0 + + + + + + + 3.2.0 + + + + + 3.2.0 + + + + + + + + 3.2.0 + + + + + 3.2.0 + + + + 3.1.4 diff --git a/eng/Baseline.xml b/eng/Baseline.xml index 5a5123aa86..ee094c82d5 100644 --- a/eng/Baseline.xml +++ b/eng/Baseline.xml @@ -8,6 +8,7 @@ Update this list when preparing for a new patch. + @@ -36,6 +37,12 @@ Update this list when preparing for a new patch. + + + + + + @@ -86,4 +93,4 @@ Update this list when preparing for a new patch. - + \ No newline at end of file diff --git a/eng/Build.props b/eng/Build.props index 31c08d2690..b3167aba70 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -25,8 +25,8 @@ $(RepoRoot)src\Installers\**\*.*proj; $(RepoRoot)src\SignalR\clients\ts\**\node_modules\**\*.*proj; $(RepoRoot)src\Components\Web.JS\node_modules\**\*.*proj; - $(RepoRoot)src\Components\Blazor\Build\testassets\**\*.*proj; - $(RepoRoot)src\ProjectTemplates\BlazorWasm.ProjectTemplates\content\**\*.csproj; + $(RepoRoot)src\Components\WebAssembly\Build\testassets\**\*.csproj; + $(RepoRoot)src\ProjectTemplates\ComponentsWebAssembly.ProjectTemplates\content\**\*.csproj; $(RepoRoot)src\ProjectTemplates\Web.ProjectTemplates\content\**\*.csproj; $(RepoRoot)src\ProjectTemplates\Web.ProjectTemplates\content\**\*.fsproj; $(RepoRoot)src\ProjectTemplates\Web.Spa.ProjectTemplates\content\**\*.csproj; diff --git a/eng/Dependencies.props b/eng/Dependencies.props index 9395da7547..d921c3eb09 100644 --- a/eng/Dependencies.props +++ b/eng/Dependencies.props @@ -73,6 +73,7 @@ and are generated based on the last package release. + @@ -106,7 +107,7 @@ and are generated based on the last package release. - + diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props index 3ff50b3b1a..3044b5f073 100644 --- a/eng/ProjectReferences.props +++ b/eng/ProjectReferences.props @@ -62,13 +62,14 @@ - - - - - - + + + + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7815e9ea3b..27c8d6d902 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -9,9 +9,13 @@ --> - + https://github.com/dotnet/blazor - dd7fb4d3931d556458f62642c2edfc59f6295bfb + cc449601d638ffaab58ae9487f0fd010bb178a12 + + + https://github.com/dotnet/corefx + 66409e392d64ed96e5d3a5fda712d9baf51196ed https://github.com/dotnet/efcore diff --git a/eng/Versions.props b/eng/Versions.props index 1d2a675c0f..984294e513 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -30,6 +30,7 @@ true $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$(AspNetCorePatchVersion) + $(ComponentsWebAssemblyMajorVersion).$(ComponentsWebAssemblyMinorVersion).$(ComponentsWebAssemblyPatchVersion) $(VersionPrefix) @@ -128,7 +129,7 @@ 5.0.0-preview.6.20271.10 - 3.2.0-preview1.20067.1 + 3.2.0 5.0.0-preview.6.20276.2 5.0.0-preview.6.20276.2 diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index f8ff7403d3..8df4e86276 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -297,7 +297,7 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = if ($msbuildCmd -ne $null) { # Workaround for https://github.com/dotnet/roslyn/issues/35793 # Due to this issue $msbuildCmd.Version returns 0.0.0.0 for msbuild.exe 16.2+ - $msbuildVersion = [Version]::new((Get-Item $msbuildCmd.Path).VersionInfo.ProductVersion.Split([char[]]@('-', '+'))[0]) + $msbuildVersion = [Version]::new((Get-Item $msbuildCmd.Path).VersionInfo.ProductVersion.Split(@('-', '+'))[0]) if ($msbuildVersion -ge $vsMinVersion) { return $global:_MSBuildExe = $msbuildCmd.Path diff --git a/src/Components/Blazor/Blazor.Version.props b/src/Components/Blazor/Blazor.Version.props deleted file mode 100644 index 8c119d5413..0000000000 --- a/src/Components/Blazor/Blazor.Version.props +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/Components/Blazor/Blazor/src/Builder/ComponentsApplicationBuilderExtensions.cs b/src/Components/Blazor/Blazor/src/Builder/ComponentsApplicationBuilderExtensions.cs deleted file mode 100644 index 66532474c6..0000000000 --- a/src/Components/Blazor/Blazor/src/Builder/ComponentsApplicationBuilderExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Components.Builder -{ - /// - /// Provides extension methods for . - /// - public static class ComponentsApplicationBuilderExtensions - { - /// - /// Associates the component type with the application, - /// causing it to be displayed in the specified DOM element. - /// - /// The . - /// The type of the component. - /// A CSS selector that uniquely identifies a DOM element. - public static void AddComponent(this IComponentsApplicationBuilder app, string domElementSelector) - where TComponent : IComponent - { - app.AddComponent(typeof(TComponent), domElementSelector); - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Builder/IComponentsApplicationBuilder.cs b/src/Components/Blazor/Blazor/src/Builder/IComponentsApplicationBuilder.cs deleted file mode 100644 index 84806a8769..0000000000 --- a/src/Components/Blazor/Blazor/src/Builder/IComponentsApplicationBuilder.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNetCore.Components.Builder -{ - /// - /// A builder for adding components to an application. - /// - public interface IComponentsApplicationBuilder - { - /// - /// Gets the application services. - /// - IServiceProvider Services { get; } - - /// - /// Associates the with the application, - /// causing it to be displayed in the specified DOM element. - /// - /// The type of the component. - /// A CSS selector that uniquely identifies a DOM element. - void AddComponent(Type componentType, string domElementSelector); - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/BlazorWebAssemblyHost.cs b/src/Components/Blazor/Blazor/src/Hosting/BlazorWebAssemblyHost.cs deleted file mode 100644 index e5631805ef..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/BlazorWebAssemblyHost.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - /// - /// Used to create an instance of Blazor host builder for a Browser application. - /// - public static class BlazorWebAssemblyHost - { - /// - /// Creates an instance of . - /// - /// The . - public static IWebAssemblyHostBuilder CreateDefaultBuilder() - { - return new WebAssemblyHostBuilder(); - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/ConventionBasedStartup.cs b/src/Components/Blazor/Blazor/src/Hosting/ConventionBasedStartup.cs deleted file mode 100644 index 53eecbf6e0..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/ConventionBasedStartup.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Runtime.ExceptionServices; -using Microsoft.AspNetCore.Components.Builder; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - // Keeping this simple for now to focus on predictable and reasonable behaviors. - // Startup in WebHost supports lots of things we don't yet support, and some we - // may never support. - // - // Possible additions: - // - environments - // - case-insensitivity (makes sense with environments) - // - // Likely never: - // - statics - // - DI into constructor - internal class ConventionBasedStartup : IBlazorStartup - { - public ConventionBasedStartup(object instance) - { - Instance = instance ?? throw new ArgumentNullException(nameof(instance)); - } - - public object Instance { get; } - - public void Configure(IComponentsApplicationBuilder app, IServiceProvider services) - { - try - { - var method = GetConfigureMethod(); - Debug.Assert(method != null); - - var parameters = method.GetParameters(); - var arguments = new object[parameters.Length]; - for (var i = 0; i < parameters.Length; i++) - { - var parameter = parameters[i]; - arguments[i] = parameter.ParameterType == typeof(IComponentsApplicationBuilder) - ? app - : services.GetRequiredService(parameter.ParameterType); - } - - method.Invoke(Instance, arguments); - } - catch (Exception ex) - { - if (ex is TargetInvocationException) - { - ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); - } - - throw; - } - } - - internal MethodInfo GetConfigureMethod() - { - var methods = Instance.GetType() - .GetMethods(BindingFlags.Instance | BindingFlags.Public) - .Where(m => string.Equals(m.Name, "Configure", StringComparison.Ordinal)) - .ToArray(); - - if (methods.Length == 1) - { - return methods[0]; - } - else if (methods.Length == 0) - { - throw new InvalidOperationException("The startup class must define a 'Configure' method."); - } - else - { - throw new InvalidOperationException("Overloading the 'Configure' method is not supported."); - } - } - - public void ConfigureServices(IServiceCollection services) - { - try - { - var method = GetConfigureServicesMethod(); - if (method != null) - { - method.Invoke(Instance, new object[] { services }); - } - } - catch (Exception ex) - { - if (ex is TargetInvocationException) - { - ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); - } - - throw; - } - } - - internal MethodInfo GetConfigureServicesMethod() - { - return Instance.GetType() - .GetMethod( - "ConfigureServices", - BindingFlags.Public | BindingFlags.Instance, - null, - new Type[] { typeof(IServiceCollection), }, - Array.Empty()); - } - } -} \ No newline at end of file diff --git a/src/Components/Blazor/Blazor/src/Hosting/IBlazorStartup.cs b/src/Components/Blazor/Blazor/src/Hosting/IBlazorStartup.cs deleted file mode 100644 index e87138387f..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/IBlazorStartup.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.Components.Builder; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - internal interface IBlazorStartup - { - void ConfigureServices(IServiceCollection services); - - void Configure(IComponentsApplicationBuilder app, IServiceProvider services); - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyHost.cs b/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyHost.cs deleted file mode 100644 index 8f21f93421..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyHost.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - /// - /// A program abstraction. - /// - public interface IWebAssemblyHost : IDisposable - { - /// - /// The programs configured services. - /// - IServiceProvider Services { get; } - - /// - /// Start the program. - /// - /// Used to abort program start. - /// - Task StartAsync(CancellationToken cancellationToken = default); - - /// - /// Attempts to gracefully stop the program. - /// - /// Used to indicate when stop should no longer be graceful. - /// - Task StopAsync(CancellationToken cancellationToken = default); - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyHostBuilder.cs b/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyHostBuilder.cs deleted file mode 100644 index c5a52bc280..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyHostBuilder.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - /// - /// Abstraction for configuring a Blazor browser-based application. - /// - public interface IWebAssemblyHostBuilder - { - /// - /// A central location for sharing state between components during the host building process. - /// - IDictionary Properties { get; } - - /// - /// Overrides the factory used to create the service provider. - /// - /// The same instance of the for chaining. - IWebAssemblyHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory); - - /// - /// Overrides the factory used to create the service provider. - /// - /// The same instance of the for chaining. - IWebAssemblyHostBuilder UseServiceProviderFactory(Func> factory); - - /// - /// Adds services to the container. This can be called multiple times and the results will be additive. - /// - /// The delegate for configuring the that will be used - /// to construct the . - /// The same instance of the for chaining. - IWebAssemblyHostBuilder ConfigureServices(Action configureDelegate); - - /// - /// Run the given actions to initialize the host. This can only be called once. - /// - /// An initialized - IWebAssemblyHost Build(); - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyServiceFactoryAdapter.cs b/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyServiceFactoryAdapter.cs deleted file mode 100644 index ff63ec3a66..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/IWebAssemblyServiceFactoryAdapter.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - // Equivalent to https://github.com/dotnet/extensions/blob/master/src/Hosting/Hosting/src/Internal/IServiceFactoryAdapter.cs - - internal interface IWebAssemblyServiceFactoryAdapter - { - object CreateBuilder(IServiceCollection services); - - IServiceProvider CreateServiceProvider(object containerBuilder); - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyBlazorApplicationBuilder.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyBlazorApplicationBuilder.cs deleted file mode 100644 index 8cb5d87561..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyBlazorApplicationBuilder.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Blazor.Rendering; -using Microsoft.AspNetCore.Components.Builder; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - internal class WebAssemblyBlazorApplicationBuilder : IComponentsApplicationBuilder - { - public WebAssemblyBlazorApplicationBuilder(IServiceProvider services) - { - Entries = new List<(Type componentType, string domElementSelector)>(); - Services = services; - } - - public List<(Type componentType, string domElementSelector)> Entries { get; } - - public IServiceProvider Services { get; } - - public void AddComponent(Type componentType, string domElementSelector) - { - if (componentType == null) - { - throw new ArgumentNullException(nameof(componentType)); - } - - if (domElementSelector == null) - { - throw new ArgumentNullException(nameof(domElementSelector)); - } - - Entries.Add((componentType, domElementSelector)); - } - - public async Task CreateRendererAsync() - { - var loggerFactory = (ILoggerFactory)Services.GetService(typeof(ILoggerFactory)); - var renderer = new WebAssemblyRenderer(Services, loggerFactory); - for (var i = 0; i < Entries.Count; i++) - { - var (componentType, domElementSelector) = Entries[i]; - await renderer.AddComponentAsync(componentType, domElementSelector); - } - - return renderer; - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs deleted file mode 100644 index b90878fdde..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Blazor.Rendering; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.JSInterop; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - internal class WebAssemblyHost : IWebAssemblyHost - { - private readonly IJSRuntime _runtime; - - private IServiceScope _scope; - private WebAssemblyRenderer _renderer; - - public WebAssemblyHost(IServiceProvider services, IJSRuntime runtime) - { - // To ensure JS-invoked methods don't get linked out, have a reference to their enclosing types - GC.KeepAlive(typeof(EntrypointInvoker)); - GC.KeepAlive(typeof(JSInteropMethods)); - GC.KeepAlive(typeof(WebAssemblyEventDispatcher)); - - Services = services ?? throw new ArgumentNullException(nameof(services)); - _runtime = runtime ?? throw new ArgumentNullException(nameof(runtime)); - } - - public IServiceProvider Services { get; } - - public Task StartAsync(CancellationToken cancellationToken = default) - { - return StartAsyncAwaited(); - } - - private async Task StartAsyncAwaited() - { - var scopeFactory = Services.GetRequiredService(); - _scope = scopeFactory.CreateScope(); - - try - { - var startup = _scope.ServiceProvider.GetService(); - if (startup == null) - { - var message = - $"Could not find a registered Blazor Startup class. " + - $"Using {nameof(IWebAssemblyHost)} requires a call to {nameof(IWebAssemblyHostBuilder)}.UseBlazorStartup."; - throw new InvalidOperationException(message); - } - - // Note that we differ from the WebHost startup path here by using a 'scope' for the app builder - // as well as the Configure method. - var builder = new WebAssemblyBlazorApplicationBuilder(_scope.ServiceProvider); - startup.Configure(builder, _scope.ServiceProvider); - - _renderer = await builder.CreateRendererAsync(); - } - catch - { - _scope.Dispose(); - _scope = null; - - if (_renderer != null) - { - _renderer.Dispose(); - _renderer = null; - } - - throw; - } - } - - public Task StopAsync(CancellationToken cancellationToken = default) - { - if (_scope != null) - { - _scope.Dispose(); - _scope = null; - } - - if (_renderer != null) - { - _renderer.Dispose(); - _renderer = null; - } - - return Task.CompletedTask; - } - - public void Dispose() - { - (Services as IDisposable)?.Dispose(); - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilder.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilder.cs deleted file mode 100644 index 7fa4dd0ae1..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilder.cs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Net.Http; -using Microsoft.AspNetCore.Blazor.Services; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Routing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Logging; -using Microsoft.JSInterop; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - // - // This code was taken virtually as-is from the Microsoft.Extensions.Hosting project in aspnet/Hosting and then - // lots of things were removed. - // - internal class WebAssemblyHostBuilder : IWebAssemblyHostBuilder - { - private List> _configureServicesActions = new List>(); - private bool _hostBuilt; - private WebAssemblyHostBuilderContext _BrowserHostBuilderContext; - private IWebAssemblyServiceFactoryAdapter _serviceProviderFactory = new WebAssemblyServiceFactoryAdapter(new DefaultServiceProviderFactory()); - private IServiceProvider _appServices; - - /// - /// A central location for sharing state between components during the host building process. - /// - public IDictionary Properties { get; } = new Dictionary(); - - /// - /// Adds services to the container. This can be called multiple times and the results will be additive. - /// - /// - /// The same instance of the for chaining. - public IWebAssemblyHostBuilder ConfigureServices(Action configureDelegate) - { - _configureServicesActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); - return this; - } - - /// - /// Overrides the factory used to create the service provider. - /// - /// The same instance of the for chaining. - public IWebAssemblyHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) - { - _serviceProviderFactory = new WebAssemblyServiceFactoryAdapter(factory ?? throw new ArgumentNullException(nameof(factory))); - return this; - } - - /// - /// Overrides the factory used to create the service provider. - /// - /// The same instance of the for chaining. - public IWebAssemblyHostBuilder UseServiceProviderFactory(Func> factory) - { - _serviceProviderFactory = new WebAssemblyServiceFactoryAdapter(() => _BrowserHostBuilderContext, factory ?? throw new ArgumentNullException(nameof(factory))); - return this; - } - - /// - /// Run the given actions to initialize the host. This can only be called once. - /// - /// An initialized - public IWebAssemblyHost Build() - { - if (_hostBuilt) - { - throw new InvalidOperationException("Build can only be called once."); - } - _hostBuilt = true; - - CreateBrowserHostBuilderContext(); - CreateServiceProvider(); - - return _appServices.GetRequiredService(); - } - - private void CreateBrowserHostBuilderContext() - { - _BrowserHostBuilderContext = new WebAssemblyHostBuilderContext(Properties); - } - - private void CreateServiceProvider() - { - var services = new ServiceCollection(); - services.AddSingleton(_BrowserHostBuilderContext); - services.AddSingleton(); - services.AddSingleton(WebAssemblyJSRuntime.Instance); - services.AddSingleton(WebAssemblyNavigationManager.Instance); - services.AddSingleton(WebAssemblyNavigationInterception.Instance); - services.AddSingleton(); - services.AddSingleton(s => - { - // Creating the URI helper needs to wait until the JS Runtime is initialized, so defer it. - var navigationManager = s.GetRequiredService(); - return new HttpClient - { - BaseAddress = new Uri(navigationManager.BaseUri) - }; - }); - - // Needed for authorization - // However, since authorization isn't on by default, we could consider removing these and - // having a separate services.AddBlazorAuthorization() call that brings in the required services. - services.AddOptions(); - services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(WebAssemblyConsoleLogger<>))); - - foreach (var configureServicesAction in _configureServicesActions) - { - configureServicesAction(_BrowserHostBuilderContext, services); - } - - var builder = _serviceProviderFactory.CreateBuilder(services); - _appServices = _serviceProviderFactory.CreateServiceProvider(builder); - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderContext.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderContext.cs deleted file mode 100644 index c7b7dd6f19..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderContext.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - /// - /// Context containing the common services on the . Some properties may be null until set by the . - /// - public sealed class WebAssemblyHostBuilderContext - { - /// - /// Creates a new . - /// - /// The property collection. - public WebAssemblyHostBuilderContext(IDictionary properties) - { - Properties = properties ?? throw new System.ArgumentNullException(nameof(properties)); - } - - /// - /// A central location for sharing state between components during the host building process. - /// - public IDictionary Properties { get; } - } -} \ No newline at end of file diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderExtensions.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderExtensions.cs deleted file mode 100644 index 9b03c09766..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderExtensions.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - /// - /// Provides Blazor-specific support for . - /// - public static class WebAssemblyHostBuilderExtensions - { - private const string BlazorStartupKey = "Blazor.Startup"; - - /// - /// Adds services to the container. This can be called multiple times and the results will be additive. - /// - /// The to configure. - /// - /// The same instance of the for chaining. - public static IWebAssemblyHostBuilder ConfigureServices(this IWebAssemblyHostBuilder hostBuilder, Action configureDelegate) - { - return hostBuilder.ConfigureServices((context, collection) => configureDelegate(collection)); - } - - /// - /// Configures the to use the provided startup class. - /// - /// The . - /// A type that configures a Blazor application. - /// The . - public static IWebAssemblyHostBuilder UseBlazorStartup(this IWebAssemblyHostBuilder builder, Type startupType) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (builder.Properties.ContainsKey(BlazorStartupKey)) - { - throw new InvalidOperationException("A startup class has already been registered."); - } - - // It would complicate the implementation to allow multiple startup classes, and we don't - // really have a need for it. - builder.Properties.Add(BlazorStartupKey, bool.TrueString); - - var startup = new ConventionBasedStartup(Activator.CreateInstance(startupType)); - - builder.ConfigureServices(startup.ConfigureServices); - builder.ConfigureServices(s => s.AddSingleton(startup)); - - return builder; - } - - /// - /// Configures the to use the provided startup class. - /// - /// A type that configures a Blazor application. - /// The . - /// The . - public static IWebAssemblyHostBuilder UseBlazorStartup(this IWebAssemblyHostBuilder builder) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return UseBlazorStartup(builder, typeof(TStartup)); - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostExtensions.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostExtensions.cs deleted file mode 100644 index 5182a1660d..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - /// - /// Extension methods for . - /// - public static class WebAssemblyHostExtensions - { - /// - /// Runs the application. - /// - /// The to run. - /// - /// Currently, Blazor applications running in the browser don't have a lifecycle - the application does not - /// get a chance to gracefully shut down. For now, simply starts the host - /// and allows execution to continue. - /// - public static void Run(this IWebAssemblyHost host) - { - // Behave like async void, because we don't yet support async-main properly on WebAssembly. - // However, don't actually make this method async, because we rely on startup being synchronous - // for things like attaching navigation event handlers. - host.StartAsync().ContinueWith(task => - { - if (task.Exception != null) - { - Console.WriteLine(task.Exception); - } - }); - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyServiceFactoryAdapter.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyServiceFactoryAdapter.cs deleted file mode 100644 index 2cfc0ba093..0000000000 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyServiceFactoryAdapter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNetCore.Blazor.Hosting -{ - // Equivalent to https://github.com/dotnet/extensions/blob/master/src/Hosting/Hosting/src/Internal/ServiceFactoryAdapter.cs - - internal class WebAssemblyServiceFactoryAdapter : IWebAssemblyServiceFactoryAdapter - { - private IServiceProviderFactory _serviceProviderFactory; - private readonly Func _contextResolver; - private Func> _factoryResolver; - - public WebAssemblyServiceFactoryAdapter(IServiceProviderFactory serviceProviderFactory) - { - _serviceProviderFactory = serviceProviderFactory ?? throw new ArgumentNullException(nameof(serviceProviderFactory)); - } - - public WebAssemblyServiceFactoryAdapter(Func contextResolver, Func> factoryResolver) - { - _contextResolver = contextResolver ?? throw new ArgumentNullException(nameof(contextResolver)); - _factoryResolver = factoryResolver ?? throw new ArgumentNullException(nameof(factoryResolver)); - } - - public object CreateBuilder(IServiceCollection services) - { - if (_serviceProviderFactory == null) - { - _serviceProviderFactory = _factoryResolver(_contextResolver()); - - if (_serviceProviderFactory == null) - { - throw new InvalidOperationException("The resolver returned a null IServiceProviderFactory"); - } - } - return _serviceProviderFactory.CreateBuilder(services); - } - - public IServiceProvider CreateServiceProvider(object containerBuilder) - { - if (_serviceProviderFactory == null) - { - throw new InvalidOperationException("CreateBuilder must be called before CreateServiceProvider"); - } - - return _serviceProviderFactory.CreateServiceProvider((TContainerBuilder)containerBuilder); - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Http/WebAssemblyHttpMessageHandlerOptions.cs b/src/Components/Blazor/Blazor/src/Http/WebAssemblyHttpMessageHandlerOptions.cs deleted file mode 100644 index bc46e4e527..0000000000 --- a/src/Components/Blazor/Blazor/src/Http/WebAssemblyHttpMessageHandlerOptions.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Reflection; - -namespace Microsoft.AspNetCore.Blazor.Http -{ - /// - /// Configures options for the WebAssembly HTTP message handler. - /// - public static class WebAssemblyHttpMessageHandlerOptions - { - /// - /// Gets or sets the default value of the 'credentials' option on outbound HTTP requests. - /// Defaults to . - /// - public static FetchCredentialsOption DefaultCredentials - { - get - { - var valueString = MonoDefaultCredentialsGetter.Value(); - var result = default(FetchCredentialsOption); - if (valueString != null) - { - Enum.TryParse(valueString, out result); - } - return result; - } - - set - { - MonoDefaultCredentialsSetter.Value(value.ToString()); - } - } - - static Func MonoWasmHttpMessageHandlerType = () - => Assembly.Load("WebAssembly.Net.Http") - .GetType("WebAssembly.Net.Http.HttpClient.WasmHttpMessageHandler"); - - static Func MonoFetchCredentialsOptionType = () - => Assembly.Load("WebAssembly.Net.Http") - .GetType("WebAssembly.Net.Http.HttpClient.FetchCredentialsOption"); - - static Lazy MonoDefaultCredentialsProperty = new Lazy( - () => MonoWasmHttpMessageHandlerType()?.GetProperty("DefaultCredentials", BindingFlags.Public | BindingFlags.Static)); - - static Lazy> MonoDefaultCredentialsGetter = new Lazy>(() => - { - return () => MonoDefaultCredentialsProperty.Value?.GetValue(null).ToString(); - }); - - static Lazy> MonoDefaultCredentialsSetter = new Lazy>(() => - { - var fetchCredentialsOptionsType = MonoFetchCredentialsOptionType(); - return value => MonoDefaultCredentialsProperty.Value?.SetValue(null, Enum.Parse(fetchCredentialsOptionsType, value)); - }); - } -} diff --git a/src/Components/Blazor/Blazor/src/JSInteropMethods.cs b/src/Components/Blazor/Blazor/src/JSInteropMethods.cs deleted file mode 100644 index 239dbb4952..0000000000 --- a/src/Components/Blazor/Blazor/src/JSInteropMethods.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.ComponentModel; -using Microsoft.AspNetCore.Blazor.Services; -using Microsoft.JSInterop; - -namespace Microsoft.AspNetCore.Blazor -{ - /// - /// Contains methods called by interop. Intended for framework use only, not supported for use in application - /// code. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public static class JSInteropMethods - { - /// - /// For framework use only. - /// - [JSInvokable(nameof(NotifyLocationChanged))] - public static void NotifyLocationChanged(string uri, bool isInterceptedLink) - { - WebAssemblyNavigationManager.Instance.SetLocation(uri, isInterceptedLink); - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj b/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj deleted file mode 100644 index d53f7d01fe..0000000000 --- a/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - netstandard2.1 - Build client-side single-page applications (SPAs) with Blazor running under WebAssembly. - false - - - - - - - - - - - - - - - - - - - - diff --git a/src/Components/Blazor/Blazor/src/Services/WebAssemblyConsoleLogger.cs b/src/Components/Blazor/Blazor/src/Services/WebAssemblyConsoleLogger.cs deleted file mode 100644 index 1769dbd915..0000000000 --- a/src/Components/Blazor/Blazor/src/Services/WebAssemblyConsoleLogger.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Blazor.Services -{ - internal class WebAssemblyConsoleLogger : ILogger, ILogger - { - public IDisposable BeginScope(TState state) - { - return NoOpDisposable.Instance; - } - - public bool IsEnabled(LogLevel logLevel) - { - return logLevel >= LogLevel.Warning; - } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - if (!IsEnabled(logLevel)) - { - return; - } - - var formattedMessage = formatter(state, exception); - Console.WriteLine($"[{logLevel}] {formattedMessage}"); - } - - private class NoOpDisposable : IDisposable - { - public static NoOpDisposable Instance = new NoOpDisposable(); - - public void Dispose() { } - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Services/WebAssemblyJSRuntime.cs b/src/Components/Blazor/Blazor/src/Services/WebAssemblyJSRuntime.cs deleted file mode 100644 index c5404c256f..0000000000 --- a/src/Components/Blazor/Blazor/src/Services/WebAssemblyJSRuntime.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Components; -using Mono.WebAssembly.Interop; - -namespace Microsoft.AspNetCore.Blazor.Services -{ - internal sealed class WebAssemblyJSRuntime : MonoWebAssemblyJSRuntime - { - private static readonly WebAssemblyJSRuntime _instance = new WebAssemblyJSRuntime(); - private static bool _initialized; - - public WebAssemblyJSRuntime() - { - JsonSerializerOptions.Converters.Add(new ElementReferenceJsonConverter()); - } - - public static WebAssemblyJSRuntime Instance - { - get - { - if (!_initialized) - { - // This is executing in MonoWASM. Consequently we do not to have concern ourselves with thread safety. - _initialized = true; - Initialize(_instance); - } - - return _instance; - } - } - } -} diff --git a/src/Components/Blazor/Blazor/src/Services/WebAssemblyLoggerFactory.cs b/src/Components/Blazor/Blazor/src/Services/WebAssemblyLoggerFactory.cs deleted file mode 100644 index 73458387e7..0000000000 --- a/src/Components/Blazor/Blazor/src/Services/WebAssemblyLoggerFactory.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Blazor.Services -{ - internal class WebAssemblyLoggerFactory : ILoggerFactory - { - public void AddProvider(ILoggerProvider provider) - { - // No-op - } - - public ILogger CreateLogger(string categoryName) - => new WebAssemblyConsoleLogger(); - - public void Dispose() - { - // No-op - } - } -} diff --git a/src/Components/Blazor/Blazor/test/Hosting/ConventionBasedStartupTest.cs b/src/Components/Blazor/Blazor/test/Hosting/ConventionBasedStartupTest.cs deleted file mode 100644 index cbc73b79f8..0000000000 --- a/src/Components/Blazor/Blazor/test/Hosting/ConventionBasedStartupTest.cs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using Microsoft.AspNetCore.Blazor.Hosting; -using Microsoft.AspNetCore.Components.Builder; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Microsoft.AspNetCore.Components.Hosting -{ - public class ConventionBasedStartupTest - { - [Fact] - public void ConventionBasedStartup_GetConfigureServicesMethod_FindsConfigureServices() - { - // Arrange - var startup = new ConventionBasedStartup(new MyStartup1()); - - // Act - var method = startup.GetConfigureServicesMethod(); - - // Assert - Assert.Equal(typeof(IServiceCollection), method.GetParameters()[0].ParameterType); - } - - private class MyStartup1 - { - public void ConfigureServices(IServiceCollection services) - { - } - - // Ignored - public void ConfigureServices(DateTime x) - { - - } - - // Ignored - private void ConfigureServices(int x) - { - } - - // Ignored - public static void ConfigureServices(string x) - { - } - } - - [Fact] - public void ConventionBasedStartup_GetConfigureServicesMethod_NoMethodFound() - { - // Arrange - var startup = new ConventionBasedStartup(new MyStartup2()); - - // Act - var method = startup.GetConfigureServicesMethod(); - - // Assert - Assert.Null(method); - } - - private class MyStartup2 - { - } - - [Fact] - public void ConventionBasedStartup_ConfigureServices_CallsMethod() - { - // Arrange - var startup = new ConventionBasedStartup(new MyStartup3()); - var services = new ServiceCollection(); - - // Act - startup.ConfigureServices(services); - - // Assert - Assert.NotEmpty(services); - } - - private class MyStartup3 - { - public void ConfigureServices(IServiceCollection services) - { - services.AddSingleton("foo"); - } - } - - [Fact] - public void ConventionBasedStartup_ConfigureServices_NoMethodFound() - { - // Arrange - var startup = new ConventionBasedStartup(new MyStartup4()); - var services = new ServiceCollection(); - - // Act - startup.ConfigureServices(services); - - // Assert - Assert.Empty(services); - } - - private class MyStartup4 - { - } - - [Fact] - public void ConventionBasedStartup_GetConfigureMethod_FindsConfigure() - { - // Arrange - var startup = new ConventionBasedStartup(new MyStartup5()); - - // Act - var method = startup.GetConfigureMethod(); - - // Assert - Assert.Empty(method.GetParameters()); - } - - private class MyStartup5 - { - public void Configure() - { - } - - // Ignored - private void Configure(int x) - { - } - - // Ignored - public static void Configure(string x) - { - } - } - - [Fact] - public void ConventionBasedStartup_GetConfigureMethod_NoMethodFoundThrows() - { - // Arrange - var startup = new ConventionBasedStartup(new MyStartup6()); - - // Act - var ex = Assert.Throws(() => startup.GetConfigureMethod()); - - // Assert - Assert.Equal("The startup class must define a 'Configure' method.", ex.Message); - } - - private class MyStartup6 - { - } - - [Fact] - public void ConventionBasedStartup_GetConfigureMethod_OverloadedThrows() - { - // Arrange - var startup = new ConventionBasedStartup(new MyStartup7()); - - // Act - var ex = Assert.Throws(() => startup.GetConfigureMethod()); - - // Assert - Assert.Equal("Overloading the 'Configure' method is not supported.", ex.Message); - } - - private class MyStartup7 - { - public void Configure() - { - } - - public void Configure(string x) - { - } - } - - [Fact] - public void ConventionBasedStartup_Configure() - { - // Arrange - var instance = new MyStartup8(); - var startup = new ConventionBasedStartup(instance); - - var services = new ServiceCollection().AddSingleton("foo").BuildServiceProvider(); - var builder = new WebAssemblyBlazorApplicationBuilder(services); - - // Act - startup.Configure(builder, services); - - // Assert - Assert.Collection( - instance.Arguments, - a => Assert.Same(builder, a), - a => Assert.Equal("foo", a)); - } - - private class MyStartup8 - { - public List Arguments { get; } = new List(); - - public void Configure(IComponentsApplicationBuilder app, string foo) - { - Arguments.Add(app); - Arguments.Add(foo); - } - } - } -} diff --git a/src/Components/Blazor/Blazor/test/Hosting/WebAssemblyHostBuilderTest.cs b/src/Components/Blazor/Blazor/test/Hosting/WebAssemblyHostBuilderTest.cs deleted file mode 100644 index 4acf6f99a3..0000000000 --- a/src/Components/Blazor/Blazor/test/Hosting/WebAssemblyHostBuilderTest.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.JSInterop; -using Xunit; - -namespace Microsoft.AspNetCore.Blazor.Hosting.Test -{ - public class WebAssemblyHostBuilderTest - { - [Fact] - public void HostBuilder_CanCallBuild_BuildsServices() - { - // Arrange - var builder = new WebAssemblyHostBuilder(); - - // Act - var host = builder.Build(); - - // Assert - Assert.NotNull(host.Services.GetService(typeof(IWebAssemblyHost))); - } - - [Fact] - public void HostBuilder_CanConfigureAdditionalServices() - { - // Arrange - var builder = new WebAssemblyHostBuilder(); - builder.ConfigureServices((c, s) => s.AddSingleton("foo")); - builder.ConfigureServices((c, s) => s.AddSingleton(new StringBuilder("bar"))); - - // Act - var host = builder.Build(); - - // Assert - Assert.Equal("foo", host.Services.GetService(typeof(string))); - Assert.Equal("bar", host.Services.GetService(typeof(StringBuilder)).ToString()); - } - - [Fact] - public void HostBuilder_UseBlazorStartup_CanConfigureAdditionalServices() - { - // Arrange - var builder = new WebAssemblyHostBuilder(); - builder.UseBlazorStartup(); - builder.ConfigureServices((c, s) => s.AddSingleton(new StringBuilder("bar"))); - - // Act - var host = builder.Build(); - - // Assert - Assert.Equal("foo", host.Services.GetService(typeof(string))); - Assert.Equal("bar", host.Services.GetService(typeof(StringBuilder)).ToString()); - } - - [Fact] - public void HostBuilder_UseBlazorStartup_DoesNotAllowMultiple() - { - // Arrange - var builder = new WebAssemblyHostBuilder(); - builder.UseBlazorStartup(); - - // Act - var ex = Assert.Throws(() => builder.UseBlazorStartup()); - - // Assert - Assert.Equal("A startup class has already been registered.", ex.Message); - } - - private class MyStartup - { - public void ConfigureServices(IServiceCollection services) - { - services.AddSingleton("foo"); - } - } - - [Fact] - public void HostBuilder_CanCustomizeServiceFactory() - { - // Arrange - var builder = new WebAssemblyHostBuilder(); - builder.UseServiceProviderFactory(new TestServiceProviderFactory()); - - // Act - var host = builder.Build(); - - // Assert - Assert.IsType(host.Services); - } - - [Fact] - public void HostBuilder_CanCustomizeServiceFactoryWithContext() - { - // Arrange - var builder = new WebAssemblyHostBuilder(); - builder.UseServiceProviderFactory(context => - { - Assert.NotNull(context.Properties); - Assert.Same(builder.Properties, context.Properties); - return new TestServiceProviderFactory(); - }); - - // Act - var host = builder.Build(); - - // Assert - Assert.IsType(host.Services); - } - - private class TestServiceProvider : IServiceProvider - { - private readonly IServiceProvider _underlyingProvider; - - public TestServiceProvider(IServiceProvider underlyingProvider) - { - _underlyingProvider = underlyingProvider; - } - - public object GetService(Type serviceType) - { - if (serviceType == typeof(IWebAssemblyHost)) - { - // Since the test will make assertions about the resulting IWebAssemblyHost, - // show that custom DI containers have the power to substitute themselves - // as the IServiceProvider - return new WebAssemblyHost( - this, _underlyingProvider.GetRequiredService()); - } - else - { - return _underlyingProvider.GetService(serviceType); - } - } - } - - private class TestServiceProviderFactory : IServiceProviderFactory - { - public IServiceCollection CreateBuilder(IServiceCollection services) - { - return new TestServiceCollection(services); - } - - public IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) - { - Assert.IsType(serviceCollection); - return new TestServiceProvider(serviceCollection.BuildServiceProvider()); - } - - class TestServiceCollection : List, IServiceCollection - { - public TestServiceCollection(IEnumerable collection) - : base(collection) - { - } - } - } - } -} diff --git a/src/Components/Blazor/Blazor/test/Hosting/WebAssemblyHostTest.cs b/src/Components/Blazor/Blazor/test/Hosting/WebAssemblyHostTest.cs deleted file mode 100644 index f99245e317..0000000000 --- a/src/Components/Blazor/Blazor/test/Hosting/WebAssemblyHostTest.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Builder; -using Microsoft.AspNetCore.Components.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.JSInterop; -using Mono.WebAssembly.Interop; -using Xunit; - -namespace Microsoft.AspNetCore.Blazor.Hosting.Test -{ - public class WebAssemblyHostTest - { - [Fact] - public async Task BrowserHost_StartAsync_ThrowsWithoutStartup() - { - // Arrange - var builder = new WebAssemblyHostBuilder(); - var host = builder.Build(); - - // Act - var ex = await Assert.ThrowsAsync(async () => await host.StartAsync()); - - // Assert - Assert.Equal( - "Could not find a registered Blazor Startup class. " + - "Using IWebAssemblyHost requires a call to IWebAssemblyHostBuilder.UseBlazorStartup.", - ex.Message); - } - - [Fact] - public async Task BrowserHost_StartAsync_RunsConfigureMethod() - { - // Arrange - var builder = new WebAssemblyHostBuilder(); - - var startup = new MockStartup(); - builder.ConfigureServices((c, s) => { s.AddSingleton(startup); }); - - var host = builder.Build(); - - // Act - await host.StartAsync(); - - // Assert - Assert.True(startup.ConfigureCalled); - } - - private class MockStartup : IBlazorStartup - { - public bool ConfigureCalled { get; set; } - - public void Configure(IComponentsApplicationBuilder app, IServiceProvider services) - { - ConfigureCalled = true; - } - - public void ConfigureServices(IServiceCollection services) - { - } - } - } -} diff --git a/src/Components/Blazor/Blazor/test/Microsoft.AspNetCore.Blazor.Tests.csproj b/src/Components/Blazor/Blazor/test/Microsoft.AspNetCore.Blazor.Tests.csproj deleted file mode 100644 index b156fde4a2..0000000000 --- a/src/Components/Blazor/Blazor/test/Microsoft.AspNetCore.Blazor.Tests.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - $(DefaultNetCoreTargetFramework) - - false - - - - - - - - - - - - diff --git a/src/Components/Blazor/Build/src/Properties/AssemblyInfo.cs b/src/Components/Blazor/Build/src/Properties/AssemblyInfo.cs deleted file mode 100644 index aac42c25cc..0000000000 --- a/src/Components/Blazor/Build/src/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Blazor.Build.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Components/Blazor/Build/src/Tasks/GenerateBlazorBootJson.cs b/src/Components/Blazor/Build/src/Tasks/GenerateBlazorBootJson.cs deleted file mode 100644 index 1984de0a57..0000000000 --- a/src/Components/Blazor/Build/src/Tasks/GenerateBlazorBootJson.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization.Json; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -namespace Microsoft.AspNetCore.Blazor.Build -{ - public class GenerateBlazorBootJson : Task - { - [Required] - public string AssemblyPath { get; set; } - - [Required] - public ITaskItem[] References { get; set; } - - [Required] - public bool LinkerEnabled { get; set; } - - [Required] - public string OutputPath { get; set; } - - public override bool Execute() - { - var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name; - var assemblies = References.Select(GetUriPath).OrderBy(c => c, StringComparer.Ordinal).ToArray(); - - using var fileStream = File.Create(OutputPath); - WriteBootJson(fileStream, entryAssemblyName, assemblies, LinkerEnabled); - - return true; - - static string GetUriPath(ITaskItem item) - { - var outputPath = item.GetMetadata("RelativeOutputPath"); - if (string.IsNullOrEmpty(outputPath)) - { - outputPath = Path.GetFileName(item.ItemSpec); - } - - return outputPath.Replace('\\', '/'); - } - } - - internal static void WriteBootJson(Stream stream, string entryAssemblyName, string[] assemblies, bool linkerEnabled) - { - var data = new BootJsonData - { - entryAssembly = entryAssemblyName, - assemblies = assemblies, - linkerEnabled = linkerEnabled, - }; - - var serializer = new DataContractJsonSerializer(typeof(BootJsonData)); - serializer.WriteObject(stream, data); - } - - /// - /// Defines the structure of a Blazor boot JSON file - /// -#pragma warning disable IDE1006 // Naming Styles - public class BootJsonData - { - /// - /// Gets the name of the assembly with the application entry point - /// - public string entryAssembly { get; set; } - - /// - /// Gets the closure of assemblies to be loaded by Blazor WASM. This includes the application entry assembly. - /// - public string[] assemblies { get; set; } - - /// - /// Gets a value that determines if the linker is enabled. - /// - public bool linkerEnabled { get; set; } - } -#pragma warning restore IDE1006 // Naming Styles - } -} diff --git a/src/Components/Blazor/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Blazor.Build.props b/src/Components/Blazor/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Blazor.Build.props deleted file mode 100644 index f20d90334c..0000000000 --- a/src/Components/Blazor/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Blazor.Build.props +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/Components/Blazor/Build/src/targets/All.targets b/src/Components/Blazor/Build/src/targets/All.targets deleted file mode 100644 index 6c69e85a40..0000000000 --- a/src/Components/Blazor/Build/src/targets/All.targets +++ /dev/null @@ -1,49 +0,0 @@ - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - $(MSBuildThisFileDirectory)..\tools\ - <_BlazorTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">netcoreapp - <_BlazorTasksTFM Condition=" '$(_BlazorTasksTFM)' == ''">netfx - $(BlazorToolsDir)$(_BlazorTasksTFM)\Microsoft.AspNetCore.Blazor.Build.Tasks.dll - - - true - - - true - - - - - - - - - $(AssemblyName).blazor.config - $(TargetDir)$(BlazorMetadataFileName) - - - - <_BlazorConfigContent Include="$(MSBuildProjectFullPath)" /> - <_BlazorConfigContent Include="$(TargetPath)" /> - <_BlazorConfigContent Include="debug:true" Condition="'$(BlazorEnableDebugging)'=='true'" /> - - - - - - - - - - diff --git a/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.props b/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.props deleted file mode 100644 index f49c1f8f2f..0000000000 --- a/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.props +++ /dev/null @@ -1,20 +0,0 @@ - - - - $(MSBuildThisFileDirectory)..\tools\blazor\blazor.webassembly.js - - - - none - --disable-opt unreachablebodies --verbose --strip-security true --exclude-feature com -v false -c link -u link -b true - dist\ - $(BaseBlazorDistPath)_content\ - $(BaseBlazorDistPath)_framework\ - $(BaseBlazorRuntimeOutputPath)_bin\ - $(BaseBlazorRuntimeOutputPath)wasm\ - wwwroot\ - blazor.boot.json - <_BlazorBuiltInBclLinkerDescriptor>$(MSBuildThisFileDirectory)BuiltInBclLinkerDescriptor.xml - - - diff --git a/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets b/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets deleted file mode 100644 index 3c7d126561..0000000000 --- a/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets +++ /dev/null @@ -1,336 +0,0 @@ - - - true - - - - - $(MonoBaseClassLibraryPath) - $(MonoBaseClassLibraryFacadesPath) - $(MonoWasmRuntimePath) - $(MonoWasmFrameworkPath) - - - - - $(DotNetWebAssemblyArtifactsRoot)\wasm-bcl\wasm\ - $(DotNetWebAssemblyBCLPath)\Facades\ - $(DotNetWebAssemblyArtifactsRoot)\builds\debug\ - $(DotNetWebAssemblyArtifactsRoot)\framework\ - - - - - - - - - - - - - - <_BlazorStatisticsOutput Include="@(BlazorOutputWithTargetPath->'%(TargetOutputPath)')" /> - - - - - - - - - - - - - - $(BlazorRuntimeWasmOutputPath)%(FileName)%(Extension) - - - $(BaseBlazorRuntimeOutputPath)%(FileName)%(Extension) - - - - - <_BlazorPackageContentOutput Include="@(BlazorPackageContentFile)" Condition="%(SourcePackage) != ''"> - $(BaseBlazorPackageContentOutputPath)%(SourcePackage)\%(RecursiveDir)\%(Filename)%(Extension) - - - - - - - - - $(IntermediateOutputPath)blazor\ - - - $(BlazorIntermediateOutputPath)linker.descriptor.xml - - <_TypeGranularityLinkerDescriptor>$(BlazorIntermediateOutputPath)linker.typegranularityconfig.xml - - - $(BlazorIntermediateOutputPath)linker/ - - - $(BlazorIntermediateOutputPath)$(BlazorBootJsonName) - - <_BlazorLinkerOutputCache>$(BlazorIntermediateOutputPath)linker.output - - <_BlazorApplicationAssembliesCacheFile>$(BlazorIntermediateOutputPath)unlinked.output - - - - <_WebAssemblyBCLFolder Include=" - $(DotNetWebAssemblyBCLPath); - $(DotNetWebAssemblyBCLFacadesPath); - $(DotNetWebAssemblyFrameworkPath)" /> - - <_WebAssemblyBCLAssembly Include="%(_WebAssemblyBCLFolder.Identity)*.dll" /> - - - - - - <_BlazorManagedRuntimeAssemby Include="@(RuntimeCopyLocalItems)" /> - - - <_BlazorUserRuntimeAssembly Include="@(ReferencePath->WithMetadataValue('CopyLocal', 'true'))" /> - <_BlazorUserRuntimeAssembly Include="@(ReferenceDependencyPaths->WithMetadataValue('CopyLocal', 'true'))" /> - - <_BlazorManagedRuntimeAssemby Include="@(_BlazorUserRuntimeAssembly)" /> - <_BlazorManagedRuntimeAssemby Include="@(IntermediateAssembly)" /> - - - - - - - - - - - <_BlazorCopyLocalPaths Include="@(ReferenceCopyLocalPaths)" /> - <_BlazorCopyLocalPaths Remove="@(_BlazorManagedRuntimeAssemby)" /> - - - true - $(BlazorRuntimeBinOutputPath)%(_BlazorCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension) - %(_BlazorCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension) - - - - true - $(BlazorRuntimeBinOutputPath)%(FileName)%(Extension) - %(FileName)%(Extension) - - - - - - - - - - - - - - - - - <_BlazorRuntimeCopyLocalItems Include="@(RuntimeCopyLocalItems)" /> - - - <_BlazorRuntimeCopyLocalItems IsLinkable="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('System.'))" /> - <_BlazorRuntimeCopyLocalItems IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.'))" /> - <_BlazorRuntimeCopyLocalItems IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.'))" /> - - <_BlazorAssemblyToLink Include="@(_WebAssemblyBCLAssembly)" /> - <_BlazorAssemblyToLink Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' == 'true'" /> - - <_BlazorLinkerRoot Include="@(IntermediateAssembly)" /> - <_BlazorLinkerRoot Include="@(_BlazorUserRuntimeAssembly)" /> - <_BlazorLinkerRoot Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' != 'true'" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_BlazorLinkerAdditionalOptions>-l $(MonoLinkerI18NAssemblies) $(AdditionalMonoLinkerOptions) - - - - <_OldLinkedFile Include="$(BlazorIntermediateLinkerOutputPath)*.dll" /> - <_OldLinkedFile Include="$(BlazorIntermediateLinkerOutputPath)*.pdb" /> - - - - - - - <_DotNetHostDirectory>$(NetCoreRoot) - <_DotNetHostFileName>dotnet - <_DotNetHostFileName Condition=" '$(OS)' == 'Windows_NT' ">dotnet.exe - - - - - - <_LinkerResult Include="$(BlazorIntermediateLinkerOutputPath)*.dll" /> - <_LinkerResult Include="$(BlazorIntermediateLinkerOutputPath)*.pdb" Condition="'$(BlazorEnableDebugging)' == 'true'" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_BlazorRuntimeFile Include="@(BlazorOutputWithTargetPath->WithMetadataValue('BlazorRuntimeFile', 'true'))" /> - - - - - - - - - - - diff --git a/src/Components/Blazor/Build/src/targets/Publish.targets b/src/Components/Blazor/Build/src/targets/Publish.targets deleted file mode 100644 index 7cb7e0ad23..0000000000 --- a/src/Components/Blazor/Build/src/targets/Publish.targets +++ /dev/null @@ -1,70 +0,0 @@ - - - true - $(AssemblyName)\dist\ - - - false - false - false - false - false - true - - - - - - - - - - $(BlazorPublishDistDir)$([System.String]::new(%(TargetPath)).Substring(8)) - - - - <_BlazorGCTPDI Include="%(BlazorOutputWithTargetPath.Identity)"> - $(AssemblyName)\%(TargetOutputPath) - - - - %(TargetPath) - PreserveNewest - - - - - - <_BlazorConfigPath>$(OutDir)$(AssemblyName).blazor.config - - - - <_BlazorPublishConfigContent Include="." /> - <_BlazorPublishConfigContent Include="$(AssemblyName)/" /> - - - - - - - - - - <_StandaloneWebConfigContent Include="$([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)Standalone.Web.config'))"/> - - - - - - - diff --git a/src/Components/Blazor/Build/src/targets/StaticWebAssets.targets b/src/Components/Blazor/Build/src/targets/StaticWebAssets.targets deleted file mode 100644 index d547f500b1..0000000000 --- a/src/Components/Blazor/Build/src/targets/StaticWebAssets.targets +++ /dev/null @@ -1,37 +0,0 @@ - - - - - $(ResolveStaticWebAssetsInputsDependsOn); - _RemoveBlazorCurrentProjectAssetsFromStaticWebAssets; - - - - $(GetCurrentProjectStaticWebAssetsDependsOn); - _RemoveBlazorCurrentProjectAssetsFromStaticWebAssets; - - - - - - - - - - - - - - - <_StandaloneExternalPublishStaticWebAsset Include="@(_ExternalPublishStaticWebAsset)" Condition="'%(RelativePath)' != ''"> - $([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)', '$([MSBuild]::NormalizePath('$([System.Text.RegularExpressions.Regex]::Replace('%(RelativePath)','^wwwroot\\?\/?(.*)','$(BlazorPublishDistDir)$1'))'))')) - - - - - - - - - diff --git a/src/Components/Blazor/Build/test/BindRazorIntegrationTest.cs b/src/Components/Blazor/Build/test/BindRazorIntegrationTest.cs deleted file mode 100644 index 2292df38d8..0000000000 --- a/src/Components/Blazor/Build/test/BindRazorIntegrationTest.cs +++ /dev/null @@ -1,534 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.AspNetCore.Blazor.Build.Test -{ - public class BindRazorIntegrationTest : RazorIntegrationTestBase - { - public BindRazorIntegrationTest(ITestOutputHelper output) - : base(output) - { - } - - internal override bool UseTwoPhaseCompilation => true; - - [Fact] - public void Render_BindToComponent_SpecifiesValue_WithMatchingProperties() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public int Value { get; set; } - - [Parameter] - public Action ValueChanged { get; set; } - } -}")); - - var component = CompileToComponent(@" - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0), - frame => AssertFrame.Attribute(frame, "Value", 42, 1), - frame => AssertFrame.Attribute(frame, "ValueChanged", typeof(Action), 2)); - } - - [Fact] - public void Render_BindToComponent_SpecifiesValue_WithoutMatchingProperties() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase, IComponent - { - Task IComponent.SetParametersAsync(ParameterView parameters) - { - return Task.CompletedTask; - } - } -}")); - - var component = CompileToComponent(@" - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0), - frame => AssertFrame.Attribute(frame, "Value", 42, 1), - frame => AssertFrame.Attribute(frame, "ValueChanged", typeof(EventCallback), 2)); - } - - [Fact] - public void Render_BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public int Value { get; set; } - - [Parameter] - public Action OnChanged { get; set; } - } -}")); - - var component = CompileToComponent(@" - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0), - frame => AssertFrame.Attribute(frame, "Value", 42, 1), - frame => AssertFrame.Attribute(frame, "OnChanged", typeof(Action), 2)); - } - - [Fact] - public void Render_BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase, IComponent - { - Task IComponent.SetParametersAsync(ParameterView parameters) - { - return Task.CompletedTask; - } - } -}")); - - var component = CompileToComponent(@" - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0), - frame => AssertFrame.Attribute(frame, "Value", 42, 1), - frame => AssertFrame.Attribute(frame, "OnChanged", typeof(EventCallback), 2)); - } - - [Fact] - public void Render_BindToElement_WritesAttributes() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - [BindElement(""div"", null, ""myvalue"", ""myevent"")] - public static class BindAttributes - { - } -}")); - - var component = CompileToComponent(@" -
-@code { - public string ParentValue { get; set; } = ""hi""; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "div", 3, 0), - frame => AssertFrame.Attribute(frame, "myvalue", "hi", 1), - frame => AssertFrame.Attribute(frame, "myevent", typeof(EventCallback), 2)); - } - - [Fact] - public void Render_BindToElementWithSuffix_WritesAttributes() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - [BindElement(""div"", ""value"", ""myvalue"", ""myevent"")] - public static class BindAttributes - { - } -}")); - - var component = CompileToComponent(@" -
-@code { - public string ParentValue { get; set; } = ""hi""; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "div", 3, 0), - frame => AssertFrame.Attribute(frame, "myvalue", "hi", 1), - frame => AssertFrame.Attribute(frame, "myevent", typeof(EventCallback), 2)); - } - - [Fact] - public void Render_BindDuplicates_ReportsDiagnostic() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - [BindElement(""div"", ""value"", ""myvalue2"", ""myevent2"")] - [BindElement(""div"", ""value"", ""myvalue"", ""myevent"")] - public static class BindAttributes - { - } -}")); - - // Act - var result = CompileToCSharp(@" -
-@code { - public string ParentValue { get; set; } = ""hi""; -}"); - - // Assert - var diagnostic = Assert.Single(result.Diagnostics); - Assert.Equal("RZ9989", diagnostic.Id); - Assert.Equal( - "The attribute '@bind-value' was matched by multiple bind attributes. Duplicates:" + Environment.NewLine + - "Test.BindAttributes" + Environment.NewLine + - "Test.BindAttributes", - diagnostic.GetMessage()); - } - - [Fact] - public void Render_BuiltIn_BindToInputWithoutType_WritesAttributes() - { - // Arrange - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 3, 0), - frame => AssertFrame.Attribute(frame, "value", "42", 1), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 2)); - } - - [Fact] - public void Render_BuiltIn_BindToInputText_WithFormat_WritesAttributes() - { - // Arrange - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web - -@code { - public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1); -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 4, 0), - frame => AssertFrame.Attribute(frame, "type", "text", 1), - frame => AssertFrame.Attribute(frame, "value", new DateTime(2018, 1, 1).ToString("MM/dd/yyyy"), 2), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 3)); - } - - [Fact] - public void Render_BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes() - { - // Arrange - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web - -@code { - public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1); - - public string Format { get; set; } = ""MM/dd/yyyy""; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 4, 0), - frame => AssertFrame.Attribute(frame, "type", "text", 1), - frame => AssertFrame.Attribute(frame, "value", new DateTime(2018, 1, 1).ToString("MM/dd/yyyy"), 2), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 3)); - } - - [Fact] - public void Render_BuiltIn_BindToInputText_WritesAttributes() - { - // Arrange - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 4, 0), - frame => AssertFrame.Attribute(frame, "type", "text", 1), - frame => AssertFrame.Attribute(frame, "value", "42", 2), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 3)); - } - - [Fact] - public void Render_BuiltIn_BindToInputCheckbox_WritesAttributes() - { - // Arrange - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web - -@code { - public bool Enabled { get; set; } -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 3, 0), - frame => AssertFrame.Attribute(frame, "type", "checkbox", 1), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 3)); - } - - [Fact] - public void Render_BindToElementFallback_WritesAttributes() - { - // Arrange - var component = CompileToComponent(@" - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 4, 0), - frame => AssertFrame.Attribute(frame, "type", "text", 1), - frame => AssertFrame.Attribute(frame, "value", "42", 2), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 3)); - } - - [Fact] - public void Render_BindToElementFallback_WithFormat_WritesAttributes() - { - // Arrange - var component = CompileToComponent(@" - -@code { - public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1); -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 4, 0), - frame => AssertFrame.Attribute(frame, "type", "text", 1), - frame => AssertFrame.Attribute(frame, "value", new DateTime(2018, 1, 1).ToString("MM/dd"), 2), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 3)); - } - - [Fact] // Additional coverage of OrphanTagHelperLoweringPass - public void Render_BindToElementFallback_SpecifiesValueAndChangeEvent_WithCSharpAttribute() - { - // Arrange - var component = CompileToComponent(@" - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 5, 0), - frame => AssertFrame.Attribute(frame, "type", "text", 1), - frame => AssertFrame.Attribute(frame, "visible", 2), - frame => AssertFrame.Attribute(frame, "value", "42", 3), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 4)); - } - - [Fact] // See https://github.com/dotnet/blazor/issues/703 - public void Workaround_703() - { - // Arrange - var component = CompileToComponent(@" - -@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - // - // The workaround for 703 is that the value attribute MUST be after the type - // attribute. - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "input", 5, 0), - frame => AssertFrame.Attribute(frame, "type", "text", 1), - frame => AssertFrame.Attribute(frame, "visible", 2), - frame => AssertFrame.Attribute(frame, "value", "42", 3), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 4)); - } - - [Fact] // Additional coverage of OrphanTagHelperLoweringPass - public void Render_BindToElementFallback_SpecifiesValueAndChangeEvent_BodyContent() - { - // Arrange - var component = CompileToComponent(@" -
- @(42.ToString()) -
-@code { - public int ParentValue { get; set; } = 42; -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "div", 7, 0), - frame => AssertFrame.Attribute(frame, "value", "42", 1), - frame => AssertFrame.Attribute(frame, "onchange", typeof(EventCallback), 2), - frame => AssertFrame.MarkupWhitespace(frame, 3), - frame => AssertFrame.Element(frame, "span", 2, 4), - frame => AssertFrame.Text(frame, "42", 5), - frame => AssertFrame.MarkupWhitespace(frame, 6)); - } - - [Fact] - public void Render_BindFallback_InvalidSyntax_TooManyParts() - { - // Arrange & Act - var generated = CompileToCSharp(@" - -@code { - public string Text { get; set; } = ""text""; -}"); - - // Assert - var diagnostic = Assert.Single(generated.Diagnostics); - Assert.Equal("RZ9991", diagnostic.Id); - } - - [Fact] - public void Render_BindFallback_InvalidSyntax_TrailingDash() - { - // Arrange & Act - var generated = CompileToCSharp(@" - -@code { - public string Text { get; set; } = ""text""; -}"); - - // Assert - var diagnostic = Assert.Single(generated.Diagnostics); - Assert.Equal("RZ9991", diagnostic.Id); - } - } -} diff --git a/src/Components/Blazor/Build/test/BootJsonWriterTest.cs b/src/Components/Blazor/Build/test/BootJsonWriterTest.cs deleted file mode 100644 index 1e2d89b573..0000000000 --- a/src/Components/Blazor/Build/test/BootJsonWriterTest.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.IO; -using System.Text.Json; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Blazor.Build -{ - public class BootJsonWriterTest - { - [Fact] - public async Task ProducesJsonReferencingAssemblyAndDependencies() - { - // Arrange/Act - var assemblyReferences = new string[] { "MyApp.EntryPoint.dll", "System.Abc.dll", "MyApp.ClassLib.dll", }; - using var stream = new MemoryStream(); - - // Act - GenerateBlazorBootJson.WriteBootJson( - stream, - "MyApp.Entrypoint.dll", - assemblyReferences, - linkerEnabled: true); - - // Assert - stream.Position = 0; - using var parsedContent = await JsonDocument.ParseAsync(stream); - var rootElement = parsedContent.RootElement; - Assert.Equal("MyApp.Entrypoint.dll", rootElement.GetProperty("entryAssembly").GetString()); - var assembliesElement = rootElement.GetProperty("assemblies"); - Assert.Equal(assemblyReferences.Length, assembliesElement.GetArrayLength()); - for (var i = 0; i < assemblyReferences.Length; i++) - { - Assert.Equal(assemblyReferences[i], assembliesElement[i].GetString()); - } - Assert.True(rootElement.GetProperty("linkerEnabled").GetBoolean()); - } - } -} diff --git a/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIncrementalismTest.cs b/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIncrementalismTest.cs deleted file mode 100644 index 73d8645029..0000000000 --- a/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIncrementalismTest.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Blazor.Build -{ - public class BuildIncrementalismTest - { - [Fact] - public async Task Build_WithLinker_IsIncremental() - { - // Arrange - using var project = ProjectDirectory.Create("standalone"); - var result = await MSBuildProcessManager.DotnetMSBuild(project); - - Assert.BuildPassed(result); - - var buildOutputDirectory = project.BuildOutputDirectory; - - // Act - var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, project.BuildOutputDirectory); - - // Assert - for (var i = 0; i < 3; i++) - { - result = await MSBuildProcessManager.DotnetMSBuild(project); - Assert.BuildPassed(result); - - var newThumbPrint = FileThumbPrint.CreateFolderThumbprint(project, project.BuildOutputDirectory); - Assert.Equal(thumbPrint.Count, newThumbPrint.Count); - for (var j = 0; j < thumbPrint.Count; j++) - { - Assert.Equal(thumbPrint[j], newThumbPrint[j]); - } - } - } - } -} diff --git a/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs b/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs deleted file mode 100644 index 06c7a5bb1b..0000000000 --- a/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.IO; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Blazor.Build -{ - public class BuildIntegrationTest - { - [Fact] - public async Task Build_WithDefaultSettings_Works() - { - // Arrange - using var project = ProjectDirectory.Create("standalone"); - var result = await MSBuildProcessManager.DotnetMSBuild(project); - - Assert.BuildPassed(result); - - var buildOutputDirectory = project.BuildOutputDirectory; - - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "blazor.webassembly.js"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "wasm", "dotnet.wasm"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "wasm", "dotnet.js"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output. - } - - [Fact] - public async Task Build_Hosted_Works() - { - // Arrange - using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", }); - project.TargetFramework = "net5.0"; - var result = await MSBuildProcessManager.DotnetMSBuild(project); - - Assert.BuildPassed(result); - - var buildOutputDirectory = project.BuildOutputDirectory; - var blazorConfig = Path.Combine(buildOutputDirectory, "standalone.blazor.config"); - Assert.FileExists(result, blazorConfig); - - var path = Path.GetFullPath(Path.Combine(project.SolutionPath, "standalone", "bin", project.Configuration, "netstandard2.1", "standalone.dll")); - Assert.FileContains(result, blazorConfig, path); - Assert.FileDoesNotExist(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll"); - } - - [Fact] - public async Task Build_WithLinkOnBuildDisabled_Works() - { - // Arrange - using var project = ProjectDirectory.Create("standalone"); - project.AddProjectFileContent( -@" - false -"); - - var result = await MSBuildProcessManager.DotnetMSBuild(project); - - Assert.BuildPassed(result); - - var buildOutputDirectory = project.BuildOutputDirectory; - - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "blazor.webassembly.js"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "wasm", "dotnet.wasm"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "wasm", "dotnet.js"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output. - } - - [Fact] - public async Task Build_SatelliteAssembliesAreCopiedToBuildOutput() - { - // Arrange - using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" }); - project.AddProjectFileContent( -@" - - $(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies - - - -"); - - var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore"); - - Assert.BuildPassed(result); - - var buildOutputDirectory = project.BuildOutputDirectory; - - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "classlibrarywithsatelliteassemblies.dll"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output. - - var bootJsonPath = Path.Combine(buildOutputDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\""); - Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\""); - } - - [Fact] - public async Task Build_WithBlazorLinkOnBuildFalse_SatelliteAssembliesAreCopiedToBuildOutput() - { - // Arrange - using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" }); - project.AddProjectFileContent( -@" - - false - $(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies - - - -"); - - var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore"); - - Assert.BuildPassed(result); - - var buildOutputDirectory = project.BuildOutputDirectory; - - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "classlibrarywithsatelliteassemblies.dll"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll"); - Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output. - - var bootJsonPath = Path.Combine(buildOutputDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\""); - Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\""); - } - } -} diff --git a/src/Components/Blazor/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs b/src/Components/Blazor/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs deleted file mode 100644 index 72d082eaf6..0000000000 --- a/src/Components/Blazor/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.IO; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Blazor.Build -{ - public class PublishIntegrationTest - { - [Fact] - public async Task Publish_WithDefaultSettings_Works() - { - // Arrange - using var project = ProjectDirectory.Create("standalone", additionalProjects: new [] { "razorclasslibrary" }); - var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish"); - - Assert.BuildPassed(result); - - var publishDirectory = project.PublishOutputDirectory; - var blazorPublishDirectory = Path.Combine(publishDirectory, Path.GetFileNameWithoutExtension(project.ProjectFilePath)); - - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.webassembly.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.wasm"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output. - - // Verify referenced static web assets - Assert.FileExists(result, blazorPublishDirectory, "dist", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_content", "RazorClassLibrary", "styles.css"); - - // Verify static assets are in the publish directory - Assert.FileExists(result, blazorPublishDirectory, "dist", "index.html"); - - // Verify web.config - Assert.FileExists(result, publishDirectory, "web.config"); - } - - [Fact] - public async Task Publish_WithNoBuild_Works() - { - // Arrange - using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" }); - var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build"); - - Assert.BuildPassed(result); - - result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", "/p:NoBuild=true"); - - Assert.BuildPassed(result); - - var publishDirectory = project.PublishOutputDirectory; - var blazorPublishDirectory = Path.Combine(publishDirectory, Path.GetFileNameWithoutExtension(project.ProjectFilePath)); - - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.webassembly.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.wasm"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output. - - // Verify static assets are in the publish directory - Assert.FileExists(result, blazorPublishDirectory, "dist", "index.html"); - - // Verify static web assets from referenced projects are copied. - // Uncomment once https://github.com/dotnet/aspnetcore/issues/17426 is resolved. - // Assert.FileExists(result, blazorPublishDirectory, "dist", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js"); - // Assert.FileExists(result, blazorPublishDirectory, "dist", "_content", "RazorClassLibrary", "styles.css"); - - // Verify static assets are in the publish directory - Assert.FileExists(result, blazorPublishDirectory, "dist", "index.html"); - - // Verify web.config - Assert.FileExists(result, publishDirectory, "web.config"); - } - - [Fact] - public async Task Publish_WithLinkOnBuildDisabled_Works() - { - // Arrange - using var project = ProjectDirectory.Create("standalone", additionalProjects: new [] { "razorclasslibrary" }); - project.AddProjectFileContent( -@" - false -"); - - var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish"); - - Assert.BuildPassed(result); - - var publishDirectory = project.PublishOutputDirectory; - var blazorPublishDirectory = Path.Combine(publishDirectory, Path.GetFileNameWithoutExtension(project.ProjectFilePath)); - - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.webassembly.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.wasm"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output. - - // Verify static assets are in the publish directory - Assert.FileExists(result, blazorPublishDirectory, "dist", "index.html"); - - // Verify referenced static web assets - Assert.FileExists(result, blazorPublishDirectory, "dist", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_content", "RazorClassLibrary", "styles.css"); - - // Verify web.config - Assert.FileExists(result, publishDirectory, "web.config"); - } - - [Fact] - public async Task Publish_SatelliteAssemblies_AreCopiedToBuildOutput() - { - // Arrange - using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" }); - project.AddProjectFileContent( -@" - - $(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies - - - -"); - - var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/restore"); - - Assert.BuildPassed(result); - - var publishDirectory = project.PublishOutputDirectory; - var blazorPublishDirectory = Path.Combine(publishDirectory, Path.GetFileNameWithoutExtension(project.ProjectFilePath)); - - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output. - - var bootJsonPath = Path.Combine(blazorPublishDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\""); - Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\""); - } - - [Fact] - public async Task Publish_HostedApp_Works() - { - // Arrange - using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", }); - project.TargetFramework = "net5.0"; - var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish"); - - Assert.BuildPassed(result); - - var publishDirectory = project.PublishOutputDirectory; - // Make sure the main project exists - Assert.FileExists(result, publishDirectory, "blazorhosted.dll"); - - var blazorPublishDirectory = Path.Combine(publishDirectory, "standalone"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.webassembly.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.wasm"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output. - - // Verify static assets are in the publish directory - Assert.FileExists(result, blazorPublishDirectory, "dist", "index.html"); - - // Verify static web assets from referenced projects are copied. - Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js"); - Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "styles.css"); - - // Verify static assets are in the publish directory - Assert.FileExists(result, blazorPublishDirectory, "dist", "index.html"); - - // Verify web.config - Assert.FileExists(result, publishDirectory, "web.config"); - - var blazorConfig = Path.Combine(result.Project.DirectoryPath, publishDirectory, "standalone.blazor.config"); - var blazorConfigLines = File.ReadAllLines(blazorConfig); - Assert.Equal(".", blazorConfigLines[0]); - Assert.Equal("standalone/", blazorConfigLines[1]); - } - - [Fact] - public async Task Publish_HostedApp_WithNoBuild_Works() - { - // Arrange - using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", }); - project.TargetFramework = "net5.0"; - var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build"); - - Assert.BuildPassed(result); - - result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", "/p:NoBuild=true"); - - var publishDirectory = project.PublishOutputDirectory; - // Make sure the main project exists - Assert.FileExists(result, publishDirectory, "blazorhosted.dll"); - - var blazorPublishDirectory = Path.Combine(publishDirectory, "standalone"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.boot.json"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "blazor.webassembly.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.wasm"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "wasm", "dotnet.js"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "standalone.dll"); - Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output. - - // Verify static assets are in the publish directory - Assert.FileExists(result, blazorPublishDirectory, "dist", "index.html"); - - // Verify static web assets from referenced projects are copied. - // Uncomment once https://github.com/dotnet/aspnetcore/issues/17426 is resolved. - // Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js"); - // Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "styles.css"); - - // Verify static assets are in the publish directory - Assert.FileExists(result, blazorPublishDirectory, "dist", "index.html"); - - // Verify web.config - Assert.FileExists(result, publishDirectory, "web.config"); - } - } -} diff --git a/src/Components/Blazor/Build/test/ChildContentRazorIntegrationTest.cs b/src/Components/Blazor/Build/test/ChildContentRazorIntegrationTest.cs deleted file mode 100644 index 720c00fe9b..0000000000 --- a/src/Components/Blazor/Build/test/ChildContentRazorIntegrationTest.cs +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.CodeAnalysis.CSharp; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.AspNetCore.Blazor.Build.Test -{ - public class ChildContentRazorIntegrationTest : RazorIntegrationTestBase - { - private readonly CSharpSyntaxTree RenderChildContentComponent = Parse(@" -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -namespace Test -{ - public class RenderChildContent : ComponentBase - { - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, ChildContent); - } - - [Parameter] - public RenderFragment ChildContent { get; set; } - } -} -"); - - private readonly CSharpSyntaxTree RenderChildContentStringComponent = Parse(@" -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -namespace Test -{ - public class RenderChildContentString : ComponentBase - { - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, ChildContent, Value); - } - - [Parameter] - public RenderFragment ChildContent { get; set; } - - [Parameter] - public string Value { get; set; } - } -} -"); - - private readonly CSharpSyntaxTree RenderMultipleChildContent = Parse(@" -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -namespace Test -{ - public class RenderMultipleChildContent : ComponentBase - { - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, Header, Name); - builder.AddContent(1, ChildContent, Value); - builder.AddContent(2, Footer); - } - - [Parameter] - public string Name { get; set; } - - [Parameter] - public RenderFragment Header { get; set; } - - [Parameter] - public RenderFragment ChildContent { get; set; } - - [Parameter] - public RenderFragment Footer { get; set; } - - [Parameter] - public string Value { get; set; } - } -} -"); - - public ChildContentRazorIntegrationTest(ITestOutputHelper output) - : base(output) - { - } - - internal override bool UseTwoPhaseCompilation => true; - - [Fact] - public void Render_BodyChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentComponent); - - var component = CompileToComponent(@" - -
-
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 0), - frame => AssertFrame.Attribute(frame, "ChildContent", 1), - frame => AssertFrame.Markup(frame, "\n
\n", 2)); - } - - [Fact] - public void Render_BodyChildContent_Generic() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentStringComponent); - - var component = CompileToComponent(@" - -
@context.ToLowerInvariant()
-
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContentString", 3, 0), - frame => AssertFrame.Attribute(frame, "Value", "HI", 1), - frame => AssertFrame.Attribute(frame, "ChildContent", 2), - frame => AssertFrame.MarkupWhitespace(frame, 3), - frame => AssertFrame.Element(frame, "div", 2, 4), - frame => AssertFrame.Text(frame, "hi", 5), - frame => AssertFrame.MarkupWhitespace(frame, 6)); - } - - [Fact] - public void Render_ExplicitChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentComponent); - - var component = CompileToComponent(@" - - -
-
-
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 0), - frame => AssertFrame.Attribute(frame, "ChildContent", 1), - frame => AssertFrame.Markup(frame, "\n
\n ", 2)); - } - - [Fact] - public void Render_BodyChildContent_Recursive() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentComponent); - - var component = CompileToComponent(@" - - - -
-
-
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 0), - frame => AssertFrame.Attribute(frame, "ChildContent", 1), - frame => AssertFrame.MarkupWhitespace(frame, 2), - frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 3), - frame => AssertFrame.Attribute(frame, "ChildContent", 4), - frame => AssertFrame.MarkupWhitespace(frame, 6), - frame => AssertFrame.Markup(frame, "\n
\n ", 5)); - } - - [Fact] - public void Render_AttributeChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentComponent); - - var component = CompileToComponent(@" -@{ RenderFragment template = (context) => @
@context.ToLowerInvariant()
; } -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 2), - frame => AssertFrame.Attribute(frame, "ChildContent", 3), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "hi", 1)); - } - - [Fact] - public void Render_AttributeChildContent_RenderFragmentOfString() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentStringComponent); - - var component = CompileToComponent(@" -@{ RenderFragment template = (context) => @
@context.ToLowerInvariant()
; } -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContentString", 3, 2), - frame => AssertFrame.Attribute(frame, "ChildContent", 3), - frame => AssertFrame.Attribute(frame, "Value", "HI", 4), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "hi", 1)); - } - - [Fact] - public void Render_AttributeChildContent_NoArgTemplate() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentComponent); - - var component = CompileToComponent(@" -@{ RenderFragment template = @
@(""HI"".ToLowerInvariant())
; } -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 2), - frame => AssertFrame.Attribute(frame, "ChildContent", 3), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "hi", 1)); - } - - [Fact] - public void Render_AttributeChildContent_IgnoresEmptyBody() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentComponent); - - var component = CompileToComponent(@" -@{ RenderFragment template = (context) => @
@context.ToLowerInvariant()
; } -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 2), - frame => AssertFrame.Attribute(frame, "ChildContent", 3), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "hi", 1)); - } - - [Fact] - public void Render_AttributeChildContent_IgnoresWhitespaceBody() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderChildContentComponent); - - var component = CompileToComponent(@" -@{ RenderFragment template = (context) => @
@context.ToLowerInvariant()
; } - - -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 2), - frame => AssertFrame.Attribute(frame, "ChildContent", 3), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "hi", 1)); - } - - [Fact] - public void Render_MultipleChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderMultipleChildContent); - - var component = CompileToComponent(@" -@{ RenderFragment header = context => @
@context.ToLowerInvariant()
; } - - Some @context.ToLowerInvariant() Content -
Bye!
-
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderMultipleChildContent", 6, 2), - frame => AssertFrame.Attribute(frame, "Name", "billg", 3), - frame => AssertFrame.Attribute(frame, "Header", typeof(RenderFragment), 4), - frame => AssertFrame.Attribute(frame, "Value", "HI", 5), - frame => AssertFrame.Attribute(frame, "ChildContent", typeof(RenderFragment), 6), - frame => AssertFrame.Attribute(frame, "Footer", typeof(RenderFragment), 10), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "billg", 1), - frame => AssertFrame.Text(frame, "Some ", 7), - frame => AssertFrame.Text(frame, "hi", 8), - frame => AssertFrame.Text(frame, " Content", 9), - frame => AssertFrame.Text(frame, "Bye!", 11)); - } - - [Fact] - public void Render_MultipleChildContent_ContextParameterOnComponent() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderMultipleChildContent); - - var component = CompileToComponent(@" - -
@item.ToLowerInvariant()
- Some @Context.ToLowerInvariant() Content -
Bye!
-
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderMultipleChildContent", 6, 0), - frame => AssertFrame.Attribute(frame, "Name", "billg", 1), - frame => AssertFrame.Attribute(frame, "Value", "HI", 2), - frame => AssertFrame.Attribute(frame, "Header", typeof(RenderFragment), 3), - frame => AssertFrame.Attribute(frame, "ChildContent", typeof(RenderFragment), 6), - frame => AssertFrame.Attribute(frame, "Footer", typeof(RenderFragment), 10), - frame => AssertFrame.Element(frame, "div", 2, 4), - frame => AssertFrame.Text(frame, "billg", 5), - frame => AssertFrame.Text(frame, "Some ", 7), - frame => AssertFrame.Text(frame, "hi", 8), - frame => AssertFrame.Text(frame, " Content", 9), - frame => AssertFrame.Text(frame, "Bye!", 11)); - } - - // Verifies that our check for reuse of parameter names isn't too aggressive. - [Fact] - public void Render_MultipleChildContent_ContextParameterOnComponent_SetsSameName() - { - // Arrange - AdditionalSyntaxTrees.Add(RenderMultipleChildContent); - - var component = CompileToComponent(@" - - -
@item.ToLowerInvariant()
- Some @item.ToLowerInvariant() Content -
Bye!
-
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.RenderMultipleChildContent", 6, 0), - frame => AssertFrame.Attribute(frame, "Name", "billg", 1), - frame => AssertFrame.Attribute(frame, "Value", "HI", 2), - frame => AssertFrame.Attribute(frame, "Header", typeof(RenderFragment), 3), - frame => AssertFrame.Attribute(frame, "ChildContent", typeof(RenderFragment), 6), - frame => AssertFrame.Attribute(frame, "Footer", typeof(RenderFragment), 10), - frame => AssertFrame.Element(frame, "div", 2, 4), - frame => AssertFrame.Text(frame, "billg", 5), - frame => AssertFrame.Text(frame, "Some ", 7), - frame => AssertFrame.Text(frame, "hi", 8), - frame => AssertFrame.Text(frame, " Content", 9), - frame => AssertFrame.Text(frame, "Bye!", 11)); - } - } -} diff --git a/src/Components/Blazor/Build/test/ComponentRenderingRazorIntegrationTest.cs b/src/Components/Blazor/Build/test/ComponentRenderingRazorIntegrationTest.cs deleted file mode 100644 index f4a45c7e2f..0000000000 --- a/src/Components/Blazor/Build/test/ComponentRenderingRazorIntegrationTest.cs +++ /dev/null @@ -1,616 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.AspNetCore.Components.Web; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.AspNetCore.Blazor.Build.Test -{ - public class ComponentRenderingRazorIntegrationTest : RazorIntegrationTestBase - { - public ComponentRenderingRazorIntegrationTest(ITestOutputHelper output) - : base(output) - { - } - - internal override bool UseTwoPhaseCompilation => true; - - [Fact] - public void Render_ChildComponent_Simple() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase - { - } -} -")); - - var component = CompileToComponent(@" -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 1, 0)); - } - - [Fact] - public void Render_ChildComponent_WithParameters() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class SomeType - { - } - - public class MyComponent : ComponentBase - { - [Parameter] public int IntProperty { get; set; } - [Parameter] public bool BoolProperty { get; set; } - [Parameter] public string StringProperty { get; set; } - [Parameter] public SomeType ObjectProperty { get; set; } - } -} -")); - - var component = CompileToComponent(@" -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 5, 0), - frame => AssertFrame.Attribute(frame, "IntProperty", 123, 1), - frame => AssertFrame.Attribute(frame, "BoolProperty", true, 2), - frame => AssertFrame.Attribute(frame, "StringProperty", "My string", 3), - frame => - { - AssertFrame.Attribute(frame, "ObjectProperty", 4); - Assert.Equal("Test.SomeType", frame.AttributeValue.GetType().FullName); - }); - } - - [Fact] - public void Render_ChildComponent_TriesToSetNonParameter() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase - { - public int IntProperty { get; set; } - } -} -")); - - var component = CompileToComponent(@" -"); - - // Act - var ex = Assert.Throws(() => GetRenderTree(component)); - - // Assert - Assert.Equal( - "Object of type 'Test.MyComponent' has a property matching the name 'IntProperty', " + - "but it does not have [ParameterAttribute] or [CascadingParameterAttribute] applied.", - ex.Message); - } - - [Fact] - public void Render_ChildComponent_WithExplicitStringParameter() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public string StringProperty { get; set; } - } -} -")); - - var component = CompileToComponent(@" -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 2, 0), - frame => AssertFrame.Attribute(frame, "StringProperty", "42", 1)); - } - - [Fact] - public void Render_ChildComponent_WithNonPropertyAttributes() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase, IComponent - { - Task IComponent.SetParametersAsync(ParameterView parameters) - { - return Task.CompletedTask; - } - } -} -")); - - var component = CompileToComponent(@" -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0), - frame => AssertFrame.Attribute(frame, "some-attribute", "foo", 1), - frame => AssertFrame.Attribute(frame, "another-attribute", "42", 2)); - } - - - [Theory] - [InlineData("e => Increment(e)")] - [InlineData("(e) => Increment(e)")] - [InlineData("@(e => Increment(e))")] - [InlineData("@(e => { Increment(e); })")] - [InlineData("Increment")] - [InlineData("@Increment")] - [InlineData("@(Increment)")] - public void Render_ChildComponent_WithEventHandler(string expression) - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; - -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public Action OnClick { get; set; } - } -} -")); - - var component = CompileToComponent($@" -@using Microsoft.AspNetCore.Components.Web - - -@code {{ - private int counter; - private void Increment(MouseEventArgs e) {{ - counter++; - }} -}}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 2, 0), - frame => - { - AssertFrame.Attribute(frame, "OnClick", 1); - - // The handler will have been assigned to a lambda - var handler = Assert.IsType>(frame.AttributeValue); - Assert.Equal("Test.TestComponent", handler.Target.GetType().FullName); - }); - } - - [Fact] - public void Render_ChildComponent_WithExplicitEventHandler() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using System; -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public Action OnClick { get; set; } - } -} -")); - - var component = CompileToComponent(@" - - -@code { - private int counter; - private void Increment(EventArgs e) { - counter++; - } -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 2, 0), - frame => - { - AssertFrame.Attribute(frame, "OnClick", 1); - - // The handler will have been assigned to a lambda - var handler = Assert.IsType>(frame.AttributeValue); - Assert.Equal("Test.TestComponent", handler.Target.GetType().FullName); - Assert.Equal("Increment", handler.Method.Name); - }); - } - - [Fact] - public void Render_ChildComponent_WithMinimizedBoolAttribute() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public bool BoolProperty { get; set; } - } -}")); - - var component = CompileToComponent(@" -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 2, 0), - frame => AssertFrame.Attribute(frame, "BoolProperty", true, 1)); - } - - [Fact] - public void Render_ChildComponent_WithChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public string MyAttr { get; set; } - - [Parameter] - public RenderFragment ChildContent { get; set; } - } -} -")); - - var component = CompileToComponent(@" -Some textNested text @(""Hello"")"); - - // Act - var frames = GetRenderTree(component); - - // Assert: component frames are correct - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0), - frame => AssertFrame.Attribute(frame, "MyAttr", "abc", 1), - frame => AssertFrame.Attribute(frame, "ChildContent", 2)); - - // Assert: Captured ChildContent frames are correct - var childFrames = GetFrames((RenderFragment)frames[2].AttributeValue); - Assert.Collection( - childFrames.AsEnumerable(), - frame => AssertFrame.Text(frame, "Some text", 3), - frame => AssertFrame.Element(frame, "some-child", 4, 4), - frame => AssertFrame.Attribute(frame, "a", "1", 5), - frame => AssertFrame.Text(frame, "Nested text ", 6), - frame => AssertFrame.Text(frame, "Hello", 7)); - } - - [Fact] - public void Render_ChildComponent_Nested() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public RenderFragment ChildContent { get; set; } - } -} -")); - - var component = CompileToComponent(@" -Some text"); - - // Act - var frames = GetRenderTree(component); - - // Assert: outer component frames are correct - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 2, 0), - frame => AssertFrame.Attribute(frame, "ChildContent", 1)); - - // Assert: first level of ChildContent is correct - // Note that we don't really need the sequence numbers to continue on from the - // sequence numbers at the parent level. All that really matters is that they are - // correct relative to each other (i.e., incrementing) within the nesting level. - // As an implementation detail, it happens that they do follow on from the parent - // level, but we could change that part of the implementation if we wanted. - var innerFrames = GetFrames((RenderFragment)frames[1].AttributeValue).AsEnumerable().ToArray(); - Assert.Collection( - innerFrames, - frame => AssertFrame.Component(frame, "Test.MyComponent", 2, 2), - frame => AssertFrame.Attribute(frame, "ChildContent", 3)); - - // Assert: second level of ChildContent is correct - Assert.Collection( - GetFrames((RenderFragment)innerFrames[1].AttributeValue).AsEnumerable(), - frame => AssertFrame.Text(frame, "Some text", 4)); - } - - [Fact] // https://github.com/dotnet/blazor/issues/773 - public void Regression_773() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; - -namespace Test -{ - public class SurveyPrompt : ComponentBase - { - [Parameter] public string Title { get; set; } - } -} -")); - - var component = CompileToComponent(@" -@page ""/"" - -Test!
"" /> -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.SurveyPrompt", 2, 0), - frame => AssertFrame.Attribute(frame, "Title", "
Test!
", 1)); - } - - - [Fact] - public void Regression_784() - { - // Arrange - - // Act - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web -

-@code { - public string ParentBgColor { get; set; } = ""#FFFFFF""; - - public void OnComponentHover(MouseEventArgs e) - { - } -} -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "p", 3, 0), - frame => AssertFrame.Attribute(frame, "onmouseover", 1), - frame => AssertFrame.Attribute(frame, "style", "background: #FFFFFF;", 2)); - } - - [Fact(Skip = "https://github.com/dotnet/aspnetcore/issues/6185")] - public void Render_Component_HtmlEncoded() - { - // Arrange - var component = CompileToComponent(@"<span>Hi</span>"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Text(frame, "Hi")); - } - - [Fact] - public void Render_Component_HtmlBlockEncoded() - { - // Arrange - var component = CompileToComponent(@"

<span>Hi</span>
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Markup(frame, "
<span>Hi</span>
")); - } - - // Integration test for HTML block rewriting - [Fact(Skip = "https://github.com/dotnet/aspnetcore/issues/6183")] - public void Render_HtmlBlock_Integration() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; -namespace Test -{ - public class MyComponent : ComponentBase - { - [Parameter] - public RenderFragment ChildContent { get; set; } - } -} -")); - - var component = CompileToComponent(@" - - - - -
-
@(""hi"")
-
-
-
@(""hi"")
-
-
- -"); - - // Act - var frames = GetRenderTree(component); - - // Assert: component frames are correct - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "html", 9, 0), - frame => AssertFrame.MarkupWhitespace(frame, 1), - frame => AssertFrame.Markup(frame, "\n ", 2), - frame => AssertFrame.Element(frame, "body", 5, 3), - frame => AssertFrame.MarkupWhitespace(frame, 4), - frame => AssertFrame.Component(frame, "Test.MyComponent", 2, 5), - frame => AssertFrame.Attribute(frame, "ChildContent", 6), - frame => AssertFrame.MarkupWhitespace(frame, 16), - frame => AssertFrame.MarkupWhitespace(frame, 17)); - - // Assert: Captured ChildContent frames are correct - var childFrames = GetFrames((RenderFragment)frames[6].AttributeValue); - Assert.Collection( - childFrames.AsEnumerable(), - frame => AssertFrame.MarkupWhitespace(frame, 7), - frame => AssertFrame.Markup(frame, "
\n ", 8), - frame => AssertFrame.Element(frame, "div", 2, 9), - frame => AssertFrame.Text(frame, "hi", 10), - frame => AssertFrame.MarkupWhitespace(frame, 11), - frame => AssertFrame.Markup(frame, "
\n
\n ", 12), - frame => AssertFrame.Element(frame, "div", 2, 13), - frame => AssertFrame.Text(frame, "hi", 14), - frame => AssertFrame.Markup(frame, "\n
\n ", 15)); - } - - [Fact] - public void RazorTemplate_CanBeUsedFromComponent() - { - // Arrange - AdditionalSyntaxTrees.Add(Parse(@" -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; - -namespace Test -{ - public class Repeater : ComponentBase - { - [Parameter] public int Count { get; set; } - [Parameter] public RenderFragment Template { get; set; } - [Parameter] public string Value { get; set; } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - for (var i = 0; i < Count; i++) - { - builder.AddContent(i, Template, Value); - } - } - } -} -")); - - var component = CompileToComponent(@" -@{ RenderFragment template = (context) => @
@context.ToLower()
; } - -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, "Test.Repeater", 4, 2), - frame => AssertFrame.Attribute(frame, "Count", typeof(int), 3), - frame => AssertFrame.Attribute(frame, "Value", typeof(string), 4), - frame => AssertFrame.Attribute(frame, "Template", typeof(RenderFragment), 5), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "hello, world!", 1), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "hello, world!", 1), - frame => AssertFrame.Element(frame, "div", 2, 0), - frame => AssertFrame.Text(frame, "hello, world!", 1)); - } - } -} diff --git a/src/Components/Blazor/Build/test/DirectiveRazorIntegrationTest.cs b/src/Components/Blazor/Build/test/DirectiveRazorIntegrationTest.cs deleted file mode 100644 index ef46dd1d19..0000000000 --- a/src/Components/Blazor/Build/test/DirectiveRazorIntegrationTest.cs +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.AspNetCore.Blazor.Build.Test -{ - // Integration tests for Blazor's directives - public class DirectiveRazorIntegrationTest : RazorIntegrationTestBase - { - public DirectiveRazorIntegrationTest(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void ComponentsDoNotHaveLayoutAttributeByDefault() - { - // Arrange/Act - var component = CompileToComponent($"Hello"); - - // Assert - Assert.Null(component.GetType().GetCustomAttribute()); - } - - [Fact] - public void SupportsLayoutDeclarations() - { - // Arrange/Act - var testComponentTypeName = FullTypeName(); - var component = CompileToComponent( - $"@layout {testComponentTypeName}\n" + - $"Hello"); - var frames = GetRenderTree(component); - - // Assert - var layoutAttribute = component.GetType().GetCustomAttribute(); - Assert.NotNull(layoutAttribute); - Assert.Equal(typeof(TestLayout), layoutAttribute.LayoutType); - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "Hello")); - } - - [Fact] - public void SupportsImplementsDeclarations() - { - // Arrange/Act - var testInterfaceTypeName = FullTypeName(); - var component = CompileToComponent( - $"@implements {testInterfaceTypeName}\n" + - $"Hello"); - var frames = GetRenderTree(component); - - // Assert - Assert.IsAssignableFrom(component); - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "Hello")); - } - - [Fact] - public void SupportsMultipleImplementsDeclarations() - { - // Arrange/Act - var testInterfaceTypeName = FullTypeName(); - var testInterfaceTypeName2 = FullTypeName(); - var component = CompileToComponent( - $"@implements {testInterfaceTypeName}\n" + - $"@implements {testInterfaceTypeName2}\n" + - $"Hello"); - var frames = GetRenderTree(component); - - // Assert - Assert.IsAssignableFrom(component); - Assert.IsAssignableFrom(component); - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "Hello")); - } - - [Fact] - public void SupportsInheritsDirective() - { - // Arrange/Act - var testBaseClassTypeName = FullTypeName(); - var component = CompileToComponent( - $"@inherits {testBaseClassTypeName}" + Environment.NewLine + - $"Hello"); - var frames = GetRenderTree(component); - - // Assert - Assert.IsAssignableFrom(component); - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "Hello")); - } - - [Fact] - public void SupportsInjectDirective() - { - // Arrange/Act 1: Compilation - var componentType = CompileToComponent( - $"@inject {FullTypeName()} MyService1\n" + - $"@inject {FullTypeName()} MyService2\n" + - $"Hello from @MyService1 and @MyService2").GetType(); - - // Assert 1: Compiled type has correct properties - var propertyFlags = BindingFlags.Instance | BindingFlags.NonPublic; - var injectableProperties = componentType.GetProperties(propertyFlags) - .Where(p => p.GetCustomAttribute() != null); - Assert.Collection(injectableProperties.OrderBy(p => p.Name), - property => - { - Assert.Equal("MyService1", property.Name); - Assert.Equal(typeof(IMyService1), property.PropertyType); - Assert.False(property.GetMethod.IsPublic); - Assert.False(property.SetMethod.IsPublic); - }, - property => - { - Assert.Equal("MyService2", property.Name); - Assert.Equal(typeof(IMyService2), property.PropertyType); - Assert.False(property.GetMethod.IsPublic); - Assert.False(property.SetMethod.IsPublic); - }); - - // Arrange/Act 2: DI-supplied component has correct behavior - var serviceProvider = new TestServiceProvider(); - serviceProvider.AddService(new MyService1Impl()); - serviceProvider.AddService(new MyService2Impl()); - var componentFactory = new ComponentFactory(); - var component = componentFactory.InstantiateComponent(serviceProvider, componentType); - var frames = GetRenderTree(component); - - // Assert 2: Rendered component behaves correctly - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "Hello from "), - frame => AssertFrame.Text(frame, typeof(MyService1Impl).FullName), - frame => AssertFrame.Text(frame, " and "), - frame => AssertFrame.Text(frame, typeof(MyService2Impl).FullName)); - } - - public class TestLayout : IComponent - { - [Parameter] - public RenderFragment Body { get; set; } - - public void Attach(RenderHandle renderHandle) - { - } - - public Task SetParametersAsync(ParameterView parameters) - { - return Task.CompletedTask; - } - } - - public interface ITestInterface { } - - public interface ITestInterface2 { } - - public class TestBaseClass : ComponentBase { } - - public interface IMyService1 { } - public interface IMyService2 { } - public class MyService1Impl : IMyService1 { } - public class MyService2Impl : IMyService2 { } - } -} diff --git a/src/Components/Blazor/Build/test/GenericComponentRazorIntegrationTest.cs b/src/Components/Blazor/Build/test/GenericComponentRazorIntegrationTest.cs deleted file mode 100644 index 7527e83535..0000000000 --- a/src/Components/Blazor/Build/test/GenericComponentRazorIntegrationTest.cs +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.CodeAnalysis.CSharp; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.AspNetCore.Blazor.Build.Test -{ - public class GenericComponentRazorIntegrationTest : RazorIntegrationTestBase - { - private readonly CSharpSyntaxTree GenericContextComponent = Parse(@" -using System; -using System.Collections.Generic; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -namespace Test -{ - public class GenericContext : ComponentBase - { - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - var items = (IReadOnlyList)Items ?? Array.Empty(); - for (var i = 0; i < items.Count; i++) - { - if (ChildContent == null) - { - builder.AddContent(i, Items[i]); - } - else - { - builder.AddContent(i, ChildContent, new Context() { Index = i, Item = items[i], }); - } - } - } - - [Parameter] - public List Items { get; set; } - - [Parameter] - public RenderFragment ChildContent { get; set; } - - public class Context - { - public int Index { get; set; } - public TItem Item { get; set; } - } - } -} -"); - - private readonly CSharpSyntaxTree MultipleGenericParameterComponent = Parse(@" -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -namespace Test -{ - public class MultipleGenericParameter : ComponentBase - { - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - builder.AddContent(0, Item1); - builder.AddContent(1, Item2); - builder.AddContent(2, Item3); - } - - [Parameter] - public TItem1 Item1 { get; set; } - - [Parameter] - public TItem2 Item2 { get; set; } - - [Parameter] - public TItem3 Item3 { get; set; } - } -} -"); - - public GenericComponentRazorIntegrationTest(ITestOutputHelper output) - : base(output) - { - } - - internal override bool UseTwoPhaseCompilation => true; - - [Fact] - public void Render_GenericComponent_WithoutChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(GenericContextComponent); - - var component = CompileToComponent(@" -() { 1, 2, })"" />"); - - // Act - var frames = GetRenderTree(component); - - // Assert - var genericComponentType = component.GetType().Assembly.DefinedTypes - .Where(t => t.Name == "GenericContext`1") - .Single() - .MakeGenericType(typeof(int)); - - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, genericComponentType.FullName, 2, 0), - frame => AssertFrame.Attribute(frame, "Items", typeof(List), 1), - frame => AssertFrame.Text(frame, "1", 0), - frame => AssertFrame.Text(frame, "2", 1)); - } - - [Fact] - public void Render_GenericComponent_WithRef() - { - // Arrange - AdditionalSyntaxTrees.Add(GenericContextComponent); - - var component = CompileToComponent(@" -() { 1, 2, })"" @ref=""_my"" /> - -@code { - GenericContext _my; - void Foo() { GC.KeepAlive(_my); } -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - var genericComponentType = component.GetType().Assembly.DefinedTypes - .Where(t => t.Name == "GenericContext`1") - .Single() - .MakeGenericType(typeof(int)); - - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, genericComponentType.FullName, 3, 0), - frame => AssertFrame.Attribute(frame, "Items", typeof(List), 1), - frame => AssertFrame.ComponentReferenceCapture(frame, 2), - frame => AssertFrame.Text(frame, "1", 0), - frame => AssertFrame.Text(frame, "2", 1)); - } - - [Fact] - public void Render_GenericComponent_WithChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(GenericContextComponent); - - var component = CompileToComponent(@" -() { 1, 2, })""> -
@(context.Item * context.Index)
-
"); - - // Act - var frames = GetRenderTree(component); - - // Assert - var genericComponentType = component.GetType().Assembly.DefinedTypes - .Where(t => t.Name == "GenericContext`1") - .Single() - .MakeGenericType(typeof(int)); - - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, genericComponentType.FullName, 3, 0), - frame => AssertFrame.Attribute(frame, "Items", typeof(List), 1), - frame => AssertFrame.Attribute(frame, "ChildContent", 2), - frame => AssertFrame.MarkupWhitespace(frame, 3), - frame => AssertFrame.Element(frame, "div", 2, 4), - frame => AssertFrame.Text(frame, "0", 5), - frame => AssertFrame.MarkupWhitespace(frame, 6), - frame => AssertFrame.MarkupWhitespace(frame, 3), - frame => AssertFrame.Element(frame, "div", 2, 4), - frame => AssertFrame.Text(frame, "2", 5), - frame => AssertFrame.MarkupWhitespace(frame, 6)); - } - - [Fact] - public void Render_GenericComponent_TypeInference_WithRef() - { - // Arrange - AdditionalSyntaxTrees.Add(GenericContextComponent); - - var component = CompileToComponent(@" -() { 1, 2, })"" @ref=""_my"" /> - -@code { - GenericContext _my; - void Foo() { GC.KeepAlive(_my); } -}"); - - // Act - var frames = GetRenderTree(component); - - // Assert - var genericComponentType = component.GetType().Assembly.DefinedTypes - .Where(t => t.Name == "GenericContext`1") - .Single() - .MakeGenericType(typeof(int)); - - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, genericComponentType.FullName, 3, 0), - frame => AssertFrame.Attribute(frame, "Items", typeof(List), 1), - frame => AssertFrame.ComponentReferenceCapture(frame, 2), - frame => AssertFrame.Text(frame, "1", 0), - frame => AssertFrame.Text(frame, "2", 1)); - } - - [Fact] - public void Render_GenericComponent_TypeInference_WithRef_Recursive() - { - // Arrange - AdditionalSyntaxTrees.Add(GenericContextComponent); - - var assembly = CompileToAssembly("Test.cshtml", @" -@typeparam TItem - - -@code { - [Parameter] public List MyItems { get; set; } - GenericContext _my; - void Foo() { GC.KeepAlive(_my); } -}"); - - var componentType = assembly.Assembly.DefinedTypes - .Where(t => t.Name == "Test`1") - .Single() - .MakeGenericType(typeof(int)); - var component = (IComponent)Activator.CreateInstance(componentType); - - // Act - var frames = GetRenderTree(component); - - // Assert - var genericComponentType = assembly.Assembly.DefinedTypes - .Where(t => t.Name == "GenericContext`1") - .Single() - .MakeGenericType(typeof(int)); - - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, genericComponentType.FullName, 3, 0), - frame => AssertFrame.Attribute(frame, "Items", 1), - frame => AssertFrame.ComponentReferenceCapture(frame, 2)); - } - - [Fact] - public void Render_GenericComponent_TypeInference_WithoutChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(GenericContextComponent); - - var component = CompileToComponent(@" -() { 1, 2, })"" />"); - - // Act - var frames = GetRenderTree(component); - - // Assert - var genericComponentType = component.GetType().Assembly.DefinedTypes - .Where(t => t.Name == "GenericContext`1") - .Single() - .MakeGenericType(typeof(int)); - - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, genericComponentType.FullName, 2, 0), - frame => AssertFrame.Attribute(frame, "Items", typeof(List), 1), - frame => AssertFrame.Text(frame, "1", 0), - frame => AssertFrame.Text(frame, "2", 1)); - } - - [Fact] - public void Render_GenericComponent_MultipleParameters_WithChildContent() - { - // Arrange - AdditionalSyntaxTrees.Add(MultipleGenericParameterComponent); - - var component = CompileToComponent(@" -"); - - // Act - var frames = GetRenderTree(component); - - // Assert - var genericComponentType = component.GetType().Assembly.DefinedTypes - .Where(t => t.Name == "MultipleGenericParameter`3") - .Single() - .MakeGenericType(typeof(int), typeof(string), typeof(long)); - - Assert.Collection( - frames, - frame => AssertFrame.Component(frame, genericComponentType.FullName, 4, 0), - frame => AssertFrame.Attribute(frame, "Item1", 3, 1), - frame => AssertFrame.Attribute(frame, "Item2", "FOO", 2), - frame => AssertFrame.Attribute(frame, "Item3", 39L, 3), - frame => AssertFrame.Text(frame, "3", 0), - frame => AssertFrame.Text(frame, "FOO", 1), - frame => AssertFrame.Text(frame, "39", 2)); - } - } -} diff --git a/src/Components/Blazor/Build/test/Razor/NotFoundProjectItem.cs b/src/Components/Blazor/Build/test/Razor/NotFoundProjectItem.cs deleted file mode 100644 index ec5359db65..0000000000 --- a/src/Components/Blazor/Build/test/Razor/NotFoundProjectItem.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; - -namespace Microsoft.AspNetCore.Razor.Language -{ - /// - /// A that does not exist. - /// - internal class NotFoundProjectItem : RazorProjectItem - { - /// - /// Initializes a new instance of . - /// - /// The base path. - /// The path. - public NotFoundProjectItem(string basePath, string path) - { - BasePath = basePath; - FilePath = path; - } - - /// - public override string BasePath { get; } - - /// - public override string FilePath { get; } - - /// - public override bool Exists => false; - - /// - public override string PhysicalPath => throw new NotSupportedException(); - - /// - public override Stream Read() => throw new NotSupportedException(); - } -} \ No newline at end of file diff --git a/src/Components/Blazor/Build/test/Razor/TestFile.cs b/src/Components/Blazor/Build/test/Razor/TestFile.cs deleted file mode 100644 index 70d5cacd70..0000000000 --- a/src/Components/Blazor/Build/test/Razor/TestFile.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using System.Reflection; -using Xunit; - -namespace Microsoft.AspNetCore.Razor.Language -{ - public class TestFile - { - private TestFile(string resourceName, Assembly assembly) - { - Assembly = assembly; - ResourceName = Assembly.GetName().Name + "." + resourceName.Replace('/', '.').Replace('\\', '.'); - } - - public Assembly Assembly { get; } - - public string ResourceName { get; } - - public static TestFile Create(string resourceName, Type type) - { - return new TestFile(resourceName, type.GetTypeInfo().Assembly); - } - - public static TestFile Create(string resourceName, Assembly assembly) - { - return new TestFile(resourceName, assembly); - } - - public Stream OpenRead() - { - var stream = Assembly.GetManifestResourceStream(ResourceName); - if (stream == null) - { - Assert.True(false, string.Format("Manifest resource: {0} not found", ResourceName)); - } - - return stream; - } - - public bool Exists() - { - var resourceNames = Assembly.GetManifestResourceNames(); - foreach (var resourceName in resourceNames) - { - // Resource names are case-sensitive. - if (string.Equals(ResourceName, resourceName, StringComparison.Ordinal)) - { - return true; - } - } - - return false; - } - - public string ReadAllText() - { - using (var reader = new StreamReader(OpenRead())) - { - // The .Replace() calls normalize line endings, in case you get \n instead of \r\n - // since all the unit tests rely on the assumption that the files will have \r\n endings. - return reader.ReadToEnd().Replace("\r", "").Replace("\n", "\r\n"); - } - } - - /// - /// Saves the file to the specified path. - /// - public void Save(string filePath) - { - var directory = Path.GetDirectoryName(filePath); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - using (var outStream = File.Create(filePath)) - { - using (var inStream = OpenRead()) - { - inStream.CopyTo(outStream); - } - } - } - } -} diff --git a/src/Components/Blazor/Build/test/Razor/TestProject.cs b/src/Components/Blazor/Build/test/Razor/TestProject.cs deleted file mode 100644 index 5f14ef4bed..0000000000 --- a/src/Components/Blazor/Build/test/Razor/TestProject.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; - -namespace Microsoft.AspNetCore.Razor.Language -{ - public static class TestProject - { - public static string GetProjectDirectory(Type type) - { - var solutionDir = GetSolutionRootDirectory("Components"); - - var assemblyName = type.Assembly.GetName().Name; - - var projectDirectory = Path.Combine(solutionDir, "test", assemblyName); - if (!Directory.Exists(projectDirectory)) - { - throw new InvalidOperationException( -$@"Could not locate project directory for type {type.FullName}. -Directory probe path: {projectDirectory}."); - } - - return projectDirectory; - } - - public static string GetSolutionRootDirectory(string solution) - { - var applicationBasePath = AppContext.BaseDirectory; - var directoryInfo = new DirectoryInfo(applicationBasePath); - - do - { - var projectFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{solution}.sln")); - if (projectFileInfo.Exists) - { - return projectFileInfo.DirectoryName; - } - - directoryInfo = directoryInfo.Parent; - } - while (directoryInfo.Parent != null); - - throw new Exception($"Solution file {solution}.sln could not be found in {applicationBasePath} or its parent directories."); - } - } -} diff --git a/src/Components/Blazor/Build/test/Razor/VirtualProjectFileSystem.cs b/src/Components/Blazor/Build/test/Razor/VirtualProjectFileSystem.cs deleted file mode 100644 index 3d694a82d0..0000000000 --- a/src/Components/Blazor/Build/test/Razor/VirtualProjectFileSystem.cs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -namespace Microsoft.AspNetCore.Razor.Language -{ - internal class VirtualRazorProjectFileSystem : RazorProjectFileSystem - { - private readonly DirectoryNode _root = new DirectoryNode("/"); - - public override IEnumerable EnumerateItems(string basePath) - { - basePath = NormalizeAndEnsureValidPath(basePath); - var directory = _root.GetDirectory(basePath); - return directory?.EnumerateItems() ?? Enumerable.Empty(); - } - - [Obsolete("Use GetItem(string path, string fileKind)] instead")] - public override RazorProjectItem GetItem(string path) - { - return GetItem(path, fileKind: null); - } - - public override RazorProjectItem GetItem(string path, string fileKind) - { - // We ignore fileKind here because the _root is pre-filled with project items that already have fileKinds defined. This is - // a unique circumstance where the RazorProjectFileSystem is actually pre-filled with all of its project items on construction. - - path = NormalizeAndEnsureValidPath(path); - return _root.GetItem(path) ?? new NotFoundProjectItem(string.Empty, path); - } - - public void Add(RazorProjectItem projectItem) - { - if (projectItem == null) - { - throw new ArgumentNullException(nameof(projectItem)); - } - - var filePath = NormalizeAndEnsureValidPath(projectItem.FilePath); - _root.AddFile(new FileNode(filePath, projectItem)); - } - - // Internal for testing - [DebuggerDisplay("{Path}")] - internal class DirectoryNode - { - public DirectoryNode(string path) - { - Path = path; - } - - public string Path { get; } - - public List Directories { get; } = new List(); - - public List Files { get; } = new List(); - - public void AddFile(FileNode fileNode) - { - var filePath = fileNode.Path; - if (!filePath.StartsWith(Path, StringComparison.OrdinalIgnoreCase)) - { - var message = "Error"; - throw new InvalidOperationException(message); - } - - // Look for the first / that appears in the path after the current directory path. - var directoryPath = GetDirectoryPath(filePath); - var directory = GetOrAddDirectory(this, directoryPath, createIfNotExists: true); - Debug.Assert(directory != null); - directory.Files.Add(fileNode); - } - - public DirectoryNode GetDirectory(string path) - { - if (!path.StartsWith(Path, StringComparison.OrdinalIgnoreCase)) - { - var message = "Error"; - throw new InvalidOperationException(message); - } - - return GetOrAddDirectory(this, path); - } - - public IEnumerable EnumerateItems() - { - foreach (var file in Files) - { - yield return file.ProjectItem; - } - - foreach (var directory in Directories) - { - foreach (var file in directory.EnumerateItems()) - { - yield return file; - } - } - } - - public RazorProjectItem GetItem(string path) - { - if (!path.StartsWith(Path, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("Error"); - } - - var directoryPath = GetDirectoryPath(path); - var directory = GetOrAddDirectory(this, directoryPath); - if (directory == null) - { - return null; - } - - foreach (var file in directory.Files) - { - var filePath = file.Path; - var directoryLength = directory.Path.Length; - - // path, filePath -> /Views/Home/Index.cshtml - // directory.Path -> /Views/Home/ - // We only need to match the file name portion since we've already matched the directory segment. - if (string.Compare(path, directoryLength, filePath, directoryLength, path.Length - directoryLength, StringComparison.OrdinalIgnoreCase) == 0) - { - return file.ProjectItem; - } - } - - return null; - } - - private static string GetDirectoryPath(string path) - { - // /dir1/dir2/file.cshtml -> /dir1/dir2/ - var fileNameIndex = path.LastIndexOf('/'); - if (fileNameIndex == -1) - { - return path; - } - - return path.Substring(0, fileNameIndex + 1); - } - - private static DirectoryNode GetOrAddDirectory( - DirectoryNode directory, - string path, - bool createIfNotExists = false) - { - Debug.Assert(!string.IsNullOrEmpty(path)); - if (path[path.Length - 1] != '/') - { - path += '/'; - } - - int index; - while ((index = path.IndexOf('/', directory.Path.Length)) != -1 && index != path.Length) - { - var subDirectory = FindSubDirectory(directory, path); - - if (subDirectory == null) - { - if (createIfNotExists) - { - var directoryPath = path.Substring(0, index + 1); // + 1 to include trailing slash - subDirectory = new DirectoryNode(directoryPath); - directory.Directories.Add(subDirectory); - } - else - { - return null; - } - } - - directory = subDirectory; - } - - return directory; - } - - private static DirectoryNode FindSubDirectory(DirectoryNode parentDirectory, string path) - { - for (var i = 0; i < parentDirectory.Directories.Count; i++) - { - // ParentDirectory.Path -> /Views/Home/ - // CurrentDirectory.Path -> /Views/Home/SubDir/ - // Path -> /Views/Home/SubDir/MorePath/File.cshtml - // Each invocation of FindSubDirectory returns the immediate subdirectory along the path to the file. - - var currentDirectory = parentDirectory.Directories[i]; - var directoryPath = currentDirectory.Path; - var startIndex = parentDirectory.Path.Length; - var directoryNameLength = directoryPath.Length - startIndex; - - if (string.Compare(path, startIndex, directoryPath, startIndex, directoryPath.Length - startIndex, StringComparison.OrdinalIgnoreCase) == 0) - { - return currentDirectory; - } - } - - return null; - } - } - - // Internal for testing - [DebuggerDisplay("{Path}")] - internal struct FileNode - { - public FileNode(string path, RazorProjectItem projectItem) - { - Path = path; - ProjectItem = projectItem; - } - - public string Path { get; } - - public RazorProjectItem ProjectItem { get; } - } - } -} diff --git a/src/Components/Blazor/Build/test/Razor/VirtualProjectItem.cs b/src/Components/Blazor/Build/test/Razor/VirtualProjectItem.cs deleted file mode 100644 index 68c135d715..0000000000 --- a/src/Components/Blazor/Build/test/Razor/VirtualProjectItem.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.IO; - -namespace Microsoft.AspNetCore.Razor.Language -{ - internal class VirtualProjectItem : RazorProjectItem - { - private readonly byte[] _content; - - public VirtualProjectItem( - string basePath, - string filePath, - string physicalPath, - string relativePhysicalPath, - string fileKind, - byte[] content) - { - BasePath = basePath; - FilePath = filePath; - PhysicalPath = physicalPath; - RelativePhysicalPath = relativePhysicalPath; - _content = content; - - // Base class will detect based on file-extension. - FileKind = fileKind ?? base.FileKind; - } - - public override string BasePath { get; } - - public override string RelativePhysicalPath { get; } - - public override string FileKind { get; } - - public override string FilePath { get; } - - public override string PhysicalPath { get; } - - public override bool Exists => true; - - public override Stream Read() - { - return new MemoryStream(_content); - } - } -} diff --git a/src/Components/Blazor/Build/test/RazorIntegrationTestBase.cs b/src/Components/Blazor/Build/test/RazorIntegrationTestBase.cs deleted file mode 100644 index 943a658a36..0000000000 --- a/src/Components/Blazor/Build/test/RazorIntegrationTestBase.cs +++ /dev/null @@ -1,542 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.ExceptionServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.CodeGeneration; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Razor; -using Microsoft.Extensions.Logging.Abstractions; -using Xunit; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.AspNetCore.Blazor.Build.Test -{ - public class RazorIntegrationTestBase - { - private static readonly AsyncLocal _output = new AsyncLocal(); - - internal const string ArbitraryWindowsPath = "x:\\dir\\subdir\\Test"; - internal const string ArbitraryMacLinuxPath = "/dir/subdir/Test"; - - // Creating the initial compilation + reading references is on the order of 250ms without caching - // so making sure it doesn't happen for each test. - private static readonly CSharpCompilation BaseCompilation; - - private static CSharpParseOptions CSharpParseOptions { get; } - - static RazorIntegrationTestBase() - { - var referenceAssemblyRoots = new[] - { - typeof(System.Runtime.AssemblyTargetedPatchBandAttribute).Assembly, // System.Runtime - typeof(ComponentBase).Assembly, - typeof(RazorIntegrationTestBase).Assembly, // Reference this assembly, so that we can refer to test component types - }; - - var referenceAssemblies = referenceAssemblyRoots - .SelectMany(assembly => assembly.GetReferencedAssemblies().Concat(new[] { assembly.GetName() })) - .Distinct() - .Select(Assembly.Load) - .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)) - .ToList(); - BaseCompilation = CSharpCompilation.Create( - "TestAssembly", - Array.Empty(), - referenceAssemblies, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - - CSharpParseOptions = new CSharpParseOptions(LanguageVersion.Preview); - } - - public RazorIntegrationTestBase(ITestOutputHelper output) - { - _output.Value = output; - - AdditionalSyntaxTrees = new List(); - AdditionalRazorItems = new List(); - - Configuration = RazorConfiguration.Create(RazorLanguageVersion.Latest, "MVC-3.0", Array.Empty()); - FileKind = FileKinds.Component; // Treat input files as components by default. - FileSystem = new VirtualRazorProjectFileSystem(); - PathSeparator = Path.DirectorySeparatorChar.ToString(); - WorkingDirectory = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ArbitraryWindowsPath : ArbitraryMacLinuxPath; - - // Many of the rendering tests include line endings in the output. - LineEnding = "\n"; - NormalizeSourceLineEndings = true; - - DefaultRootNamespace = "Test"; // Matches the default working directory - DefaultFileName = "TestComponent.cshtml"; - } - - internal List AdditionalRazorItems { get; } - - internal List AdditionalSyntaxTrees { get; } - - internal virtual RazorConfiguration Configuration { get; } - - internal virtual string DefaultRootNamespace { get; } - - internal virtual string DefaultFileName { get; } - - internal virtual bool DesignTime { get; } - - internal virtual string FileKind { get; } - - internal virtual VirtualRazorProjectFileSystem FileSystem { get; } - - // Used to force a specific style of line-endings for testing. This matters - // for the baseline tests that exercise line mappings. Even though we normalize - // newlines for testing, the difference between platforms affects the data through - // the *count* of characters written. - internal virtual string LineEnding { get; } - - internal virtual string PathSeparator { get; } - - internal virtual bool NormalizeSourceLineEndings { get; } - - internal virtual bool UseTwoPhaseCompilation { get; } - - internal virtual string WorkingDirectory { get; } - - // Intentionally private, we don't want tests messing with this because it's fragile. - private RazorProjectEngine CreateProjectEngine(MetadataReference[] references) - { - return RazorProjectEngine.Create(Configuration, FileSystem, b => - { - b.SetRootNamespace(DefaultRootNamespace); - - // Turn off checksums, we're testing code generation. - b.Features.Add(new SuppressChecksum()); - - if (LineEnding != null) - { - b.Phases.Insert(0, new ForceLineEndingPhase(LineEnding)); - } - - // Including MVC here so that we can find any issues that arise from mixed MVC + Components. - Microsoft.AspNetCore.Mvc.Razor.Extensions.RazorExtensions.Register(b); - - // Features that use Roslyn are mandatory for components - Microsoft.CodeAnalysis.Razor.CompilerFeatures.Register(b); - - b.Features.Add(new CompilationTagHelperFeature()); - b.Features.Add(new DefaultMetadataReferenceFeature() - { - References = references, - }); - }); - } - - internal RazorProjectItem CreateProjectItem(string cshtmlRelativePath, string cshtmlContent) - { - var fullPath = WorkingDirectory + PathSeparator + cshtmlRelativePath; - - // FilePaths in Razor are **always** are of the form '/a/b/c.cshtml' - var filePath = cshtmlRelativePath.Replace('\\', '/'); - if (!filePath.StartsWith('/')) - { - filePath = '/' + filePath; - } - - if (NormalizeSourceLineEndings) - { - cshtmlContent = cshtmlContent.Replace("\r", "").Replace("\n", LineEnding); - } - - return new VirtualProjectItem( - WorkingDirectory, - filePath, - fullPath, - cshtmlRelativePath, - FileKind, - Encoding.UTF8.GetBytes(cshtmlContent.TrimStart())); - } - - protected CompileToCSharpResult CompileToCSharp(string cshtmlContent) - { - return CompileToCSharp(DefaultFileName, cshtmlContent); - } - - protected CompileToCSharpResult CompileToCSharp(string cshtmlRelativePath, string cshtmlContent) - { - if (UseTwoPhaseCompilation) - { - // The first phase won't include any metadata references for component discovery. This mirrors - // what the build does. - var projectEngine = CreateProjectEngine(Array.Empty()); - - RazorCodeDocument codeDocument; - foreach (var item in AdditionalRazorItems) - { - // Result of generating declarations - codeDocument = projectEngine.ProcessDeclarationOnly(item); - Assert.Empty(codeDocument.GetCSharpDocument().Diagnostics); - - var syntaxTree = Parse(codeDocument.GetCSharpDocument().GeneratedCode, path: item.FilePath); - AdditionalSyntaxTrees.Add(syntaxTree); - } - - // Result of generating declarations - var projectItem = CreateProjectItem(cshtmlRelativePath, cshtmlContent); - codeDocument = projectEngine.ProcessDeclarationOnly(projectItem); - var declaration = new CompileToCSharpResult - { - BaseCompilation = BaseCompilation.AddSyntaxTrees(AdditionalSyntaxTrees), - CodeDocument = codeDocument, - Code = codeDocument.GetCSharpDocument().GeneratedCode, - Diagnostics = codeDocument.GetCSharpDocument().Diagnostics, - }; - - // Result of doing 'temp' compilation - var tempAssembly = CompileToAssembly(declaration); - - // Add the 'temp' compilation as a metadata reference - var references = BaseCompilation.References.Concat(new[] { tempAssembly.Compilation.ToMetadataReference() }).ToArray(); - projectEngine = CreateProjectEngine(references); - - // Now update the any additional files - foreach (var item in AdditionalRazorItems) - { - // Result of generating declarations - codeDocument = DesignTime ? projectEngine.ProcessDesignTime(item) : projectEngine.Process(item); - Assert.Empty(codeDocument.GetCSharpDocument().Diagnostics); - - // Replace the 'declaration' syntax tree - var syntaxTree = Parse(codeDocument.GetCSharpDocument().GeneratedCode, path: item.FilePath); - AdditionalSyntaxTrees.RemoveAll(st => st.FilePath == item.FilePath); - AdditionalSyntaxTrees.Add(syntaxTree); - } - - // Result of real code generation for the document under test - codeDocument = DesignTime ? projectEngine.ProcessDesignTime(projectItem) : projectEngine.Process(projectItem); - - _output.Value.WriteLine("Use this output when opening an issue"); - _output.Value.WriteLine(string.Empty); - - _output.Value.WriteLine($"## Main source file ({projectItem.FileKind}):"); - _output.Value.WriteLine("```"); - _output.Value.WriteLine(ReadProjectItem(projectItem)); - _output.Value.WriteLine("```"); - _output.Value.WriteLine(string.Empty); - - foreach (var item in AdditionalRazorItems) - { - _output.Value.WriteLine($"### Additional source file ({item.FileKind}):"); - _output.Value.WriteLine("```"); - _output.Value.WriteLine(ReadProjectItem(item)); - _output.Value.WriteLine("```"); - _output.Value.WriteLine(string.Empty); - } - - _output.Value.WriteLine("## Generated C#:"); - _output.Value.WriteLine("```C#"); - _output.Value.WriteLine(codeDocument.GetCSharpDocument().GeneratedCode); - _output.Value.WriteLine("```"); - - return new CompileToCSharpResult - { - BaseCompilation = BaseCompilation.AddSyntaxTrees(AdditionalSyntaxTrees), - CodeDocument = codeDocument, - Code = codeDocument.GetCSharpDocument().GeneratedCode, - Diagnostics = codeDocument.GetCSharpDocument().Diagnostics, - }; - } - else - { - // For single phase compilation tests just use the base compilation's references. - // This will include the built-in Blazor components. - var projectEngine = CreateProjectEngine(BaseCompilation.References.ToArray()); - - var projectItem = CreateProjectItem(cshtmlRelativePath, cshtmlContent); - var codeDocument = DesignTime ? projectEngine.ProcessDesignTime(projectItem) : projectEngine.Process(projectItem); - - // Log the generated code for test results. - _output.Value.WriteLine("Use this output when opening an issue"); - _output.Value.WriteLine(string.Empty); - - _output.Value.WriteLine($"## Main source file ({projectItem.FileKind}):"); - _output.Value.WriteLine("```"); - _output.Value.WriteLine(ReadProjectItem(projectItem)); - _output.Value.WriteLine("```"); - _output.Value.WriteLine(string.Empty); - - _output.Value.WriteLine("## Generated C#:"); - _output.Value.WriteLine("```C#"); - _output.Value.WriteLine(codeDocument.GetCSharpDocument().GeneratedCode); - _output.Value.WriteLine("```"); - - return new CompileToCSharpResult - { - BaseCompilation = BaseCompilation.AddSyntaxTrees(AdditionalSyntaxTrees), - CodeDocument = codeDocument, - Code = codeDocument.GetCSharpDocument().GeneratedCode, - Diagnostics = codeDocument.GetCSharpDocument().Diagnostics, - }; - } - } - - protected CompileToAssemblyResult CompileToAssembly(string cshtmlRelativePath, string cshtmlContent) - { - var cSharpResult = CompileToCSharp(cshtmlRelativePath, cshtmlContent); - return CompileToAssembly(cSharpResult); - } - - protected CompileToAssemblyResult CompileToAssembly(CompileToCSharpResult cSharpResult, bool throwOnFailure = true) - { - if (cSharpResult.Diagnostics.Any()) - { - var diagnosticsLog = string.Join(Environment.NewLine, cSharpResult.Diagnostics.Select(d => d.ToString()).ToArray()); - throw new InvalidOperationException($"Aborting compilation to assembly because RazorCompiler returned nonempty diagnostics: {diagnosticsLog}"); - } - - var syntaxTrees = new[] - { - Parse(cSharpResult.Code), - }; - - var compilation = cSharpResult.BaseCompilation.AddSyntaxTrees(syntaxTrees); - - var diagnostics = compilation - .GetDiagnostics() - .Where(d => d.Severity != DiagnosticSeverity.Hidden); - - if (diagnostics.Any() && throwOnFailure) - { - throw new CompilationFailedException(compilation); - } - else if (diagnostics.Any()) - { - return new CompileToAssemblyResult - { - Compilation = compilation, - Diagnostics = diagnostics, - }; - } - - using (var peStream = new MemoryStream()) - { - compilation.Emit(peStream); - - return new CompileToAssemblyResult - { - Compilation = compilation, - Diagnostics = diagnostics, - Assembly = diagnostics.Any() ? null : Assembly.Load(peStream.ToArray()) - }; - } - } - - protected IComponent CompileToComponent(string cshtmlSource) - { - var assemblyResult = CompileToAssembly(DefaultFileName, cshtmlSource); - - var componentFullTypeName = $"{DefaultRootNamespace}.{Path.GetFileNameWithoutExtension(DefaultFileName)}"; - return CompileToComponent(assemblyResult, componentFullTypeName); - } - - protected IComponent CompileToComponent(CompileToCSharpResult cSharpResult, string fullTypeName) - { - return CompileToComponent(CompileToAssembly(cSharpResult), fullTypeName); - } - - protected IComponent CompileToComponent(CompileToAssemblyResult assemblyResult, string fullTypeName) - { - var componentType = assemblyResult.Assembly.GetType(fullTypeName); - if (componentType == null) - { - throw new XunitException( - $"Failed to find component type '{fullTypeName}'. Found types:" + Environment.NewLine + - string.Join(Environment.NewLine, assemblyResult.Assembly.ExportedTypes.Select(t => t.FullName))); - } - - return (IComponent)Activator.CreateInstance(componentType); - } - - protected static CSharpSyntaxTree Parse(string text, string path = null) - { - return (CSharpSyntaxTree)CSharpSyntaxTree.ParseText(text, CSharpParseOptions, path: path); - } - - protected static string FullTypeName() => typeof(T).FullName.Replace('+', '.'); - - protected RenderTreeFrame[] GetRenderTree(IComponent component) - { - var renderer = new TestRenderer(); - return GetRenderTree(renderer, component); - } - - protected private RenderTreeFrame[] GetRenderTree(TestRenderer renderer, IComponent component) - { - renderer.AttachComponent(component); - var task = renderer.Dispatcher.InvokeAsync(() => component.SetParametersAsync(ParameterView.Empty)); - // we will have to change this method if we add a test that does actual async work. - Assert.True(task.Status.HasFlag(TaskStatus.RanToCompletion) || task.Status.HasFlag(TaskStatus.Faulted)); - if (task.IsFaulted) - { - ExceptionDispatchInfo.Capture(task.Exception.InnerException).Throw(); - } - return renderer.LatestBatchReferenceFrames; - } - - protected ArrayRange GetFrames(RenderFragment fragment) - { - var builder = new RenderTreeBuilder(); - fragment(builder); - return builder.GetFrames(); - } - - protected static void AssertSourceEquals(string expected, CompileToCSharpResult generated) - { - // Normalize the paths inside the expected result to match the OS paths - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var windowsPath = Path.Combine(ArbitraryWindowsPath, generated.CodeDocument.Source.RelativePath).Replace('/', '\\'); - expected = expected.Replace(windowsPath, generated.CodeDocument.Source.FilePath); - } - - expected = expected.Trim(); - Assert.Equal(expected, generated.Code.Trim(), ignoreLineEndingDifferences: true); - } - - private static string ReadProjectItem(RazorProjectItem item) - { - using (var reader = new StreamReader(item.Read())) - { - return reader.ReadToEnd(); - } - } - - protected class CompileToCSharpResult - { - // A compilation that can be used *with* this code to compile an assembly - public Compilation BaseCompilation { get; set; } - public RazorCodeDocument CodeDocument { get; set; } - public string Code { get; set; } - public IEnumerable Diagnostics { get; set; } - } - - protected class CompileToAssemblyResult - { - public Assembly Assembly { get; set; } - public Compilation Compilation { get; set; } - public string VerboseLog { get; set; } - public IEnumerable Diagnostics { get; set; } - } - - protected class TestRenderer : Renderer - { - public TestRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance) - { - } - - public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault(); - - public RenderTreeFrame[] LatestBatchReferenceFrames { get; private set; } - - public void AttachComponent(IComponent component) - => AssignRootComponentId(component); - - protected override void HandleException(Exception exception) - { - ExceptionDispatchInfo.Capture(exception).Throw(); - } - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - { - LatestBatchReferenceFrames = renderBatch.ReferenceFrames.AsEnumerable().ToArray(); - return Task.CompletedTask; - } - } - - private class CompilationFailedException : XunitException - { - public CompilationFailedException(Compilation compilation) - { - Compilation = compilation; - } - - public Compilation Compilation { get; } - - public override string Message - { - get - { - var builder = new StringBuilder(); - builder.AppendLine("Compilation failed: "); - - var diagnostics = Compilation.GetDiagnostics(); - var syntaxTreesWithErrors = new HashSet(); - foreach (var diagnostic in diagnostics) - { - builder.AppendLine(diagnostic.ToString()); - - if (diagnostic.Location.IsInSource) - { - syntaxTreesWithErrors.Add(diagnostic.Location.SourceTree); - } - } - - if (syntaxTreesWithErrors.Any()) - { - builder.AppendLine(); - builder.AppendLine(); - - foreach (var syntaxTree in syntaxTreesWithErrors) - { - builder.AppendLine($"File {syntaxTree.FilePath ?? "unknown"}:"); - builder.AppendLine(syntaxTree.GetText().ToString()); - } - } - - return builder.ToString(); - } - } - } - - private class SuppressChecksum : IConfigureRazorCodeGenerationOptionsFeature - { - public int Order => 0; - - public RazorEngine Engine { get; set; } - - public void Configure(RazorCodeGenerationOptionsBuilder options) - { - options.SuppressChecksum = true; - } - } - - private class ForceLineEndingPhase : RazorEnginePhaseBase - { - public ForceLineEndingPhase(string lineEnding) - { - LineEnding = lineEnding; - } - - public string LineEnding { get; } - - protected override void ExecuteCore(RazorCodeDocument codeDocument) - { - var field = typeof(CodeRenderingContext).GetField("NewLineString", BindingFlags.Static | BindingFlags.NonPublic); - var key = field.GetValue(null); - codeDocument.Items[key] = LineEnding; - } - } - } -} diff --git a/src/Components/Blazor/Build/test/RenderingRazorIntegrationTest.cs b/src/Components/Blazor/Build/test/RenderingRazorIntegrationTest.cs deleted file mode 100644 index 3f380cbc79..0000000000 --- a/src/Components/Blazor/Build/test/RenderingRazorIntegrationTest.cs +++ /dev/null @@ -1,744 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Test.Helpers; -using Microsoft.AspNetCore.Components.Web; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.AspNetCore.Blazor.Build.Test -{ - // Integration tests for the end-to-end of successful Razor compilation of component definitions - // Includes running the component code to verify the output. - public class RenderingRazorIntegrationTest : RazorIntegrationTestBase - { - public RenderingRazorIntegrationTest(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void SupportsPlainText() - { - // Arrange/Act - var component = CompileToComponent("Some plain text"); - var frames = GetRenderTree(component); - - // Assert - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "Some plain text", 0)); - } - - [Fact] - public void SupportsCSharpExpressions() - { - // Arrange/Act - var component = CompileToComponent(@" - @(""Hello"") - @((object)null) - @(123) - @(new object()) - "); - - // Assert - var frames = GetRenderTree(component); - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "Hello", 0), - frame => AssertFrame.MarkupWhitespace(frame, 1), - frame => AssertFrame.TextWhitespace(frame, 2), // @((object)null) - frame => AssertFrame.MarkupWhitespace(frame, 3), - frame => AssertFrame.Text(frame, "123", 4), - frame => AssertFrame.MarkupWhitespace(frame, 5), - frame => AssertFrame.Text(frame, new object().ToString(), 6)); - } - - [Fact] - public void SupportsCSharpFunctionsBlock() - { - // Arrange/Act - var component = CompileToComponent(@" - @foreach(var item in items) { - @item - } - @code { - string[] items = new[] { ""First"", ""Second"", ""Third"" }; - } - "); - - // Assert - var frames = GetRenderTree(component); - Assert.Collection(frames, - frame => AssertFrame.Text(frame, "First", 0), - frame => AssertFrame.Text(frame, "Second", 0), - frame => AssertFrame.Text(frame, "Third", 0)); - } - - [Fact] - public void SupportsElementsWithDynamicContent() - { - // Arrange/Act - var component = CompileToComponent("Hello @(\"there\")"); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "myelem", 3, 0), - frame => AssertFrame.Text(frame, "Hello ", 1), - frame => AssertFrame.Text(frame, "there", 2)); - } - - [Fact] - public void SupportsElementsAsStaticBlock() - { - // Arrange/Act - var component = CompileToComponent("Hello"); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Markup(frame, "Hello", 0)); - } - - [Fact] - public void CreatesSeparateMarkupFrameForEachTopLevelStaticElement() - { - // The JavaScript-side rendering code does not rely on this behavior. It supports - // inserting markup frames with arbitrary markup (e.g., multiple top-level elements - // or none). This test exists only as an observation of the current behavior rather - // than a promise that we never want to change it. - - // Arrange/Act - var component = CompileToComponent( - "@(\"Hi\") a b "); - - // Assert - var frames = GetRenderTree(component); - Assert.Collection( - frames, - frame => AssertFrame.Element(frame, "root", 5, 0), - frame => AssertFrame.Text(frame, "Hi", 1), - frame => AssertFrame.Text(frame, " ", 2), - frame => AssertFrame.Markup(frame, "a ", 3), - frame => AssertFrame.Markup(frame, "b ", 4)); - } - - [Fact] - public void RendersMarkupStringAsMarkupFrame() - { - // Arrange/Act - var component = CompileToComponent( - "@{ var someMarkup = new MarkupString(\"
Hello
\"); }" - + "

@someMarkup

"); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "p", 2, 0), - frame => AssertFrame.Markup(frame, "
Hello
", 1)); - } - - [Fact] - public void SupportsSelfClosingElementsWithDynamicContent() - { - // Arrange/Act - var component = CompileToComponent("Some text so elem isn't at position 0 "); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Text(frame, "Some text so elem isn't at position 0 ", 0), - frame => AssertFrame.Element(frame, "myelem", 2, 1), - frame => AssertFrame.Attribute(frame, "myattr", "val", 2)); - } - - [Fact] - public void SupportsSelfClosingElementsAsStaticBlock() - { - // Arrange/Act - var component = CompileToComponent("Some text so elem isn't at position 0 "); - - // Assert - Assert.Collection( - GetRenderTree(component), - frame => AssertFrame.Markup(frame, "Some text so elem isn't at position 0 ", 0)); - } - - [Fact] - public void SupportsVoidHtmlElements() - { - // Arrange/Act - var component = CompileToComponent("Some text so elem isn't at position 0 "); - - // Assert - Assert.Collection( - GetRenderTree(component), - frame => AssertFrame.Markup(frame, "Some text so elem isn't at position 0 ", 0)); - } - - [Fact] - public void SupportsComments() - { - // Arrange/Act - var component = CompileToComponent("StartEnd"); - var frames = GetRenderTree(component); - - // Assert - Assert.Collection( - frames, - frame => AssertFrame.Markup(frame, "StartEnd", 0)); - } - - [Fact] - public void SupportsAttributesWithLiteralValues() - { - // Arrange/Act - var component = CompileToComponent("@(\"Hello\")"); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "elem", 4, 0), - frame => AssertFrame.Attribute(frame, "attrib-one", "Value 1", 1), - frame => AssertFrame.Attribute(frame, "a2", "v2", 2), - frame => AssertFrame.Text(frame, "Hello", 3)); - } - - [Fact] - public void SupportsAttributesWithStringExpressionValues() - { - // Arrange/Act - var component = CompileToComponent( - "@{ var myValue = \"My string\"; }" - + ""); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", "My string", 1)); - } - - [Fact] - public void SupportsAttributesWithNonStringExpressionValues() - { - // Arrange/Act - var component = CompileToComponent( - "@{ var myValue = 123; }" - + ""); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", "123", 1)); - } - - [Fact] - public void SupportsAttributesWithInterpolatedStringExpressionValues() - { - // Arrange/Act - var component = CompileToComponent( - "@{ var myValue = \"world\"; var myNum=123; }" - + ""); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", "Hello, WORLD with number 246!", 1)); - } - - [Fact] - public void SupportsAttributesWithInterpolatedTernaryExpressionValues() - { - // Arrange/Act - var component = CompileToComponent( - "@{ var myValue = \"world\"; }" - + ""); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "attr", "Hello, world!", 1)); - } - - [Fact] - public void SupportsHyphenedAttributesWithCSharpExpressionValues() - { - // Arrange/Act - var component = CompileToComponent( - "@{ var myValue = \"My string\"; }" - + ""); - - // Assert - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => AssertFrame.Attribute(frame, "abc-def", "My string", 1)); - } - - [Fact] - public void SupportsDataDashAttributes() - { - // Arrange/Act - var component = CompileToComponent(@" -@{ - var myValue = ""Expression value""; -} -"); - - // Assert - Assert.Collection( - GetRenderTree(component), - frame => AssertFrame.Element(frame, "elem", 3, 0), - frame => AssertFrame.Attribute(frame, "data-abc", "Literal value", 1), - frame => AssertFrame.Attribute(frame, "data-def", "Expression value", 2)); - } - - [Fact] - public void SupportsUsingStatements() - { - // Arrange/Act - var component = CompileToComponent( - @"@using System.Collections.Generic - @(typeof(List).FullName)"); - var frames = GetRenderTree(component); - - // Assert - Assert.Collection(frames, - frame => AssertFrame.Text(frame, typeof(List).FullName, 0)); - } - - [Fact] - public async Task SupportsTwoWayBindingForTextboxes() - { - // Arrange/Act - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web - -@code { - public string MyValue { get; set; } = ""Initial value""; -}"); - var myValueProperty = component.GetType().GetProperty("MyValue"); - - var renderer = new TestRenderer(); - - // Assert - EventCallback setter = default; - var frames = GetRenderTree(renderer, component); - Assert.Collection(frames, - frame => AssertFrame.Element(frame, "input", 3, 0), - frame => AssertFrame.Attribute(frame, "value", "Initial value", 1), - frame => - { - AssertFrame.Attribute(frame, "onchange", 2); - setter = Assert.IsType(frame.AttributeValue); - }); - - // Trigger the change event to show it updates the property - // - // This should always complete synchronously. - var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new ChangeEventArgs { Value = "Modified value", })); - Assert.Equal(TaskStatus.RanToCompletion, task.Status); - await task; - - Assert.Equal("Modified value", myValueProperty.GetValue(component)); - } - - [Fact] - public async Task SupportsTwoWayBindingForTextareas() - { - // Arrange/Act - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web - -@code { - public string MyValue { get; set; } = ""Initial value""; -}"); - var myValueProperty = component.GetType().GetProperty("MyValue"); - - var renderer = new TestRenderer(); - - // Assert - EventCallback setter = default; - var frames = GetRenderTree(renderer, component); - Assert.Collection(frames, - frame => AssertFrame.Element(frame, "textarea", 3, 0), - frame => AssertFrame.Attribute(frame, "value", "Initial value", 1), - frame => - { - AssertFrame.Attribute(frame, "onchange", 2); - setter = Assert.IsType(frame.AttributeValue); - }); - - // Trigger the change event to show it updates the property - // - // This should always complete synchronously. - var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new ChangeEventArgs { Value = "Modified value", })); - Assert.Equal(TaskStatus.RanToCompletion, task.Status); - await task; - - Assert.Equal("Modified value", myValueProperty.GetValue(component)); - } - - [Fact] - public async Task SupportsTwoWayBindingForDateValues() - { - // Arrange/Act - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web - -@code { - public DateTime MyDate { get; set; } = new DateTime(2018, 3, 4, 1, 2, 3); -}"); - var myDateProperty = component.GetType().GetProperty("MyDate"); - - var renderer = new TestRenderer(); - - // Assert - EventCallback setter = default; - var frames = GetRenderTree(renderer, component); - Assert.Collection(frames, - frame => AssertFrame.Element(frame, "input", 3, 0), - frame => AssertFrame.Attribute(frame, "value", new DateTime(2018, 3, 4, 1, 2, 3).ToString(), 1), - frame => - { - AssertFrame.Attribute(frame, "onchange", 2); - setter = Assert.IsType(frame.AttributeValue); - }); - - // Trigger the change event to show it updates the property - // Trigger the change event to show it updates the property - // - // This should always complete synchronously. - var newDateValue = new DateTime(2018, 3, 5, 4, 5, 6); - var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new ChangeEventArgs { Value = newDateValue.ToString(), })); - Assert.Equal(TaskStatus.RanToCompletion, task.Status); - await task; - - Assert.Equal(newDateValue, myDateProperty.GetValue(component)); - } - - [Fact] - public async Task SupportsTwoWayBindingForDateValuesWithFormatString() - { - // Arrange/Act - var testDateFormat = "ddd yyyy-MM-dd"; - var component = CompileToComponent($@" -@using Microsoft.AspNetCore.Components.Web - -@code {{ - public DateTime MyDate {{ get; set; }} = new DateTime(2018, 3, 4); -}}"); - var myDateProperty = component.GetType().GetProperty("MyDate"); - - var renderer = new TestRenderer(); - - // Assert - EventCallback setter = default; - var frames = GetRenderTree(renderer, component); - Assert.Collection(frames, - frame => AssertFrame.Element(frame, "input", 3, 0), - frame => AssertFrame.Attribute(frame, "value", new DateTime(2018, 3, 4).ToString(testDateFormat), 1), - frame => - { - AssertFrame.Attribute(frame, "onchange", 2); - setter = Assert.IsType(frame.AttributeValue); - }); - - // Trigger the change event to show it updates the property - // - // This should always complete synchronously. - var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new ChangeEventArgs { Value = new DateTime(2018, 3, 5).ToString(testDateFormat), })); - Assert.Equal(TaskStatus.RanToCompletion, task.Status); - await task; - - Assert.Equal(new DateTime(2018, 3, 5), myDateProperty.GetValue(component)); - } - - [Fact] // In this case, onclick is just a normal HTML attribute - public void SupportsEventHandlerWithString() - { - // Arrange - var component = CompileToComponent(@" -", 0)); - } - - [Fact] - public void SupportsEventHandlerWithLambda() - { - // Arrange - var component = CompileToComponent(@" -@using Microsoft.AspNetCore.Components.Web -