Check out a free preview of the full Enterprise Web App Accessibility (feat. React) course

The "Accessibility Testing Exercise" Lesson is part of the full, Enterprise Web App Accessibility (feat. React) course featured in this preview video. Here's what you'd learn in this lesson:

Marcy discusses writing tests for a component in an insurance portal. They explain the importance of writing tests when fixing bugs and how it helps prevent future issues. The instructor demonstrates writing tests using Jest and Testing Library, focusing on keyboard support and link navigation. They also mention the limitations of Jest and suggest using other testing tools like Cypress for certain scenarios.


Transcript from the "Accessibility Testing Exercise" Lesson

>> Going back to our little insurance portal, we've got some tests that we could write for this. So that's what I always do. If I am fixing something on a component, I really wanna write some tests when I ship it cuz that's a great time to like, okay, we fix some bugs.

How can we prevent this from ever happening again? We could probably write some tests for it. So, let's go over to VS Code, and this is gonna be our last coding exercise. We have one more section that will be a little shorter after this that we will have a discussion at the end.

Should be easy breezy. So our portal switcher, I have some Jest tests set up in here. So, where you structure your tests can vary. Sometimes people put tests off in their own directory. Sometimes people have a directory for each component that has its own storybook stories and Jest tests all kinda co-located.

This is a small project, so I just co-located everything. But we have this set up. It uses testing-library and jest-dom. We have testing-library/react, testing-library/user-event. We pull in our component and render it, and then we have this little sandbox. We can write some assertions. So I have at least one in there to make sure that this renders and it's in the document.

So what other kinds of tests do you think that we could write for this component? If you think about the things that we fixed, there was like stuff for keyboard users, any ideas on kind of what our test assertions would look like?
>> I guess simulating the keyboard user flow for trying to use the component to change the portal?

>> Yeah, yeah, totally. I guess some other things I had in mind were, yeah, the keyboard support is the big one. I think that's primarily what we'll do. But if there's anything in here that kind of goes outside of the scope of a single component, like, do we need to do anything outside of jest?

So that's something to keep in mind. And I guess for this one, it was that there's links in here and I wanted to make sure that those links navigate to the right place. It just seemed like something that could easily be broken. And I wanted some protection against that.

But that was kind of outside of the scope of Jest, because Jest and JSDOM get very mad if you try and do things with the window.location.href in very particular ways. So sometimes when the tooling doesn't have knowledge of the window object or there's some API that's kind of just outside of the scope of your little internal unit-tested component.

You might start to be thinking about other types of testing, like component testing in Cypress. That might be easier, or Cypress in general. So that's something I was thinking about, can I add multiple types of coverage for this to make sure I'm covering the things that seem risky?

So let's write some tests. For the keyboard test, let's do that. So, within this describe statement, I could say it renders the portal, or sorry, toggles. Toggles the portal switcher with the keyboard. And I am gonna make this an asynchronous function. Okay, so in here I need to render our component.

I need to get the toggle button. So, and actually I'll show you kind of my workflow. So when I'm writing tests, I put I put the component on one side or up top, and then I put the tests so I can look at them next to each other.

I'm on a small screen right now, so I am going to collapse the sidebar. So let's open this PortalSwitcher and then I'll do control-click, open to the side on the test, and then I can do Command+B to put them next to each other. So that's kind of nice, cuz now I don't have to flip back and forth.

Conceptually, I can look at what our code look like. And actually, we can do it a little bit TDD style by writing these tests. I'm writing them for what I know is gonna be the fix. And that way they should fail with the old code, which is kinda, that's a nice way to work, I think.

So, let's say const toggleButton, and actually I might need one userEvent. Sometimes you have to set up userEvent a certain way. We'll see if we need it. So toggleButton = screen.getByRole. So here's that matcher, that Kent C Dodds, everyone's friend, was recommending, which I love, cuz that's centering accessibility in our testing.

So, I'm gonna get a link, or sorry, a button. It says it right there, toggleButton. And I don't want just any toggleButton, I want one with a name that matches the regular expression of Toggle portal menu. And that's what we ended up putting on at least the icon button version.

It has an label. So the name, hey, there's another thing we learned today, the accessible name. This API will get that name from any of those options that we talked about. So now you know what that does. So that's pretty cool. So toggleButton, getByRole. This is an async function.

So I can await userEvent.type. I can say toggleButton. And I'm gonna pass it the Enter key. I'm actually going to make this slightly bigger. And, is that right? I have extra parentheses or curly braces I didn't need. Okay, so, let's get through this, const brokerLink. I'm gonna store where I'm gonna try and get to.

So that is an await screen.getByRole. And that one is a link. It has a name of Broker Portal. And text strings and matchers do make me a little bit uncomfortable. They seem a little flaky, or they could be less stable. But that's what they say to you, so I'm gonna try it.

Await, so we're gonna await this expectation cuz it's dependent on an asynchronous brokerLink call with the screen.getByRole. So I'm going to await this expected broker link to be visible. And this is from jest-dom. jest-dom also has a bunch of really cool accessibility stuff in it, like to be focused, to be visible, to have an accessible name.

jest-dom is awesome. So we are going to expect that that link is visible after we toggle it with the keyboard. I'm also going to await userEvent.type on brokerLink, when it supports the escape key, it should send focus back. We haven't moved that code over so that this test would pass for that yet.

So here is where in Jest and testing-library, I can say waitFor an async action. And I can await an expected toggleButton to have focus. Cool, so that should fail. It should be blowing up red. So I'm gonna do Ctrl+backtick. Let's open our terminal here, and I can say yarn run.

Actually, one thing I'm gonna do real quick. Let me show you where these tests are set up. So in package.json, for any testing tool on the web, this is your command center of all your scripts. You probably knew that. But when I'm setting up things like Jest, or Cypress, or Playwright, or whatever, this is where my test commands go.

So if you're ever new on a project, go see what test commands there are. It's made me very effective on a new project cuz I can be like, storybook. And I didn't even need to ask someone. So always go check the scripts cuz it can help orient you to what tooling you have.

So, back to yarn run test. That's gonna run Jest. Let's see what happens. Wow, a big thing of red. We knew that, right? We knew that. We were expecting that, [LAUGH]. No pun intended. So TestingLibraryElementError: unable to find an accessible element with the role "link" and the name '/Broker Portal/'.

So that element, it was not toggleable. We fired that event and it didn't do anything. So even before that, I have one detail where the links don't quite match. And, let's see what else. Unable to find an element by. I hope that's not just an issue with my test.

But we can write some feature tests that, if it's not working, hopefully it's because we just haven't fixed it yet. But sometimes this is the going around and around trying to fix your test. Sometimes, that's the work. So let's swap out our PortalSwitcher for the one that is working better.

I'm gonna put it here in our main directory. Replace that one. Hopefully it'll work, [LAUGH]. My demo gods at this time of the day might not be blessing me. So, yeah, we might not be able to fix this one in time. So what it should do is go from failing to passing, and now I'm gonna wanna go and fix those but in the interest of time, we're gonna have to live with some broken tests.

How's that for a motivator to be like, I need to go fix those? So these tests do work but sometimes, it's probably a tooling thing. I was switching stuff around to try and make the whole project work. Yeah, sometimes you got to go check your tests again. But when these are running in your CI environment and you had, everything worked, [LAUGH] and then it starts to fail.

It can tell you something about your environment, somebody broke a component. I mean, you look at what the failure is. This looks deeper than the actual component itself, I could tell, because it's not finding the component on the page at all. Definitely try it out when you're writing some accessibility tests.

Check these things out, make sure your components rendered for one. I mean, that's why we have these tests in here. It renders, that test failed. So that actually was very helpful because I didn't go wondering, well, why didn't my keyboard tests work? I'm like, well, even before I get there, I already know that there's an infrastructure issue.

So that's why that test's valuable. And so part of the stuff is it takes time. It's not the quickest fix. And that's why when executives in leadership are like, just automate everything. It's like, that is not a cost saving measure. [LAUGH] I don't know if you've had a fiddle with a test suite, but you could have everything working and it can just stop with like one upgrade, TypeScript or a plugin or something.

And then all of a sudden it's like everything changed. So it can be costly, but it's amazing when it works. And that's why I showed it here, even though I risked it not working, [LAUGH]. Because it can be really awesome, especially when you have a little more stable environment.

Your test tools have been working, you haven't made any changes. You can write some tests, you can run them in CI. It works really well. Or it can, anyway.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now