There are a number of ways we can query form elements. In the past we've used getByRole
with a name
filter. We've also used getByLabelText
to query <labels>
and aria-label
property. In this lesson we use getByTitle. The title
attribute is often used on buttons that have just an icon or an X to give a little bit more context to its purpose. When you hover an item with a title attribute you often see a little tooltip with the full text displayed. It can be a nice improvement to accessibility.
We use the title
attribute here while testing the remove from cart button which just shows an X for the button contents. We give each title a unique name associated with what it's going to delete, so we can easily search for the exact button we want to use.
--
This lesson continues to rely on the user event library for simulating clicks.
For a fantastic explanation of various approaches to calculating accessible names for form elements based on labels and titles check out this article: https://webaim.org/articles/label-name/#computation
Instructor: The next thing that we're going to test is our ability to remove items from the cart. If you hover over the Remove button, you can see a little tooltip, saying "Remove bananas from shopping cart." That shows up because our Remove button has a title.
If you look at the WebAIM Accessibility Guidelines, the form field has a title attribute but no label. Screen readers will treat the title as a label. In a terminal window, go ahead and start Jest up in watch mode, and then open up cart.test.tsx. At the bottom of the page, add a new test called Removing Items Should Update Total. That's going to take an async function.
Inside of that test, type const state = getStateWithItems. In this case, for items, we're going to say carrots, two, and bunnies, three. We need to create those products, so carrots, name, carrots, price, $5.50, as product. We'll do something similar for our bunnies here. Bunnies for an ID, a name of bunnies, and we'll make these cost $20 each.
All right, with that in place, we can type render with context cart and pass in our state and then screen.getByText $71, the selector of .total.
So far, we've just confirmed that we have a number of items in the cart and the total is correct. Next type const remove bunnies, grow screen, getByTitle. Once again, we'll pass in a regular expression and we'll say remove bunnies. Let's see if that works for us.
It looks like it found that button. Now we can type userevent.click move bunnies. Now we can expect screen.getByText.total to be only $11. Let's do the same thing with our carrots. Copy those last three note lines.
This one we'll call remove carrots and we'll say getByTitle remove carrots, userevent.click remove carrots. Then after we remove both the carrots and bunnies our total should be zero dollars and zero cents.
Steve, excellent catch!
I verified that both in the sample code and in the previous lesson I used aria-label on the remove button, but then in this lesson it magically switches to title without so much as an explanation. I will add a note in the description for now and talk with the egghead team about possibly updating the video. Apologies for the mistake. Hope the rest of the course is helpful!
Also around 1:36 the code should be:
const removeBunnies = screen.getByLabelText(/remove bunnies/i);
await userEvent.click(removeBunnies); screen.getByText('$11.00', { selector: '.total' });
Did I miss something? In lecture 28 the remove button clearly has an aria and no title attribute!?! That made the end of this lecture very confusing :(