// 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 Microsoft.AspNetCore.Blazor.Components; using Microsoft.AspNetCore.Blazor.Layouts; using Microsoft.AspNetCore.Blazor.Test.Helpers; using Xunit; namespace Microsoft.AspNetCore.Blazor.Build.Test { // Integration tests for Blazor's directives public class DirectiveRazorIntegrationTest : RazorIntegrationTestBase { [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 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 | 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(serviceProvider); var component = componentFactory.InstantiateComponent(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 : ILayoutComponent { public RenderFragment Body { get; set; } public void Init(RenderHandle renderHandle) { } public void SetParameters(ParameterCollection parameters) { } } public interface ITestInterface { } public class TestBaseClass : BlazorComponent { } public interface IMyService1 { } public interface IMyService2 { } public class MyService1Impl : IMyService1 { } public class MyService2Impl : IMyService2 { } } }