-
-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bUnit version of testing-library.com #938
Comments
I did search a bit and found https://github.com/morganlaneap/blazor-testing-library from @morganlaneap that does try to adopt some of the testing library API and combine it with bUnit and Fluent Assertions. It's not complete, and the future plans are not clear, but perhaps Morgan is interested in a collaboration. |
@egil thanks for finding my project! I originally created it as I come from a React Testing Library approach of testing, and noticed bUnit didn't have anything like it. It's current form only has the functionality that I needed for a Blazor website I made, but it definitely would be possible to expand it. I haven't worked on it recently as I've had no need for it, but I'd be open to getting started on it again and implementing more functionality. |
@morganlaneap that's great to hear. we're still debating whether or not it makes sense to put something like this under the bUnit umbrella explicitly, e.g. as a |
@egil I think having something like this in bUnit would be beneficial. A |
This comment was marked as outdated.
This comment was marked as outdated.
It's definitely a good start, this is what I had in mind when I wanted to create something like this. Seems like the right path to go down. The only thing I'd say is that in testing library, I believe if |
Appreciate your input. When I read the description of However, there is an option to specify the expected count in But my ultimate goal was not to introduce too many variants of the query methods, that does not signal explicitly what they do. That part, the getAll and queryAll methods, is not intuitive, at least not coming from .NET. And here we do have the convention of postfixing methods with "Async", so that means we do not have both a query and getAll methods. Finally, the That said, I have no personal experience with Testing Library and their API, so I am very eager to get all the input I can. |
Yeah that makes sense. I think testing library just does it "because that's how we do it". In fact, it actually makes more sense having the |
That's awesome and thanks for starting this! I had debated opening an issue about this but wasn't sure if it was considered in scope of the bUnit project but I think a companion library makes sense. I have a few bits of feedback. This is minor, but I'm not sure I understand the reason for naming the library To clarify a couple points about the testing-library api: The reason TestingLibraryElementError: Unable to find an accessible element with the role "link"
Here are the accessible roles:
button:
Name "Hello World":
<button />
--------------------------------------------------
<body>
<div>
<button>
<span>
Hello
</span>
<span>
World
</span>
</button>
</div>
</body> as opposed to if it returned an empty array then you would only get a message like "expected length 2 but received 0". This is why there is even a linter rule to enforce people use the correct query for the circumstance. And while you can use this behavior to implicitly assert that an element exists, the recommended practice is to have an explicit assertion like: That being said, I agree the names aren't very intuitive especially in C# land (I've had to remind myself that The error messages aren't really shown in the docs but you can see them in the test suite: https://github.com/testing-library/dom-testing-library/blob/main/src/__tests__/role.js. Probably not necessary to fully implement all the detailed info at least initially, but I at least found it handy to output the markup automatically when a query failed. I also wonder if it would be worth defining an subset of the testing-library api to support initially since some of the queries/options will require the library do some heavy lifting that testing-library is able do by leveraging other npm packages. For example, the For me at least, I find I hope this is helpful and thanks for all your work on bUnit! |
Thank you for your input @bpugh.
I agree. After reading through the Testing Library's docs, I realize it's mostly a query API, and I am considering just including the additional query APIs into The same can be said for the event dispatch methods (fireEvent in Testing Library), e.g.
I really like having the "actual" markup in the error message for the My concern is making the API as intuitive to a C#/.NET dev as possible though, and providing a map for users coming from Testing Library where we differ. I'm not a huge fan of However, I guess the An alternative is to mirror the LINQ methods, and create special overload versions of
I agree. We would start with the basic options and get a release out that supports them. It was not exactly clear to me what
Thanks, it's super helpful to get this kind of input and I hope you are able to help out refining our version of Testing Library further! |
Sounds like a good plan!
They're not mutually exclusive since elements can have both so specifying both options would return elements that match on the |
Happy new year everyone. I updated my original issue text with the changes we discussed. Let me know if it looks OK (@bpugh / @morganlaneap). |
@egil - As we discussed at NDC Porto... I'm gonna take a crack at starting a PR here in the next week or so to start hitting on some of these queries. If you have any thoughts not captured in this issue - lemme know so I can reflect it in the PR accordingly. I do have a "TDD with Blazor" webinar with JetBrains on November 9th... but that might be cutting it close to have this done and shipped by then... but assuming we're in a good spot with these... maybe I could tease these at the end. 😄 |
Most excellent @scottsauber. It was nice chatting with you again in Porto. It's been a while since I looked at this, so my memory is a little foggy on the entire thing. Would it make sense to create an experimental |
Sounds good to me on creating another package for this. Just to be clear - you're thinking the package would not remain separate long term? |
Yes, or, I think once the API is settled it would make sense to include it by default in bunit, either by moving the code into the bunit.web package or by referencing the new package in the |
Yeah, I have a session during .net conf on the topic as well so yeah, would be good to say definitely that this feature is coming to bunit. |
@linkdotnet whats your thinking on the idea of having a (perhaps temp) experimental package? |
Currently on vacation, so only able to type on mobile. In short I am much in favor of an experimental and somewhat external package we can promote. My main reason is a diluted API in v1. There are many overlaps or functions that do 1 to 1 the same as the "native bunit" one. That gives us a time to think of a way forward (for example ditching much in v2 in favor of the testing-library API). TL;DR: Yes to external package, some reservations if we internalize now |
I'll shoot up a draft PR later tonight with what I've started but just FYI some of the signatures will change because you can grab more than just an |
Sounds good. Write in the PR when you want us to start providing input. |
First preview version has been released: https://www.nuget.org/packages/bunit.web.query/1.28.4-preview Thanks to @scottsauber for picking up the mantel and helping us get going with this. |
I could’ve used OrDefault today… I really need to get back in the saddle on this. |
In the front-end testing world, https://testing-library.com/ API surface has become very popular.
As far as I can see, it's a bunch of helper methods that allow users to easily traverse the DOM, interact with it, and assert against it. All the core APIs should be fairly straightforward to support based on bUnit's API surface, the queries, the firing of events, the async "wait for", e.g. for elements to appear or disappear, accessibility checks, etc.
The cheat sheet for the DOM Testing Library can be found here: https://testing-library.com/docs/dom-testing-library/cheatsheet
Below are the initial design and docs for bUnit's version of Testing Library. The additional APIs would be part of the
bunit.web
project, as the are all related to interacting with the rendered DOM:Querying and interacting with rendered markup
bUnit includes methods that make it easy to query, interact, and use the rendered markup (DOM), similar to how a user would. They are inspired by the https://testing-library.com library from the JavaScript world. Check out their Guiding Principles for additional tips for writing good tests using the assertion methods in this library.
Mapping between Testing Library and bUnit conventions
getBy*
Find*
ElementNotFoundException
exception if no elements match or if more than one match is found (useFindAll*
instead if more than one element is expected).queryBy*
Find*OrDefault
null
if no elements match. This is useful for asserting an element that is not present. Throws an error if more than one match is found (useFindAll*
and assert the returned collection is empty instead, if this is OK).findBy*
Find*Async
Task
that completes when the matching element is found which matches the given query. Throws aTimeoutException
if no element is found or if more than one element is found after a default timeout of 1000ms. If you need to find more than one element, useFindAll*Async
.getAllBy*
FindExactly*
queryAllBy*
FindAll*
findAllBy*
FindAll*Async
Task
that completes when any matching elements are found which matches the given query. Throws aTimeoutException
if no elements are found after a default timeout of 1000ms.FindExactly*Async
Task
that completes when exactly the number of matching elements are found for a given query. Throws aTimeoutException
if no elements are found after a default timeout of 1000ms.As the table above shows, the method names are slightly simplified in bUnit compared to Testing Library, and more aligned with what one would expect in .NET / C# code, e.g. using
FindOrDefault
instead ofqueryBy*
.Using queries
The query methods are available on the
IRenderedFragment
type andIInputElement
types. When a query method is issued on anIRenderedFragment
, it will search the entire component tree for matching elements. When a query method is issued on anIInputElement
, it will only search the children of that element.Query options
Each query method has a default set of options that can be overridden by passing in an options object. The options object is optional, and if not provided, the default options will be used.
TextMatch
delegateMost of the query methods can be passed a
TextMatch
, in addition to a string or aRegEx
type.The
TextMatch
delegate is used to specify how a given text should be matched if the default string comparer should not be used. This is the signature forTextMatch
:Where
text
is the text that should be matched, andelement
is the element that contains the text. Theelement
parameter is optional and can benull
if the text is not contained in an element.TODO: is this possible in bUnit?
Matching text (precision)
Instead of the text matching feature of Testing Library, bUnit uses the
StringComparison
enum to specify how to match text. The default isStringComparison.Ordinal
, which is the same as the default in Testing Library, but you can also useStringComparison.OrdinalIgnoreCase
if you want to ignore case or any of the other options for string comparison available in .NET.Normalization
Similar to how
MarkupMatches
normalize text before comparison, the query methods will normalize the text before matching. By default, normalization consists of trimming whitespace from the start and end of text and collapsing multiple adjacent whitespace characters into a single space.If you want to prevent that normalization or provide alternative normalization (e.g. to remove Unicode control characters), you can provide a normalizer delegate in the options object. This function will be given a string and is expected to return a normalized version of that string.
The signature for the normalizer delegate is:
Wait for options
The
WaitForOptions
class is used to specify how long to wait for an element to appear in the DOM, and how often to check for the element. The default is to wait for 1000ms and check every 50ms.Previously, the
WaitFor*
methods in bUnit only retried the wait predicate after every render. I am not sure if it makes sense to introduce a recurring retry interval like Testing Library provides, but it is something to consider.In addition, the
OnTimeout?: (error: Error) => Error
call back does not seem to be useful in C#/.NET, and neither doesmutationObserverOptions?: MutationObserverInit
.The core Find* method
bUnit ships with
Find(string cssSelector)
andFindAll(string cssSelector)
methods already, and it makes sense to continue having these. They are updated to match the structure described above, and replace theWaitForElement
andWaitForElements
methods:ByRole
Check out the ByRole query in Testing Library for a description of the
ByRole
query and its options.Here is the C# API for the
ByRole
query:ByLabelText
Check out the ByLabelText query in Testing Library for a description of the
ByLabelText
query and its options.Here is the C# API for the
ByLabelText
query:The remaining queries follow the same pattern as the above queries and are not much different.
Firing events
Event firing, or dispatching, as it's called in bUnit until now, will stay pretty much the same, but with a few improvements.
We will drop the overloads that take each property in an EventArgs type and just keep the overload that takes an optional EventArg. If none is provided, we will create a default EventArgs type for the event in question.
The text was updated successfully, but these errors were encountered: