Skip to content

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

@toniarnold

Description

@toniarnold

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions