UNPKG

@wordpress/components

Version:
309 lines (277 loc) 8.19 kB
/** * External dependencies */ import { fireEvent, render } from '@testing-library/react'; import { each } from 'lodash'; /** * WordPress dependencies */ import { UP, DOWN, LEFT, RIGHT, SPACE } from '@wordpress/keycodes'; /** * Internal dependencies */ import { NavigableMenu } from '../menu'; function simulateVisible( container, selector ) { const elements = container.querySelectorAll( selector ); each( elements, ( elem ) => { elem.getClientRects = () => [ 'trick-jsdom-into-having-size-for-element-rect', ]; } ); } function fireKeyDown( node, keyCode, shiftKey ) { const interaction = { stopped: false, }; const event = new window.KeyboardEvent( 'keydown', { keyCode, shiftKey, } ); event.stopImmediatePropagation = () => { interaction.stopped = true; }; fireEvent( node, event ); return interaction; } describe( 'NavigableMenu', () => { it( 'vertical: should navigate by up and down', () => { let currentIndex = 0; const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. */ /* eslint-disable no-restricted-syntax */ <NavigableMenu orientation="vertical" onNavigate={ ( index ) => ( currentIndex = index ) } > <span tabIndex="-1" id="btn1"> One </span> <span tabIndex="-1" id="btn2"> Two </span> <span id="btn-deep-wrapper"> <span id="btn-deep" tabIndex="-1"> Deep </span> </span> <span tabIndex="-1" id="btn3"> Three </span> </NavigableMenu> /* eslint-enable no-restricted-syntax */ ); simulateVisible( container, '*' ); container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { const interaction = fireKeyDown( getByRole( 'menu' ), keyCode, false ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } assertKeyDown( DOWN, 1, true ); assertKeyDown( DOWN, 2, true ); assertKeyDown( DOWN, 3, true ); assertKeyDown( DOWN, 0, true ); assertKeyDown( UP, 3, true ); assertKeyDown( UP, 2, true ); assertKeyDown( UP, 1, true ); assertKeyDown( UP, 0, true ); assertKeyDown( LEFT, 0, true ); assertKeyDown( RIGHT, 0, true ); assertKeyDown( SPACE, 0, false ); } ); it( 'vertical: should navigate by up and down, and stop at edges', () => { let currentIndex = 0; const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. */ /* eslint-disable no-restricted-syntax */ <NavigableMenu cycle={ false } orientation="vertical" onNavigate={ ( index ) => ( currentIndex = index ) } > <span tabIndex="-1" id="btn1"> One </span> <span tabIndex="-1" id="btn2"> Two </span> <span tabIndex="-1" id="btn3"> Three </span> </NavigableMenu> /* eslint-enable no-restricted-syntax */ ); simulateVisible( container, '*' ); container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { const interaction = fireKeyDown( getByRole( 'menu' ), keyCode, false ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } assertKeyDown( DOWN, 1, true ); assertKeyDown( DOWN, 2, true ); assertKeyDown( DOWN, 2, true ); assertKeyDown( UP, 1, true ); assertKeyDown( UP, 0, true ); assertKeyDown( UP, 0, true ); assertKeyDown( LEFT, 0, true ); assertKeyDown( RIGHT, 0, true ); assertKeyDown( SPACE, 0, false ); } ); it( 'horizontal: should navigate by left and right', () => { let currentIndex = 0; const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. */ /* eslint-disable no-restricted-syntax */ <NavigableMenu orientation="horizontal" onNavigate={ ( index ) => ( currentIndex = index ) } > <span tabIndex="-1" id="btn1"> One </span> <span tabIndex="-1" id="btn2"> Two </span> <span id="btn-deep-wrapper"> <span id="btn-deep" tabIndex="-1"> Deep </span> </span> <span tabIndex="-1" id="btn3"> Three </span> </NavigableMenu> /* eslint-enable no-restricted-syntax */ ); simulateVisible( container, '*' ); container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { const interaction = fireKeyDown( getByRole( 'menu' ), keyCode, false ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } assertKeyDown( RIGHT, 1, true ); assertKeyDown( RIGHT, 2, true ); assertKeyDown( RIGHT, 3, true ); assertKeyDown( RIGHT, 0, true ); assertKeyDown( LEFT, 3, true ); assertKeyDown( LEFT, 2, true ); assertKeyDown( LEFT, 1, true ); assertKeyDown( LEFT, 0, true ); assertKeyDown( UP, 0, true ); assertKeyDown( DOWN, 0, true ); assertKeyDown( SPACE, 0, false ); } ); it( 'horizontal: should navigate by left and right, and stop at edges', () => { let currentIndex = 0; const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. */ /* eslint-disable no-restricted-syntax */ <NavigableMenu cycle={ false } orientation="horizontal" onNavigate={ ( index ) => ( currentIndex = index ) } > <span tabIndex="-1" id="btn1"> One </span> <span tabIndex="-1" id="btn2"> Two </span> <span tabIndex="-1" id="btn3"> Three </span> </NavigableMenu> /* eslint-enable no-restricted-syntax */ ); simulateVisible( container, '*' ); container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { const interaction = fireKeyDown( getByRole( 'menu' ), keyCode, false ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } assertKeyDown( RIGHT, 1, true ); assertKeyDown( RIGHT, 2, true ); assertKeyDown( RIGHT, 2, true ); assertKeyDown( LEFT, 1, true ); assertKeyDown( LEFT, 0, true ); assertKeyDown( LEFT, 0, true ); assertKeyDown( DOWN, 0, true ); assertKeyDown( UP, 0, true ); assertKeyDown( SPACE, 0, false ); } ); it( 'both: should navigate by up/down and left/right', () => { let currentIndex = 0; const { container, getByRole } = render( /* Disabled because of our rule restricting literal IDs, preferring `withInstanceId`. In this case, it's fine to use literal IDs. */ /* eslint-disable no-restricted-syntax */ <NavigableMenu orientation="both" onNavigate={ ( index ) => ( currentIndex = index ) } > <button id="btn1">One</button> <button id="btn2">Two</button> <button id="btn3">Three</button> </NavigableMenu> /* eslint-enable no-restricted-syntax */ ); simulateVisible( container, '*' ); container.querySelector( '#btn1' ).focus(); // Navigate options function assertKeyDown( keyCode, expectedActiveIndex, expectedStop ) { const interaction = fireKeyDown( getByRole( 'menu' ), keyCode ); expect( currentIndex ).toBe( expectedActiveIndex ); expect( interaction.stopped ).toBe( expectedStop ); } assertKeyDown( DOWN, 1, true ); assertKeyDown( DOWN, 2, true ); assertKeyDown( DOWN, 0, true ); assertKeyDown( RIGHT, 1, true ); assertKeyDown( RIGHT, 2, true ); assertKeyDown( RIGHT, 0, true ); assertKeyDown( UP, 2, true ); assertKeyDown( UP, 1, true ); assertKeyDown( UP, 0, true ); assertKeyDown( LEFT, 2, true ); assertKeyDown( LEFT, 1, true ); assertKeyDown( LEFT, 0, true ); assertKeyDown( SPACE, 0, false ); } ); } );