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

Changing a DynamicComponent type should not null out the ReferenceCaptureId of other elements #749

Open
toniarnold opened this issue Jun 8, 2022 · 2 comments
Labels
bug Something isn't working
Milestone

Comments

@toniarnold
Copy link

Describe the bug

When a Razor component contains a DynamicComponent and its type gets changed in a click event, other elements with @ref element references lose their ReferenceCaptureId and they get rendered as empty blazor:elementReference="" (not necessarily all other elements, sometimes just some of them).
When the exact same component is rendered in a full Blazor Server application, this does not happen, the id is rendered e.g. as _bl_75ef2312-3b13-4dfe-925b-b29a10026a50="" (with the Guid in the attribute name) and stays constant.

Example:
Testing this component:

@page "/dynamic"
<h3 @ref="title">DynamicContainer</h3>
<DynamicComponent Type="@pageType"></DynamicComponent>
<button @onclick="@ChangeDynamic" @ref="button" id="button">ChangeDynamic</button>
@code {
    private Type pageType = typeof(ComponentA);
    public ElementReference title;
    public ElementReference button;

    private void ChangeDynamic()
    {
        pageType = (pageType == typeof(ComponentA)) ? typeof(ComponentB) : typeof(ComponentA);
    }
}

With this test:

[Fact(DisplayName = "Changing a DynamicComponent type should not null out the ReferenceCaptureId of other elements")]
public void Test001()
{
	var cut = RenderComponent<DynamicContainer>();
	output.WriteLine($"Before changing DynamicComponent: {cut.Markup}");
	// All @ref elements have a blazor:elementReference GUID
	Guid.Parse(GetRefRerenceCaptureId(cut.Markup, "h3"));
	Guid.Parse(GetRefRerenceCaptureId(cut.Markup, "button"));

	cut.Find("#button").Click();

	output.WriteLine($"After changing DynamicComponent: {cut.Markup}");
	// Issue: The @ref elements have an empty blazor:elementReference, thus this throws now:
	Guid.Parse(GetRefRerenceCaptureId(cut.Markup, "h3"));
	Guid.Parse(GetRefRerenceCaptureId(cut.Markup, "button"));
}

// Extract the blazor:elementReference Id string for a HTML element
private string GetRefRerenceCaptureId(string markup, string element)
{
	var re = new Regex($"<{element}.*blazor:elementReference=\"([^\"]+).*");
	var match = re.Match(markup);
}

Results in this output:

Output:
  Before changing DynamicComponent: <h3 blazor:elementReference="644bd20d-ad50-47c1-a183-92376a40134a">DynamicContainer</h3>
  <DynamicComponent Type="Bunit.TestAssets.SampleComponents.DynamicComponents.ComponentA"></DynamicComponent>
  <button blazor:onclick="1" id="button" blazor:elementReference="552d73b0-5783-41c7-a0c9-3053dfe20d62">ChangeDynamic</button>
  After changing DynamicComponent: <h3 blazor:elementReference="">DynamicContainer</h3>
  <DynamicComponent Type="Bunit.TestAssets.SampleComponents.DynamicComponents.ComponentB"></DynamicComponent>
  <button blazor:onclick="1" id="button" blazor:elementReference="">ChangeDynamic</button>

Expected behavior:

The TestContext.RenderComponent() should exhibit the same behavior as a Blazor Server application and leave the ReferenceCaptureId in place when a DynamicComponent gets rerendered due to a type change.

Version info:

  • bUnit version: 1.9.8
  • .NET Runtime and Blazor version: 6
  • OS type and version: Windows 10

Additional context:

The described problem was first encountered in the Blazor part of https://github.com/toniarnold/aspnettest in the asptest.blazor.bunit sample test of the asp.blazor project with bUnit 1.8.15. There the Id is used to Find an element, which works with Selenium in a Blazor Server application, but fails with bUnit: It seems that only the Id of a button below a DynamicComponent gets nulled out. The other references in the test https://github.com/toniarnold/aspnettest/blob/master/src/asptest.blazor.bunit/CalculatorTest/CalculateTest.razor remain reachable in that case.

I've submitted a pull request #748 which exposes the issue with above test case.

@egil
Copy link
Member

egil commented Jun 8, 2022

Hi @toniarnold, thanks for reaching out!

I remember looking at this previously a few years ago, and I think it is a limitation we cannot get around until we implement #48, which is something I want to attempt for v2.

The problem is that the Blazor renderer does not provide a value for @ref on re-renders when the element does not change, thus we cannot set the blazor:elementReference attribute again, and we currently do not have a way to keep track of that info ourselves from the previous render, since we recreate the DOM on each render.

Will have to take an second look and make sure my memory is correct.

@egil egil added the bug Something isn't working label Jun 8, 2022
@egil egil added this to the 2.0.0 milestone Jun 8, 2022
@egil
Copy link
Member

egil commented Jun 8, 2022

Btw. thumbs up for a thorough crafted issue and PR. Its much appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants