public void Render_AttributeChildContent_IgnoresEmptyBody() { // Arrange AdditionalSyntaxTrees.Add(RenderChildContentComponent); var component = CompileToComponent(@" @addTagHelper *, TestAssembly @{ RenderFragment<string> template = (context) => @<div>@context.ToLowerInvariant()</div>; } <RenderChildContent ChildContent=""@template(""HI"")""></RenderChildContent>"); // Act var frames = GetRenderTree(component); // Assert Assert.Collection( frames, frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 2), frame => AssertFrame.Attribute(frame, RenderTreeBuilder.ChildContent, 3), frame => AssertFrame.Element(frame, "div", 2, 0), frame => AssertFrame.Text(frame, "hi", 1)); }
public void Render_BodyChildContent() { // Arrange AdditionalSyntaxTrees.Add(RenderChildContentComponent); var component = CompileToComponent(@" @addTagHelper *, TestAssembly <RenderChildContent> <div></div> </RenderChildContent>"); // Act var frames = GetRenderTree(component); // Assert Assert.Collection( frames, frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 0), frame => AssertFrame.Attribute(frame, RenderTreeBuilder.ChildContent, 1), frame => AssertFrame.Markup(frame, "\n <div></div>\n", 2)); }
public void Template_ExplicitExpressionInComponentAttribute_CreatesDiagnostic() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Components; namespace Test { public class MyComponent : ComponentBase { } } ")); // Act var generated = CompileToCSharp(@"<MyComponent attr=""@(@<div></div>)"" />"); // Assert var diagnostic = Assert.Single(generated.Diagnostics); Assert.Equal("BL9994", diagnostic.Id); }
public void Render_AttributeChildContent_NoArgTemplate() { // Arrange AdditionalSyntaxTrees.Add(RenderChildContentComponent); var component = CompileToComponent(@" @addTagHelper *, TestAssembly @{ RenderFragment template = @<div>@(""HI"".ToLowerInvariant())</div>; } <RenderChildContent ChildContent=""@template"" />"); // Act var frames = GetRenderTree(component); // Assert Assert.Collection( frames, frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 2), frame => AssertFrame.Attribute(frame, RenderTreeBuilder.ChildContent, 3), frame => AssertFrame.Element(frame, "div", 2, 0), frame => AssertFrame.Text(frame, "hi", 1)); }
public void Render_AttributeChildContent_RenderFragmentOfString() { // Arrange AdditionalSyntaxTrees.Add(RenderChildContentStringComponent); var component = CompileToComponent(@" @{ RenderFragment<string> template = (context) => @<div>@context.ToLowerInvariant()</div>; } <RenderChildContentString ChildContent=""@template"" Value=""HI"" />"); // Act var frames = GetRenderTree(component); // Assert Assert.Collection( frames, frame => AssertFrame.Component(frame, "Test.RenderChildContentString", 3, 2), frame => AssertFrame.Attribute(frame, RenderTreeBuilder.ChildContent, 3), frame => AssertFrame.Attribute(frame, "Value", "HI", 4), frame => AssertFrame.Element(frame, "div", 2, 0), frame => AssertFrame.Text(frame, "hi", 1)); }
public void Render_ChildComponent_WithChildContent() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor; using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class MyComponent : BlazorComponent { public string MyAttr { get; set; } public RenderFragment ChildContent { get; set; } } } ")); var component = CompileToComponent(@" @addTagHelper *, TestAssembly <MyComponent MyAttr=""abc"">Some text<some-child a='1'>Nested text</some-child></MyComponent>"); // 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, RenderTreeBuilder.ChildContent, 2)); // Assert: Captured ChildContent frames are correct var childFrames = GetFrames((RenderFragment)frames[2].AttributeValue); Assert.Collection( childFrames, frame => AssertFrame.Text(frame, "Some text", 3), frame => AssertFrame.Element(frame, "some-child", 3, 4), frame => AssertFrame.Attribute(frame, "a", "1", 5), frame => AssertFrame.Text(frame, "Nested text", 6)); }
public void RejectsTagHelperDirectives() { // Arrange/Act AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Components; namespace Test { public class MyComponent : ComponentBase { } } ")); var result = CompileToCSharp(@" @addTagHelper *, TestAssembly @tagHelperPrefix th <MyComponent /> "); // Assert Assert.Collection(result.Diagnostics, item => { Assert.Equal("RZ9978", item.Id); Assert.Equal("The directives @addTagHelper, @removeTagHelper and @tagHelperPrefix are not valid in a component document. " + "Use '@using <namespace>' directive instead.", item.GetMessage(CultureInfo.CurrentCulture)); Assert.Equal(0, item.Span.LineIndex); Assert.Equal(0, item.Span.CharacterIndex); }, item => { Assert.Equal("RZ9978", item.Id); Assert.Equal("The directives @addTagHelper, @removeTagHelper and @tagHelperPrefix are not valid in a component document. " + "Use '@using <namespace>' directive instead.", item.GetMessage(CultureInfo.CurrentCulture)); Assert.Equal(1, item.Span.LineIndex); Assert.Equal(0, item.Span.CharacterIndex); }); }
public void ComponentDiscovery_CanFindComponent_WithNamespace_DefinedinCSharp() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor.Components; namespace Test.AnotherNamespace { public class MyComponent : BlazorComponent { } } ")); // Act var result = CompileToCSharp("@addTagHelper *, TestAssembly"); // Assert var bindings = result.CodeDocument.GetTagHelperContext(); Assert.Single(bindings.TagHelpers, t => t.Name == "Test.AnotherNamespace.MyComponent"); }
public void ChildContent_ExplicitChildContent_UnrecogizedContent_ProducesDiagnostic() { // Arrange AdditionalSyntaxTrees.Add(RenderChildContentComponent); // Act var generated = CompileToCSharp(@" <RenderChildContent> <ChildContent> </ChildContent> @somethingElse </RenderChildContent>"); // Assert var diagnostic = Assert.Single(generated.Diagnostics); Assert.Same(ComponentDiagnosticFactory.ChildContentMixedWithExplicitChildContent.Id, diagnostic.Id); Assert.Equal( "Unrecognized child content inside component 'RenderChildContent'. The component 'RenderChildContent' accepts " + "child content through the following top-level items: 'ChildContent'.", diagnostic.GetMessage()); }
public void Render_ExplicitChildContent() { // Arrange AdditionalSyntaxTrees.Add(RenderChildContentComponent); var component = CompileToComponent(@" <RenderChildContent> <ChildContent> <div></div> </ChildContent> </RenderChildContent>"); // 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 <div></div>\n ", 2)); }
public void BindToComponent_TypeChecked_WithMatchingProperties() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using System; using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class MyComponent : BlazorComponent { [Parameter] int Value { get; set; } [Parameter] Action<int> ValueChanged { get; set; } } }")); // Act var generated = CompileToCSharp(@" @addTagHelper *, TestAssembly <MyComponent bind-Value=""ParentValue"" /> @functions { public string ParentValue { get; set; } = ""42""; }"); // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); var assembly = CompileToAssembly(generated, throwOnFailure: false); // This has some errors Assert.Collection( assembly.Diagnostics.OrderBy(d => d.Id), d => Assert.Equal("CS0029", d.Id), d => Assert.Equal("CS1503", d.Id)); }
public void ComponentDiscovery_CanFindComponent_DefinedinCSharp() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Components; namespace Test { public class MyComponent : ComponentBase { } } ")); // Act var result = CompileToCSharp(string.Empty); // Assert var bindings = result.CodeDocument.GetTagHelperContext(); Assert.Contains(bindings.TagHelpers, t => t.Name == "Test.MyComponent"); }
public void Template_ImplicitExpressionInComponentAttribute_CreatesDiagnostic() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Components; namespace Test { public class MyComponent : ComponentBase { } } ")); // Act var generated = CompileToCSharp(@"<MyComponent attr=""@<div></div>"" />", throwOnFailure: false); // Assert Assert.Collection( generated.Diagnostics, d => Assert.Equal("RZ9986", d.Id), d => Assert.Equal("RZ1005", d.Id)); }
public void BodyAndExplicitChildContent() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor; using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class MyComponent : BlazorComponent { [Parameter] RenderFragment<string> Header { get; set; } [Parameter] RenderFragment ChildContent { get; set; } [Parameter] RenderFragment Footer { get; set; } } } ")); // Act var generated = CompileToCSharp(@" @addTagHelper *, TestAssembly @{ RenderFragment<string> header = (context) => @<div>@context.ToLowerInvariant()</div>; } <MyComponent Header=@header> <ChildContent>Some Content</ChildContent> <Footer>Bye!</Footer> </MyComponent>"); // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); CompileToAssembly(generated); }
public void RazorTemplate_FollowedByComponent() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class MyComponent : BlazorComponent { [Parameter] string Name { get; set; } } } ")); // Act var generated = CompileToCSharp(@" @addTagHelper ""*, TestAssembly"" @{ RenderFragment<Person> p = (person) => @<div><MyComponent Name=""@person.Name""/></div>; } <MyComponent> @(""hello, world!"") </MyComponent> @functions { class Person { public string Name { get; set; } } }"); // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); CompileToAssembly(generated); }
[Fact] // https://github.com/aspnet/Blazor/issues/772 public void Regression_772() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class SurveyPrompt : BlazorComponent { [Parameter] private string Title { get; set; } } } ")); // Act var generated = CompileToCSharp(@" @addTagHelper *, TestAssembly @page ""/"" <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="" "); // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); // This has some errors Assert.Collection( generated.Diagnostics.OrderBy(d => d.Id), d => Assert.Equal("RZ1034", d.Id), d => Assert.Equal("RZ1035", d.Id)); }
private IReadOnlyList <TagHelperDescriptor> GetComponents() { AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Components; namespace Test { public class Counter : ComponentBase { [Parameter] public int IncrementAmount { get; set; } } public class GridTable : ComponentBase { [Parameter] public RenderFragment ChildContent { get; set; } } public class GridRow : ComponentBase { [Parameter] public RenderFragment ChildContent { get; set; } } public class GridCell : ComponentBase { [Parameter] public RenderFragment ChildContent { get; set; } } } ")); var generated = CompileToCSharp("Test.razor", string.Empty, throwOnFailure: false, fileKind: FileKinds.Component); var tagHelpers = generated.CodeDocument.GetTagHelperContext().TagHelpers; return(tagHelpers); }
public void Render_GenericComponent_TypeInference_WithRef_Recursive() { // Arrange AdditionalSyntaxTrees.Add(GenericContextComponent); var assembly = CompileToAssembly("Test.cshtml", @" @addTagHelper *, TestAssembly @typeparam TItem <GenericContext Items=""@MyItems"" ref=""_my"" /> @functions { [Parameter] List<TItem> MyItems { get; set; } GenericContext<TItem> _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)); }
public void Render_BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using System; using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class MyComponent : BlazorComponent { [Parameter] int Value { get; set; } [Parameter] Action<int> OnChanged { get; set; } } }")); var component = CompileToComponent(@" @addTagHelper *, TestAssembly <MyComponent bind-Value-OnChanged=""ParentValue"" /> @functions { 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 <int>), 2)); }
public void ChildComponent_WithParameters() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class SomeType { } public class MyComponent : BlazorComponent { [Parameter] int IntProperty { get; set; } [Parameter] bool BoolProperty { get; set; } [Parameter] string StringProperty { get; set; } [Parameter] SomeType ObjectProperty { get; set; } } } ")); // Act var generated = CompileToCSharp(@" @addTagHelper *, TestAssembly <MyComponent IntProperty=""123"" BoolProperty=""true"" StringProperty=""My string"" ObjectProperty=""new SomeType()""/>"); // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); CompileToAssembly(generated); }
public void ChildComponent_WithNonPropertyAttributes() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class MyComponent : BlazorComponent { } } ")); // Act var generated = CompileToCSharp(@" @addTagHelper *, TestAssembly <MyComponent some-attribute=""foo"" another-attribute=""@(43.ToString())""/>"); // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); CompileToAssembly(generated); }
public void Render_GenericComponent_WithoutChildContent() { // Arrange AdditionalSyntaxTrees.Add(GenericContextComponent); var component = CompileToComponent(@" <GenericContext TItem=int Items=""@(new List<int>() { 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 <int>), 1), frame => AssertFrame.Text(frame, "1", 0), frame => AssertFrame.Text(frame, "2", 1)); }
public void ChildComponent_WithExplicitEventHandler() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using System; using Microsoft.AspNetCore.Blazor; using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class MyComponent : BlazorComponent { [Parameter] Action<UIEventArgs> OnClick { get; set; } } } ")); // Act var generated = CompileToCSharp(@" @addTagHelper *, TestAssembly @using Microsoft.AspNetCore.Blazor <MyComponent OnClick=""@Increment""/> @functions { private int counter; private void Increment(UIEventArgs e) { counter++; } }"); // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); CompileToAssembly(generated); }
public void Component_StartAndEndTagCaseMismatch_ReportsError() { // Arrange & Act AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Components; namespace Test { public class MyComponent : ComponentBase { } } ")); var generated = CompileToCSharp(@" <MyComponent></mycomponent>"); // Assert var diagnostic = Assert.Single(generated.Diagnostics); Assert.Equal("RZ10013", diagnostic.Id); Assert.Equal( "The start tag name 'MyComponent' does not match the end tag name 'mycomponent'. Components must have matching start and end tag names (case-sensitive).", diagnostic.GetMessage(CultureInfo.CurrentCulture)); }
public void ChildComponent_Simple() { // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor.Components; namespace Test { public class MyComponent : BlazorComponent { } } ")); // Act var generated = CompileToCSharp(@" @addTagHelper *, TestAssembly <MyComponent />"); // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); CompileToAssembly(generated); }
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(ParameterCollection parameters) { return Task.CompletedTask; } } }")); var component = CompileToComponent(@" @addTagHelper *, TestAssembly <MyComponent bind-Value=""ParentValue"" /> @functions { 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 <UIChangeEventArgs>), 2)); }
public void Render_BodyChildContent_Generic() { // Arrange AdditionalSyntaxTrees.Add(RenderChildContentStringComponent); var component = CompileToComponent(@" <RenderChildContentString Value=""HI""> <div>@context.ToLowerInvariant()</div> </RenderChildContentString>"); // 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)); }
protected CompileToCSharpResult CompileToCSharp(string cshtmlRelativePath, string cshtmlContent, bool throwOnFailure = true, string fileKind = null) { if (DeclarationOnly && DesignTime) { throw new InvalidOperationException($"{nameof(DeclarationOnly)} cannot be used with {nameof(DesignTime)}."); } if (DeclarationOnly && UseTwoPhaseCompilation) { throw new InvalidOperationException($"{nameof(DeclarationOnly)} cannot be used with {nameof(UseTwoPhaseCompilation)}."); } if (UseTwoPhaseCompilation) { // The first phase won't include any metadata references for component discovery. This mirrors // what the build does. var projectEngine = CreateProjectEngine(RazorConfiguration.Default, Array.Empty <MetadataReference>()); 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, fileKind); 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, throwOnFailure); // Add the 'temp' compilation as a metadata reference var references = BaseCompilation.References.Concat(new[] { tempAssembly.Compilation.ToMetadataReference() }).ToArray(); projectEngine = CreateProjectEngine(RazorConfiguration.Default, references); // Now update the any additional files foreach (var item in AdditionalRazorItems) { // Result of generating definition 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); 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 components. var projectEngine = CreateProjectEngine(Configuration, BaseCompilation.References.ToArray()); var projectItem = CreateProjectItem(cshtmlRelativePath, cshtmlContent, fileKind); RazorCodeDocument codeDocument; if (DeclarationOnly) { codeDocument = projectEngine.ProcessDeclarationOnly(projectItem); } else { codeDocument = DesignTime ? projectEngine.ProcessDesignTime(projectItem) : projectEngine.Process(projectItem); } return(new CompileToCSharpResult { BaseCompilation = BaseCompilation.AddSyntaxTrees(AdditionalSyntaxTrees), CodeDocument = codeDocument, Code = codeDocument.GetCSharpDocument().GeneratedCode, Diagnostics = codeDocument.GetCSharpDocument().Diagnostics, }); } }
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(@" <html> <head><meta><meta></head> <body> <MyComponent> <div><span></span><span></span></div> <div>@(""hi"")</div> <div><span></span><span></span></div> <div></div> <div>@(""hi"")</div> <div></div> </MyComponent> </body> </html>"); // 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, "<head><meta><meta></head>\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, "<div><span></span><span></span></div>\n ", 8), frame => AssertFrame.Element(frame, "div", 2, 9), frame => AssertFrame.Text(frame, "hi", 10), frame => AssertFrame.MarkupWhitespace(frame, 11), frame => AssertFrame.Markup(frame, "<div><span></span><span></span></div>\n <div></div>\n ", 12), frame => AssertFrame.Element(frame, "div", 2, 13), frame => AssertFrame.Text(frame, "hi", 14), frame => AssertFrame.Markup(frame, "\n <div></div>\n ", 15)); }
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 <MetadataReference>()); 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, }); } }