File tree Expand file tree Collapse file tree 4 files changed +60
-5
lines changed Expand file tree Collapse file tree 4 files changed +60
-5
lines changed Original file line number Diff line number Diff line change @@ -17,7 +17,7 @@ test('fires events when tabbing between two elements', () => {
1717 userEvent . tab ( )
1818 expect ( getEventSnapshot ( ) ) . toMatchInlineSnapshot ( `
1919 Events fired on: div
20-
20+
2121 input#a[value=""] - keydown: Tab (9)
2222 input#a[value=""] - focusout
2323 input#b[value=""] - focusin
@@ -45,7 +45,7 @@ test('does not change focus if default prevented on keydown', () => {
4545 userEvent . tab ( )
4646 expect ( getEventSnapshot ( ) ) . toMatchInlineSnapshot ( `
4747 Events fired on: div
48-
48+
4949 input#a[value=""] - keydown: Tab (9)
5050 input#a[value=""] - keyup: Tab (9)
5151 ` )
@@ -418,6 +418,26 @@ test('should not focus disabled elements', () => {
418418 expect ( five ) . toHaveFocus ( )
419419} )
420420
421+ test ( 'should not focus elements inside a hidden parent' , ( ) => {
422+ setup ( `
423+ <div>
424+ <input data-testid="one" />
425+ <div hidden="">
426+ <button>click</button>
427+ </div>
428+ <input data-testid="three" />
429+ </div>` )
430+
431+ const one = document . querySelector ( '[data-testid="one"]' )
432+ const three = document . querySelector ( '[data-testid="three"]' )
433+
434+ userEvent . tab ( )
435+ expect ( one ) . toHaveFocus ( )
436+
437+ userEvent . tab ( )
438+ expect ( three ) . toHaveFocus ( )
439+ } )
440+
421441test ( 'should keep focus on the document if there are no enabled, focusable elements' , ( ) => {
422442 setup ( `<button disabled>no clicky</button>` )
423443 userEvent . tab ( )
Original file line number Diff line number Diff line change 1- import { isInstanceOfElement } from '../utils'
1+ import { screen } from '@testing-library/dom'
2+ import { isInstanceOfElement , isVisible } from '../utils'
23import { setup } from './helpers/utils'
34
45// isInstanceOfElement can be removed once the peerDependency for @testing -library/dom is bumped to a version that includes https://github.com/testing-library/dom-testing-library/pull/885
@@ -71,3 +72,19 @@ describe('check element type per isInstanceOfElement', () => {
7172 expect ( ( ) => isInstanceOfElement ( element , 'HTMLSpanElement' ) ) . toThrow ( )
7273 } )
7374} )
75+
76+ test ( 'check if element is visible' , ( ) => {
77+ setup ( `
78+ <input data-testid="visibleInput"/>
79+ <input data-testid="hiddenInput" hidden/>
80+ <input data-testid="styledHiddenInput" style="display: none">
81+ <input data-testid="styledDisplayedInput" hidden style="display: block"/>
82+ <div style="display: none"><input data-testid="childInput" /></div>
83+ ` )
84+
85+ expect ( isVisible ( screen . getByTestId ( 'visibleInput' ) ) ) . toBe ( true )
86+ expect ( isVisible ( screen . getByTestId ( 'styledDisplayedInput' ) ) ) . toBe ( true )
87+ expect ( isVisible ( screen . getByTestId ( 'styledHiddenInput' ) ) ) . toBe ( false )
88+ expect ( isVisible ( screen . getByTestId ( 'childInput' ) ) ) . toBe ( false )
89+ expect ( isVisible ( screen . getByTestId ( 'hiddenInput' ) ) ) . toBe ( false )
90+ } )
Original file line number Diff line number Diff line change 11import { fireEvent } from '@testing-library/dom'
2- import { getActiveElement , FOCUSABLE_SELECTOR } from './utils'
2+ import { getActiveElement , FOCUSABLE_SELECTOR , isVisible } from './utils'
33import { focus } from './focus'
44import { blur } from './blur'
55
@@ -31,7 +31,11 @@ function tab({shift = false, focusTrap} = {}) {
3131 const enabledElements = [ ...focusableElements ] . filter (
3232 el =>
3333 el === previousElement ||
34- ( el . getAttribute ( 'tabindex' ) !== '-1' && ! el . disabled ) ,
34+ ( el . getAttribute ( 'tabindex' ) !== '-1' &&
35+ ! el . disabled &&
36+ // Hidden elements are not tabable
37+ isVisible ( el )
38+ ) ,
3539 )
3640
3741 if ( enabledElements . length === 0 ) return
Original file line number Diff line number Diff line change @@ -293,6 +293,19 @@ function isClickableInput(element) {
293293 )
294294}
295295
296+ function isVisible ( element ) {
297+ const getComputedStyle = getWindowFromNode ( element ) . getComputedStyle
298+
299+ for ( ; element && element . ownerDocument ; element = element . parentNode ) {
300+ const display = getComputedStyle ( element ) . display
301+ if ( display === 'none' ) {
302+ return false
303+ }
304+ }
305+
306+ return true
307+ }
308+
296309function eventWrapper ( cb ) {
297310 let result
298311 getConfig ( ) . eventWrapper ( ( ) => {
@@ -367,4 +380,5 @@ export {
367380 getSelectionRange ,
368381 isContentEditable ,
369382 isInstanceOfElement ,
383+ isVisible ,
370384}
You can’t perform that action at this time.
0 commit comments