Skip to content

Commit

Permalink
feat: toHaveAccessibleName and toHaveAccessibleDescription (#377)
Browse files Browse the repository at this point in the history
* Add toHaveAccessibleName
* Add toHaveAccessibleDescription
* Update README.md

Co-authored-by: Sebastian Silbermann <[email protected]>
  • Loading branch information
gnapse and eps1lon authored Jun 11, 2021
1 parent 317e319 commit 87ffd2a
Show file tree
Hide file tree
Showing 7 changed files with 559 additions and 2 deletions.
93 changes: 91 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ clear to read and to maintain.
- [`toBeVisible`](#tobevisible)
- [`toContainElement`](#tocontainelement)
- [`toContainHTML`](#tocontainhtml)
- [`toHaveAccessibleDescription`](#tohaveaccessibledescription)
- [`toHaveAccessibleName`](#tohaveaccessiblename)
- [`toHaveAttribute`](#tohaveattribute)
- [`toHaveClass`](#tohaveclass)
- [`toHaveFocus`](#tohavefocus)
Expand Down Expand Up @@ -155,8 +157,7 @@ toBeDisabled()
```

This allows you to check whether an element is disabled from the user's
perspective.
According to the specification, the following elements can be
perspective. According to the specification, the following elements can be
[disabled](https://html.spec.whatwg.org/multipage/semantics-other.html#disabled-elements):
`button`, `input`, `select`, `textarea`, `optgroup`, `option`, `fieldset`.

Expand Down Expand Up @@ -526,6 +527,94 @@ expect(getByTestId('parent')).toContainHTML('</span>')
<hr />

### `toHaveAccessibleDescription`

```typescript
toHaveAccessibleDescription(expectedAccessibleDescription?: string | RegExp)
```

This allows to assert that an element has the expected
[accessible description](https://w3c.github.io/accname/).

You can pass the exact string of the expected accessible description, or you can
make a partial match passing a regular expression, or by using
[expect.stringContaining](https://jestjs.io/docs/en/expect.html#expectnotstringcontainingstring)/[expect.stringMatching](https://jestjs.io/docs/en/expect.html#expectstringmatchingstring-regexp).

#### Examples

```html
<a
data-testid="link"
href="/"
aria-label="Home page"
title="A link to start over"
>Start</a
>
<a data-testid="extra-link" href="/about" aria-label="About page">About</a>
<img src="avatar.jpg" data-testid="avatar" alt="User profile pic" />
<img
src="logo.jpg"
data-testid="logo"
alt="Company logo"
aria-describedby="t1"
/>
<span id="t1" role="presentation">The logo of Our Company</span>
```

```js
expect(getByTestId('link')).toHaveAccessibleDescription()
expect(getByTestId('link')).toHaveAccessibleDescription('A link to start over')
expect(getByTestId('link')).not.toHaveAccessibleDescription('Home page')
expect(getByTestId('extra-link')).not.toHaveAccessibleDescription()
expect(getByTestId('avatar')).not.toHaveAccessibleDescription()
expect(getByTestId('logo')).not.toHaveAccessibleDescription('Company logo')
expect(getByTestId('logo')).toHaveAccessibleDescription(
'The logo of Our Company',
)
```

<hr />

### `toHaveAccessibleName`

```typescript
toHaveAccessibleName(expectedAccessibleName?: string | RegExp)
```

This allows to assert that an element is has the expected
[accessible name](https://w3c.github.io/accname/). It is useful, for instance,
to assert that form elements and buttons are properly labelled.

You can pass the exact string of the expected accessible name, or you can make a
partial match passing a regular expression, or by using
[expect.stringContaining](https://jestjs.io/docs/en/expect.html#expectnotstringcontainingstring)/[expect.stringMatching](https://jestjs.io/docs/en/expect.html#expectstringmatchingstring-regexp).

#### Examples

```html
<img data-testid="img-alt" src="" alt="Test alt" />
<img data-testid="img-empty-alt" src="" alt="" />
<svg data-testid="svg-title"><title>Test title</title></svg>
<button data-testid="button-img-alt"><img src="" alt="Test" /></button>
<p><img data-testid="img-paragraph" src="" alt="" /> Test content</p>
<button data-testid="svg-button"><svg><title>Test</title></svg></p>
<div><svg data-testid="svg-without-title"></svg></div>
<input data-testid="input-title" title="test" />
```

```javascript
expect(getByTestId('img-alt')).toHaveAccessibleName('Test alt')
expect(getByTestId('img-empty-alt')).not.toHaveAccessibleName()
expect(getByTestId('svg-title')).toHaveAccessibleName('Test title')
expect(getByTestId('button-img-alt')).toHaveAccessibleName()
expect(getByTestId('img-paragraph')).not.toHaveAccessibleName()
expect(getByTestId('svg-button')).toHaveAccessibleName()
expect(getByTestId('svg-without-title')).not.toHaveAccessibleName()
expect(getByTestId('input-title')).toHaveAccessibleName()
```

<hr />

### `toHaveAttribute`

```typescript
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"chalk": "^3.0.0",
"css": "^3.0.0",
"css.escape": "^1.5.1",
"dom-accessibility-api": "^0.5.6",
"lodash": "^4.17.15",
"redent": "^3.0.0"
},
Expand Down
59 changes: 59 additions & 0 deletions src/__tests__/to-have-accessible-description.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {render} from './helpers/test-utils'

describe('.toHaveAccessibleDescription', () => {
it('works with the link title attribute', () => {
const {queryByTestId} = render(`
<div>
<a data-testid="link" href="/" aria-label="Home page" title="A link to start over">Start</a>
<a data-testid="extra-link" href="/about" aria-label="About page">About</a>
</div>
`)

const link = queryByTestId('link')
expect(link).toHaveAccessibleDescription()
expect(link).toHaveAccessibleDescription('A link to start over')
expect(link).not.toHaveAccessibleDescription('Home page')
expect(() => {
expect(link).toHaveAccessibleDescription('Invalid description')
}).toThrow(/expected element to have accessible description/i)
expect(() => {
expect(link).not.toHaveAccessibleDescription()
}).toThrow(/expected element not to have accessible description/i)

const extraLink = queryByTestId('extra-link')
expect(extraLink).not.toHaveAccessibleDescription()
expect(() => {
expect(extraLink).toHaveAccessibleDescription()
}).toThrow(/expected element to have accessible description/i)
})

it('works with aria-describedby attributes', () => {
const {queryByTestId} = render(`
<div>
<img src="avatar.jpg" data-testid="avatar" alt="User profile pic">
<img src="logo.jpg" data-testid="logo" alt="Company logo" aria-describedby="t1">
<span id="t1" role="presentation">The logo of Our Company</span>
</div>
`)

const avatar = queryByTestId('avatar')
expect(avatar).not.toHaveAccessibleDescription()
expect(() => {
expect(avatar).toHaveAccessibleDescription('User profile pic')
}).toThrow(/expected element to have accessible description/i)

const logo = queryByTestId('logo')
expect(logo).not.toHaveAccessibleDescription('Company logo')
expect(logo).toHaveAccessibleDescription('The logo of Our Company')
expect(logo).toHaveAccessibleDescription(/logo of our company/i)
expect(logo).toHaveAccessibleDescription(
expect.stringContaining('logo of Our Company'),
)
expect(() => {
expect(logo).toHaveAccessibleDescription("Our company's logo")
}).toThrow(/expected element to have accessible description/i)
expect(() => {
expect(logo).not.toHaveAccessibleDescription('The logo of Our Company')
}).toThrow(/expected element not to have accessible description/i)
})
})
Loading

0 comments on commit 87ffd2a

Please sign in to comment.