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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions