Closed linkdotnet closed 1 year ago
Hmm, I spiked the idea, and it seems that the RemoveRootComponent
is a dealbreaker for us mainly because you can only remove components with no parent making it virtually useless for our case.
protected internal void RemoveRootComponent(int componentId)
{
Dispatcher.AssertAccess();
// Asserts it's a root component
_ = GetRequiredRootComponentState(componentId);
...
private ComponentState GetRequiredRootComponentState(int componentId)
{
var componentState = GetRequiredComponentState(componentId);
if (componentState.ParentComponentState is not null)
{
throw new InvalidOperationException("The specified component is not a root component");
}
return componentState;
}
As all of our components under test have a ParentComponentState
we will always be kicked out in this line of code.
A few loose thoughts, I will have to think more about them before committing to anything.
What is the purpose for a bUnit user to want to dispose/remove a component from the render tree? I suspect it is to test a component's dispose logic. If that is the scenario, I think in many cases that just being able to remove the root component is going to work out.
Ideally I prefer not to have to store the renderer in Services, especially if we have one renderer per "root render". I would rather pass that to rendered component types created by the renderer.
A few loose thoughts, I will have to think more about them before committing to anything.
- What is the purpose for a bUnit user to want to dispose/remove a component from the render tree? I suspect it is to test a component's dispose logic. If that is the scenario, I think in many cases that just being able to remove the root component is going to work out.
- Ideally I prefer not to have to store the renderer in Services, especially if we have one renderer per "root render". I would rather pass that to rendered component types created by the renderer.
Fair points - let's close this ticket and revisit if we need something once we have the one Renderer per Render-Call
Current state
In our current state, the
TestContext
andITestRenderer
offers aDisposeComponents
method that basically removes all components from theRenderTree
so they get disposed of. That has three flaws:DisposeComponents
to too many hierarchies (and objects).Renderer
instance perRender
call ourDisposeComponents
wouldn't work anymore.Fine-grained disposing
With
v2
we have the ability to correct such things. TheRenderer
(from Blazor itself) offers aRemoveRootComponent
that allows us the remove specific elements from the tree.API
The API would sit on top of the
IRenderFragment
type and some API inside theTestRenderer
:TestRenderer.cs
Extensions for
IRenderFragment
:Usage
The usage would be fairly trivial:
Alternative Design
Alternatively, we already have a
IDisposable
implementation insideIRenderFragment
. That said, we could leverage this:That would feel more natural to the language itself. It seems odd to have two dedicated functions taking care of disposing (from an outside point of view).
The inherent issue with this approach is that the markup is set to empty - anyway, there should be no check on the markup if your component gets disposed of.
As the
IRenderFragment
already hasIDisposable
that could lead to side effects for users that already do things like:Seems to be some usage like this: https://grep.app/search?q=using%20var.%2ARenderComponent®exp=true&case=true&filter[lang][0]=C%23.
What are your thoughts @egil ?
Edit: I am leaning towards the second approach of leveraging the already existing
Dispose
method.