bUnit-dev / bUnit

bUnit is a testing library for Blazor components that make tests look, feel, and runs like regular unit tests. bUnit makes it easy to render and control a component under test’s life-cycle, pass parameter and inject services into it, trigger event handlers, and verify the rendered markup from the component using a built-in semantic HTML comparer.
https://bunit.dev
MIT License
1.14k stars 105 forks source link

In v1.12.6 and later .GetAttribute("value") fails to return the correct value if it contains "{" #946

Closed brettwinters closed 1 year ago

brettwinters commented 1 year ago

After upgrading from v1.11.7 -> v1.12.6, .GetAttribute("value") fails to return the value if it contains "{" (my use case here is that I'm displaying json 'log' data in a text area)

Simplified (not real json, no binding, etc):

<textarea value="@("{ \"abc\" }")"></textarea>

The test:

Assert.Equal(
    expected: "{ \"abc\" }",
    actual: cut.Find("textarea").GetAttribute("value")
);

In v1.12.6 and later the test fails with value = "{\n "

In all versions, printing the output in the immediate: cut.Find("textarea") outputs:

OuterHtml: "<textarea id=\"myText\" value=\"{ \" abc\"=\"\" }\"=\"\"></textarea>"
linkdotnet commented 1 year ago

Hey @brettwinters,

that is expected behavior. Prior to 1.12.6 we did encode attribute-values which was not correct. Blazor does not do so, so we shouldn't do either.

For your specific use-case you should do something like that:

<textarea>@myField</textarea>

<textarea> does not have a value attribute. I guess your browser is just defensive in that situation. So in this case: Two stones one bird ;)

brettwinters commented 1 year ago

Hi @linkdotnet - thanks for getting back to me so quickly!

Got it, makes sense, and indeed your solution works. But a couple of questions:

  1. If attribute-value shouldn't be used, why not return null or empty for all cases, not just those that start with "{"? Or is this not handled by BUnit?

  2. If I change to Blazor's InputTextArea and bind to the Value property I also get the incorrect attribute via GetAttribute("value"). Looking at the source, BuildRenderTree(...) adds the builder.AddAttribute(3, "value", BindConverter.FormatValue(CurrentValue)); Is this non-standard html and what do we do in the case where we're using a Blazor component in the correct manner but can't read it's value using BUnit?

Regards

Brett

linkdotnet commented 1 year ago

Hi @brettwinters,

Regarding your first question: bUnit as well as the underlying Blazor renderer does not really care about valid HTML or not. Of course, you are allowed to use the value attribute in any shape or form. The change we did in 1.12 was to be aligned to the Blazor renderer itself. We have our representation of what the Blazor compiler does to create HTML from your razor markup. We aligned that behavior. I am wondering why in your case the actual result contains \n. I have to reproduce that locally. I am suspecting it has something to do with the expression syntax @().

To your second question. Well it is a bit awkward to see that they use textarea like that and I will open a ticket on the aspnet GitHub tracker. And it makes sense that you see the same result, as the underlying InputTextArea get transformed to your initial example. GetAttribute is from AngleSharp that we use under the hood. Basically, we transform the renderer HTML into a C# object representation via AngleSharp. To give you a more detailed explanation I have to make some local experiements.

linkdotnet commented 1 year ago

I checked the InputTextArea component and where it seems it has this attribute - the rendered output looks good. Blazor does put it between the HTML tags.

brettwinters commented 1 year ago

You mean in the actual browser, right? If I inspect <InputTextArea id="myText" @bind-Value="@(Value)"></InputTextArea> using cut.Find("#myText") is does not:

image
linkdotnet commented 1 year ago

Yeah in the browser. But it gets weirder from there as even between the tags there is no content:

<textarea _bl_4b9cdf47-b92a-4204-bbb3-473daec5430f=""></textarea>

But I guess that is a different topic.

I try to reproduce your initial @() statement. I guess for now let's assume that the value attribute is fine (even if it isn't)

brettwinters commented 1 year ago

Yeah, I checked the rendered output from an InputTextArea and noticed the same too.

document.getElementById("textarea")

Shows nothing between the brackets

document.getElementById("textarea").getAttribute('value')

outputs null, as it does for all elements

document.getElementById("textarea").value

outputs the correct value, but this doesn't mean that the value-attribute has been set

linkdotnet commented 1 year ago

Okay I could reproduce this and I am currently figuring out what we can do here. In the end, the whole transformation is done by AngleSharp. And AngleSharp sees your example as 5 key-value pairs instead of 1. I'll investigate a bit later