Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sections support #46727

Merged
merged 34 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
89c686d
sections support
surayya-MS Feb 17, 2023
7e99bde
change SecionsTest
surayya-MS Feb 17, 2023
cbb63aa
fix
surayya-MS Feb 17, 2023
397b91a
use Browser.Exists in tests; move code block to the end of .razor file
surayya-MS Feb 20, 2023
0e7d9c5
E2E tests
surayya-MS Feb 21, 2023
269b8d4
use private fields for buttons in tests; use "-" instead of "_" fir ids
surayya-MS Feb 21, 2023
85f3a7c
support changing IsDefaultContent; fix tests
surayya-MS Feb 22, 2023
ebca897
fix
surayya-MS Feb 23, 2023
32fb842
Merge branch 'main' into sectionsSupport
surayya-MS Feb 23, 2023
85b8ec6
use object SectionId instead of string Name
surayya-MS Feb 23, 2023
435716a
fix
surayya-MS Feb 23, 2023
4cca921
Merge branch 'main' into sectionsSupport
surayya-MS Feb 23, 2023
c42520a
Update src/Components/Components/src/Sections/SectionContent.cs
surayya-MS Feb 24, 2023
d3352be
fix
surayya-MS Feb 28, 2023
495bff4
Update src/Components/test/E2ETest/Tests/SectionsTest.cs
surayya-MS Mar 1, 2023
4742a2d
Update src/Components/Web/src/Head/HeadOutlet.cs
surayya-MS Mar 1, 2023
7323ca1
Update src/Components/Components/src/Sections/SectionOutlet.cs
surayya-MS Mar 1, 2023
b7be8b4
Update src/Components/Components/src/Sections/SectionContent.cs
surayya-MS Mar 1, 2023
cb0d2e3
Update src/Components/Components/src/Sections/SectionOutlet.cs
surayya-MS Mar 1, 2023
52bc8d9
fix
surayya-MS Mar 1, 2023
e21ae58
Merge branch 'sectionsSupport' of https://github.com/surayya-MS/aspne…
surayya-MS Mar 1, 2023
ae3171e
fix
surayya-MS Mar 2, 2023
35d13b9
fix
surayya-MS Mar 6, 2023
275100b
change exceptions messages in SectionRegistry
surayya-MS Mar 6, 2023
4b92f0c
remove IsDefaultContent from SectionContent
surayya-MS Mar 6, 2023
48538d1
remove IsDefaultContent from PublicAPI
surayya-MS Mar 6, 2023
08ebe15
Merge branch 'main' into sectionsSupport
surayya-MS Mar 6, 2023
e418aa6
fix
surayya-MS Mar 6, 2023
853e6ea
Merge branch 'main' into sectionsSupport
surayya-MS Mar 7, 2023
157bdaf
Revert "remove IsDefaultContent from PublicAPI"
surayya-MS Mar 7, 2023
036dc2d
Revert "remove IsDefaultContent from SectionContent"
surayya-MS Mar 7, 2023
a6ef091
made IsDefaultContent internal
surayya-MS Mar 7, 2023
403d493
Merge branch 'main' into sectionsSupport
surayya-MS Mar 7, 2023
b1b8be8
fix
surayya-MS Mar 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/Components/Components/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,18 @@
Microsoft.AspNetCore.Components.ComponentBase.DispatchExceptionAsync(System.Exception! exception) -> System.Threading.Tasks.Task!
Microsoft.AspNetCore.Components.RenderHandle.DispatchExceptionAsync(System.Exception! exception) -> System.Threading.Tasks.Task!
*REMOVED*Microsoft.AspNetCore.Components.NavigationManager.ToAbsoluteUri(string! relativeUri) -> System.Uri!
Microsoft.AspNetCore.Components.NavigationManager.ToAbsoluteUri(string? relativeUri) -> System.Uri!
Microsoft.AspNetCore.Components.NavigationManager.ToAbsoluteUri(string? relativeUri) -> System.Uri!
Microsoft.AspNetCore.Components.Sections.SectionContent
Microsoft.AspNetCore.Components.Sections.SectionContent.ChildContent.get -> Microsoft.AspNetCore.Components.RenderFragment?
Microsoft.AspNetCore.Components.Sections.SectionContent.ChildContent.set -> void
Microsoft.AspNetCore.Components.Sections.SectionContent.Dispose() -> void
Microsoft.AspNetCore.Components.Sections.SectionContent.IsDefaultContent.get -> bool
Microsoft.AspNetCore.Components.Sections.SectionContent.IsDefaultContent.set -> void
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved
Microsoft.AspNetCore.Components.Sections.SectionContent.Name.get -> string!
Microsoft.AspNetCore.Components.Sections.SectionContent.Name.set -> void
Microsoft.AspNetCore.Components.Sections.SectionContent.SectionContent() -> void
Microsoft.AspNetCore.Components.Sections.SectionOutlet
Microsoft.AspNetCore.Components.Sections.SectionOutlet.Dispose() -> void
Microsoft.AspNetCore.Components.Sections.SectionOutlet.Name.get -> string!
Microsoft.AspNetCore.Components.Sections.SectionOutlet.Name.set -> void
Microsoft.AspNetCore.Components.Sections.SectionOutlet.SectionOutlet() -> void
2 changes: 1 addition & 1 deletion src/Components/Components/src/Sections/SectionContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Components.Sections;
/// <summary>
/// Provides content to <see cref="SectionOutlet"/> components with matching <see cref="Name"/>s.
/// </summary>
internal sealed class SectionContent : ISectionContentProvider, IComponent, IDisposable
public sealed class SectionContent : ISectionContentProvider, IComponent, IDisposable
{
private string? _registeredName;
private SectionRegistry _registry = default!;
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Components/src/Sections/SectionOutlet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Components.Sections;
/// <summary>
/// Renders content provided by <see cref="SectionContent"/> components with matching <see cref="Name"/>s.
/// </summary>
internal sealed class SectionOutlet : ISectionContentSubscriber, IComponent, IDisposable
public sealed class SectionOutlet : ISectionContentSubscriber, IComponent, IDisposable
{
private static readonly RenderFragment _emptyRenderFragment = _ => { };

Expand Down
4 changes: 2 additions & 2 deletions src/Components/Web/src/Head/HeadOutlet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public sealed class HeadOutlet : ComponentBase
{
private const string GetAndRemoveExistingTitle = "Blazor._internal.PageTitle.getAndRemoveExistingTitle";

internal const string HeadSectionOutletName = "head";
internal const string TitleSectionOutletName = "title";
internal const string HeadSectionOutletName = "blazor_head";
internal const string TitleSectionOutletName = "blazor_title";
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved

private string? _defaultTitle;

Expand Down
179 changes: 179 additions & 0 deletions src/Components/test/E2ETest/Tests/SectionsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.E2ETesting;
using Xunit.Abstractions;
using Microsoft.AspNetCore.Components.E2ETest;
using OpenQA.Selenium;

namespace Microsoft.AspNetCore.Components.E2ETests.Tests;
public class SectionsTest : ServerTestBase<ToggleExecutionModeServerFixture<Program>>
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved
{
private IWebElement _appElement;

public SectionsTest
(BrowserFixture browserFixture,
ToggleExecutionModeServerFixture<Program> serverFixture,
ITestOutputHelper output)
: base(browserFixture, serverFixture, output)
{
}

protected override void InitializeAsyncCore()
{
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved
_appElement = Browser.MountTestComponent<BasicTestApp.SectionsTest.ParentComponentWithTwoChildren>();
}

[Fact]
public void NoExistingSectionContents_SectionOutletsRenderNothing()
{
// At the beginning no SectionContents are rendered
Browser.DoesNotExist(By.Id("counter"));
Browser.DoesNotExist(By.Id("text"));
}

[Fact]
public void RenderOneSectionContent_MatchingSectionOutletRendersContentSuccessfully()
{
_appElement.FindElement(By.Id("counter_render_section_content")).Click();

var counter = Browser.Exists(By.Id("counter"));
Assert.Equal("0", counter.Text);

_appElement.FindElement(By.Id("increment_button")).Click();

Assert.Equal("1", counter.Text);
}

[Fact]
public void RenderTwoSectionContentsWithSameName_LastRenderedOverridesSectionOutletContent()
{
_appElement.FindElement(By.Id("counter_render_section_content")).Click();

Browser.Exists(By.Id("counter"));

_appElement.FindElement(By.Id("text_render_section_content")).Click();

Browser.Exists(By.Id("text"));
Browser.DoesNotExist(By.Id("counter"));
}

[Fact]
public void SecondSectionContentGetsDisposed_SectionOutletRendersFirstSectionContent()
{
//Render Counter and TextComponent SectionContents with same Name
// TextComponent's SectionContent overrides Counter SectionContent
_appElement.FindElement(By.Id("counter_render_section_content")).Click();
_appElement.FindElement(By.Id("text_render_section_content")).Click();

_appElement.FindElement(By.Id("text_dispose_section_content")).Click();

Browser.Exists(By.Id("counter"));
}

[Fact]
public void BothSectionContentsGetDisposed_SectionOutletsRenderNothing()
{
_appElement.FindElement(By.Id("counter_render_section_content")).Click();
_appElement.FindElement(By.Id("text_render_section_content")).Click();

_appElement.FindElement(By.Id("counter_dispose_section_content")).Click();
_appElement.FindElement(By.Id("text_dispose_section_content")).Click();

Browser.DoesNotExist(By.Id("counter"));
Browser.DoesNotExist(By.Id("text"));
}

[Fact]
public void SectionContentNameChanges_MatchingSectionOutletRendersContent()
{
// Render Counter and TextComponent SectionContents with same Name
// TextComponent's SectionContent overrides Counter SectionContent
_appElement.FindElement(By.Id("counter_render_section_content")).Click();
_appElement.FindElement(By.Id("text_render_section_content")).Click();

_appElement.FindElement(By.Id("counter_change_section_content_name")).Click();

Browser.Exists(By.Id("counter"));
}

[Fact]
public void SectionContentNameChangesToNonExisting_NoMatchingSectionOutletResultingNoRendering()
{
// Render Counter and TextComponent SectionContents with same Name
// TextComponent's SectionContent overrides Counter SectionContent
_appElement.FindElement(By.Id("counter_render_section_content")).Click();
_appElement.FindElement(By.Id("text_render_section_content")).Click();

_appElement.FindElement(By.Id("counter_change_section_content_name_nonexisting")).Click();

Browser.DoesNotExist(By.Id("counter"));
}

[Fact]
public void SectionOutletGetsDisposed_NoContentsRendered()
{
// Render Counter and TextComponent SectionContents with same Name
_appElement.FindElement(By.Id("counter_render_section_content")).Click();
_appElement.FindElement(By.Id("text_render_section_content")).Click();

// TextComponent's SectionContent overrides Counter SectionContent
Browser.Exists(By.Id("text"));

_appElement.FindElement(By.Id("section_outlet_dispose")).Click();

Browser.DoesNotExist(By.Id("counter"));
Browser.DoesNotExist(By.Id("text"));
}

[Fact]
public void DefaultSectionContent_DoesNotOverrideAnotherSectionContent()
{
_appElement.FindElement(By.Id("text_section_content_make_default")).Click();

_appElement.FindElement(By.Id("counter_render_section_content")).Click();
_appElement.FindElement(By.Id("text_render_section_content")).Click();

// TextComponent's SectionContent IsDefaultContent=true does not override Counter's SectionContent
Browser.DoesNotExist(By.Id("text"));
Browser.Exists(By.Id("counter"));
}

[Fact]
public void BothDefaultSectionContents_()
{
//TODO
}

[Fact]
public void DefaultSectionContent_RendersWhenAnotherSectionContentGetsDisposed()
{
_appElement.FindElement(By.Id("text_section_content_make_default")).Click();

_appElement.FindElement(By.Id("counter_render_section_content")).Click();
_appElement.FindElement(By.Id("text_render_section_content")).Click();

_appElement.FindElement(By.Id("counter_dispose_section_content")).Click();

Browser.DoesNotExist(By.Id("counter"));
Browser.Exists(By.Id("text"));
}

// TODO support changing IsDefaultContent
[Fact]
public void IsDefaultContentChanges_DoesNotOverrideAnotherSectionContent()
{
_appElement.FindElement(By.Id("counter_render_section_content")).Click();
_appElement.FindElement(By.Id("text_render_section_content")).Click();

_appElement.FindElement(By.Id("text_section_content_make_default")).Click();

// TextComponent's SectionContent IsDefaultContent=true does not override Counter's SectionContent
Browser.DoesNotExist(By.Id("text"));
Browser.Exists(By.Id("counter"));
}
}
1 change: 1 addition & 0 deletions src/Components/test/testassets/BasicTestApp/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
<option value="BasicTestApp.VirtualizationDataChanges">Virtualization data changes</option>
<option value="BasicTestApp.VirtualizationTable">Virtualization HTML table</option>
<option value="BasicTestApp.HotReload.RenderOnHotReload">Render on hot reload</option>
<option value="BasicTestApp.SectionsTest.ParentComponentWithTwoChildren">Sections test</option>
</select>

<span id="runtime-info"><code><tt>@System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription</tt></code></span>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@using Microsoft.AspNetCore.Components.Sections

<div>
<PageTitle>Counter</PageTitle>

<h2>Counter</h2>

<p>Counter SectionContent was rendered = @SectionContentExists.ToString()</p>

<p>Counter SectionContent Name = @SectionName</p>

<p>Counter IsDefaultContent = @IsDefaultContent.ToString()</p>

@if (SectionContentExists)
{
<SectionContent Name="@SectionName" IsDefaultContent="@IsDefaultContent">
<p id="counter">@currentCount</p>
</SectionContent>
}

<button id="increment_button" @onclick="IncrementCount">Click me</button>
</div>

@code {
[Parameter]
public bool SectionContentExists { get; set; }

[Parameter]
public bool IsDefaultContent { get; set; }

[Parameter]
public string SectionName { get; set; }

int currentCount = 0;

void IncrementCount()
{
currentCount++;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
@using Microsoft.AspNetCore.Components.Sections

<h1>Parent Component</h1>

@if (SectionOutletExists)
{
<SectionOutlet Name="@firstSectionName" />
}

<p>Text between two section outlets</p>

<SectionOutlet Name="@secondSectionName" />

<button id="section_outlet_dispose"
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved
@onclick="@(() => SectionOutletExists = false)">
Dispose first SectionOutlet
</button>

<Counter
SectionContentExists="@CounterSectionContentExists"
SectionName="@CounterSectionContentName"
IsDefaultContent="@CounterIsDefaultContent">
</Counter>

<br />

<button id="counter_render_section_content"
@onclick="@(() => CounterSectionContentExists = true)">
Render Counter SectionContent
</button><br />

<button id="counter_dispose_section_content"
@onclick="@(() => CounterSectionContentExists = false)">
Dispose Counter SectionContent
</button><br />

<button id="counter_change_section_content_name"
@onclick="@(() => CounterSectionContentName = secondSectionName)">
Change Counter SectionContent Name
</button><br />

<button id="counter_change_section_content_name_nonexisting"
@onclick="@(() => CounterSectionContentName = "test3")">
Change Counter SectionContent Name to non sexisting
</button>
<br />

<button id="counter_section_content_make_default"
@onclick="@(() => CounterIsDefaultContent = true)">
Make Counter's SectionContent Default
</button>

<TextComponent
SectionContentExists="@TextComponentSectionContentExists"
SectionName="@TextComponentSectionContentName"
IsDefaultContent="@TextComponentIsDefaultContent">
</TextComponent>

<button id="text_render_section_content"
@onclick="@(() => TextComponentSectionContentExists= true)">
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved
Render TextComponent SectionContent
</button><br />

<button id="text_dispose_section_content"
@onclick="@(() => TextComponentSectionContentExists = false)">
Dispose TextComponent SectionContent
</button><br />

<button id="text_section_content_make_default"
@onclick="@(() => TextComponentIsDefaultContent = true)">
Make TextComponent's SectionContent Default
</button>



@code {
private const string firstSectionName = "test1";
private const string secondSectionName = "test2";
surayya-MS marked this conversation as resolved.
Show resolved Hide resolved

[Parameter]
public bool CounterSectionContentExists { get; set; } = false;
[Parameter]
public bool TextComponentSectionContentExists { get; set; } = false;

[Parameter]
public string CounterSectionContentName { get; set; } = firstSectionName;
[Parameter]
public string TextComponentSectionContentName { get; set; } = firstSectionName;

[Parameter]
public bool CounterIsDefaultContent { get; set; } = false;
[Parameter]
public bool TextComponentIsDefaultContent { get; set; } = false;

[Parameter]
public bool SectionOutletExists { get; set; } = true;
}
Loading