Skip to content

Commit 011bb5a

Browse files
feat: add toHaveFocus functionality (#32)
feat: add toHaveFocus functionality
1 parent addebad commit 011bb5a

File tree

5 files changed

+64
-0
lines changed

5 files changed

+64
-0
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ to maintain.
5252
- [`toHaveAttribute`](#tohaveattribute)
5353
- [`toHaveClass`](#tohaveclass)
5454
- [`toHaveStyle`](#tohavestyle)
55+
- [`toHaveFocus`](#tohavefocus)
5556
- [`toBeVisible`](#tobevisible)
5657
- [Inspiration](#inspiration)
5758
- [Other Solutions](#other-solutions)
@@ -252,6 +253,28 @@ This also works with rules that are applied to the element via a class name for
252253
which some rules are defined in a stylesheet currently active in the document.
253254
The usual rules of css precedence apply.
254255

256+
### `toHaveFocus`
257+
258+
This allows you to assert whether an element has focus or not.
259+
260+
```javascript
261+
// add the custom expect matchers once
262+
import 'jest-dom/extend-expect'
263+
264+
// ...
265+
// <div><input id="focused" type="text" data-testid="focused" /></div>
266+
// const { container } = render(...)
267+
// const input = container.querySelector('#focused');
268+
269+
// input.focus()
270+
expect(queryByTestId(container, 'focused')).toHaveFocus()
271+
272+
// input.blur()
273+
expect(queryByTestId(container, 'focused')).not.toHaveFocus()
274+
275+
// ...
276+
```
277+
255278
### `toBeVisible`
256279

257280
This allows you to check if an element is currently visible to the user.

extend-expect.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ declare namespace jest {
88
toHaveClass(className: string): R
99
toHaveStyle(css: string): R
1010
toHaveTextContent(text: string | RegExp): R
11+
toHaveFocus(): R
1112
}
1213
}

src/__tests__/index.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,26 @@ test('.toHaveStyle', () => {
322322
document.body.removeChild(container)
323323
})
324324

325+
test('.toHaveFocus', () => {
326+
const {container} = render(`
327+
<div>
328+
<label for="focused">test</label>
329+
<input id="focused" type="text" />
330+
<button type="submit" id="not-focused">Not Focused</button>
331+
</div>`)
332+
333+
const focused = container.querySelector('#focused')
334+
const notFocused = container.querySelector('#not-focused')
335+
336+
focused.focus()
337+
338+
expect(focused).toHaveFocus()
339+
expect(notFocused).not.toHaveFocus()
340+
341+
expect(() => expect(focused).not.toHaveFocus()).toThrowError()
342+
expect(() => expect(notFocused).toHaveFocus()).toThrowError()
343+
})
344+
325345
test('.toBeVisible', () => {
326346
const {container} = render(`
327347
<div>

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {toHaveTextContent} from './to-have-text-content'
55
import {toHaveAttribute} from './to-have-attribute'
66
import {toHaveClass} from './to-have-class'
77
import {toHaveStyle} from './to-have-style'
8+
import {toHaveFocus} from './to-have-focus'
89
import {toBeVisible} from './to-be-visible'
910

1011
export {
@@ -15,5 +16,6 @@ export {
1516
toHaveAttribute,
1617
toHaveClass,
1718
toHaveStyle,
19+
toHaveFocus,
1820
toBeVisible,
1921
}

src/to-have-focus.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {matcherHint, printReceived} from 'jest-matcher-utils'
2+
import {checkHtmlElement} from './utils'
3+
4+
export function toHaveFocus(element) {
5+
checkHtmlElement(element, toHaveFocus, this)
6+
7+
return {
8+
pass: document.activeElement === element,
9+
message: () => {
10+
return [
11+
matcherHint(`${this.isNot ? '.not' : ''}.toHaveFocus`, 'element', ''),
12+
'',
13+
'Received:',
14+
` ${printReceived(document.activeElement)}`,
15+
].join('\n')
16+
},
17+
}
18+
}

0 commit comments

Comments
 (0)