React Testing Librbary & Jest part 2 Element Roles
===

---
###### tags: `React Testing Library`, `Jest`, `React`
## Partial Role List
Here are common roles when testing components.
```javascript!
// Example.jsx
const Example = () => {
return (
<div>
<a href='/'>link</a>
<button>button</button>
<footer>contentinfo</footer>
<h1>heading</h1>
<header>banner</header>
<img alt='description' />img
<input type='checkbox'/> checkbox
<input type='number' /> spinbutton
<input type='radio'/>radio
<input type='text'/>textbox
<li>Listitem</li>
<ul>Listgroup</ul>
)
}
export default Example;
```
Let's try to find these roles.
```javascript!
// Example.test.js
import { render, screen } from '@testing-library/react';
import Example from '../components/Example';
test('Find roles', () => {
render(<Example />);
const roles = [
'link',
'button',
'contentinfo',
'heading',
'banner',
'img',
'checkbox',
'spinbutton',
'radio',
'textbox',
'listitem',
'listgroup',
];
for (let role of roles) {
const ele = screen.getByRole(role);
expect(ele).toBeInTheDocument();
}
});
```
Open terminal and run `npm run test`, the test failed and inside the terminal, we can see the last one of `Name: '': <ul/>`, it showed `list` instead of `listgroup`, meaning that we used the wrong one, let's change `listgroup` to `list`.

Test passed after changing `listgroup` to `list`.

## Finding by accessible name
Often we will see there're same elements in one component, if we want to check individually, we need to be specific and add more criteria in order to filter the ideal result.
```javascript!
// Accessible.jsx
const Accessible = () => {
return (
<div>
<button>Submit</button>
<button>Cancel</button>
</div>
);
};
export default Accessible;
```
In this example, we have two buttons, if we try to check submit button, it's not enough to just `getByRole('button')`, but if we want to check if all buttons in the document, we can use `getByAllRole('button')`.
In this case, we can add `name` as additioanl criteria.
```javascript!
// Accessible.test.js
import { render, screen } from '@testing-library/react';
import Accessible from '../components/Accessible';
test('Select button by accessible name', () => {
render(<Accessible />);
// i indicates case insensitive
const submitButton = screen.getByRole('button', { name: /submit/i });
const cancelButton = screen.getByRole('button', { name: /cancel/i });
expect(submitButton).toBeInTheDocument();
expect(cancelButton).toBeInTheDocument();
});
```
## Self-closed tag for using accessible name
In the example above, we can use `name` to find each `button`, but when it comes to self-closed element such like `<input />`, we need to find another way to target the element.
When we use `<input/>`, make sure there's `<lable>` along with it, but how can we connect these two?
We need to give **`htmlfor`** to `<lable>` and add **`id`** inside `<input/>`, this way when we click `<label>`, it will automatically focus the `<input/>` accordingly.
```javascript!
// SelfClosed.jsx
const SelfClosed = () => {
return (
<div>
<label htmlFor="email">Email</label>
<input id="email" />
<label htmlFor="password">Password</label>
<input id="password" />
</div>
);
};
export default SelfClosed;
```
```javascript!
// SelfClosed.test.js
import SelfClosed from '../components/SelfClosed';
test('Shows an email and password input', () => {
render(<SelfClosed />);
const emailInput = screen.getByRole('textbox', { name: /email/i });
const passwordInput = screen.getByRole('textbox', { name: /password/i });
expect(emailInput).toBeInTheDocument();
expect(passwordInput).toBeInTheDocument();
});
```
## Directly Assigning accessible name
This is a very common usecase of when there's an icon in between the element, how do we check based on name?
Use `aria-label` to assign an accessible name.
> What is `arai-label`
> The `aria-label` should be used to provide a text alternative to an element that has no visible text on the screen.
> [aria-label](https://www.aditus.io/aria/aria-label/)
```javascript!
// IconButton.jsx
const IconButton = () => {
return (
<div>
<button aria-label="login">
<svg />
</button>
<button aria-label="logout">
<svg />
</button>
</div>
);
};
export default IconButton;
```
```javascript!
// IconButton.test.js
import { render, screen } from '@testing-library/react';
import IconButton from '../components/IconButton';
test('Find login and logout', () => {
render(<IconButton />);
const loginBtn = screen.getByRole('button', { name: /login/i });
const logoutBtn = screen.getByRole('button', { name: /logout/i });
expect(loginBtn).toBeInTheDocument();
expect(logoutBtn).toBeInTheDocument();
});
```