Skip to content

feat: Add FindComponent on IElement (#153)#1738

Closed
linkdotnet wants to merge 1 commit intov2from
find-component-ext
Closed

feat: Add FindComponent on IElement (#153)#1738
linkdotnet wants to merge 1 commit intov2from
find-component-ext

Conversation

@linkdotnet
Copy link
Copy Markdown
Collaborator

@linkdotnet linkdotnet commented Jul 13, 2025

FindComponent<TComponent>

This PR allows users to call FindComponent on an IElement 1. Fixes #153

var button = cut.Find("#btn");
var owningComponent = button.FindComponent<ButtonComponent>();

It should cover all the basic scenarios (see tests), even when using ElementReferences (that should stay valid when using FindComponent).

The idea is that we can hook into the CssSelectorElementFactory (or the any other factory that inherits from IElementWrapperFactory or better the new IComponentAccessor) to retrieve the elements rendered. If that way doesn't work, we use the BunitRenderer and basically go through everything there (more expensive, but we could also solely rely on that).

The last one happens if we have a ParentComponent that gets rendered, but we do a cut.Find("...").FindComponent<ChildComponent>.

Considerations

The API forces the user to specify the desired output component type: FindComponent<TComponent> - we could also offer a version, where it "just" takes the direct parent component (as an IComponent).


1 It does not work in INode, so users can't use something like: cut.NodeList.First().FindComponent<TComponent>(); because I have no idea on how to hook into that pipeline. Maybe we some factories of Anglesharp, but I am not too deep into that at the moment.

@linkdotnet linkdotnet requested a review from egil July 13, 2025 15:30
@linkdotnet
Copy link
Copy Markdown
Collaborator Author

The name might be misleading as we have already FindComponent, but from an abstract point of view, it does the same (just on a different element). So I rolled with it.

@egil
Copy link
Copy Markdown
Member

egil commented Jul 14, 2025

So if element is created by ComponentA, then element.FindComponent<ComponentB>() will find the ComponentB if it is a child of ComponentA and element?

@egil
Copy link
Copy Markdown
Member

egil commented Jul 14, 2025

Related; i have been thinking that WaitForElement and Find could just be one method, e.g. FindAsync. If the element is not immediately there then it switches to "waiting mode". This is a lot like Playwright does it.

Makes test more resilient, e.g., if component introduces an async aspect, the test does not have to change.

@linkdotnet
Copy link
Copy Markdown
Collaborator Author

So if element is created by ComponentA, then element.FindComponent<ComponentB>() will find the ComponentB if it is a child of ComponentA and element?

So something like this:

Parent.razor

<button>Btn</button>
<ChildComponent/>

Test.cs

var cut = Render<Parent>();
var btn = cut.Find("button");

var child = btn.FindComponent<ChildComponent>();

The FindComponent would throw an exception as it can't find the component.

@linkdotnet
Copy link
Copy Markdown
Collaborator Author

linkdotnet commented Jul 14, 2025

Related; i have been thinking that WaitForElement and Find could just be one method, e.g. FindAsync. If the element is not immediately there then it switches to "waiting mode". This is a lot like Playwright does it.

Makes test more resilient, e.g., if component introduces an async aspect, the test does not have to change.

Basically that would only mean relabelling WaitForElementAsync to FindAsync (of course a bit more - but you get the idea).

The same should be true for: FindAllAsync and FindComponent(s)

@linkdotnet linkdotnet force-pushed the find-component-ext branch from 4107571 to 75bd705 Compare July 14, 2025 11:03
/// <summary>
/// Retrieves the first component of type <typeparamref name="TComponent"/> that is rendered inside the specified <paramref name="element"/>.
/// </summary>
public static IRenderedComponent<TComponent> FindComponent<TComponent>(this IElement element)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are unsure, we can also add
[Experimental] Attribute on top

@linkdotnet linkdotnet closed this Sep 14, 2025
@PavloParafiloCricut
Copy link
Copy Markdown

PavloParafiloCricut commented Oct 20, 2025

Why is it closed? Seems like pretty much useful
I am trying to build something like Page Object Models and this is what I need

@linkdotnet
Copy link
Copy Markdown
Collaborator Author

The PR did not cover all the cases we want and we found it is not in a state where we want to release it - especially because there are edge cases where FindComponent would just behave strange. It is not that we are not planning this feature anymore, but it needs more design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants