Skip to content

Commit

Permalink
unit tests for abort/handle, see #1445
Browse files Browse the repository at this point in the history
  • Loading branch information
jessegreenberg committed Oct 26, 2022
1 parent 38efe5c commit feaaddf
Showing 1 changed file with 147 additions and 9 deletions.
156 changes: 147 additions & 9 deletions js/listeners/KeyboardListenerTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
* @author Agustín Vallejo (PhET Interactive Simulations)
*/

import { Display, KeyboardListener, KeyboardUtils, Node } from '../imports.js';
import { Display, KeyboardListener, KeyboardUtils, Node, SceneryEvent } from '../imports.js';

QUnit.module( 'KeyboardListener' );

QUnit.test( 'Basics', assert => {
QUnit.test( 'KeyboardListener Tests', assert => {

let callbackFired = false;
const listener = new KeyboardListener( {
Expand All @@ -31,29 +31,31 @@ QUnit.test( 'Basics', assert => {
rootNode.addChild( a );
a.addInputListener( listener );

const domElement = a.pdomInstances[ 0 ].peer.primarySibling;
assert.ok( domElement, 'pdom element needed' );
const domElementA = a.pdomInstances[ 0 ].peer.primarySibling;
assert.ok( domElementA, 'pdom element needed' );

domElement.dispatchEvent( new KeyboardEvent( 'keydown', {
domElementA.dispatchEvent( new KeyboardEvent( 'keydown', {
code: KeyboardUtils.KEY_TAB,
bubbles: true
} ) );

assert.ok( !callbackFired, 'should not fire on tab' );

domElement.dispatchEvent( new KeyboardEvent( 'keydown', {
domElementA.dispatchEvent( new KeyboardEvent( 'keydown', {
code: KeyboardUtils.KEY_ENTER,
bubbles: true
} ) );
assert.ok( callbackFired, 'should fire on enter' );

//////////////////////////////////////////////////////
// Test an overlap of keys in two keygroups. The callback should fire for BOTH gey groups
// in response to a single input event.

a.removeInputListener( listener );

let pFired = false;
let ctrlPFired = false;
a.addInputListener( new KeyboardListener( {
const listenerWithOverlappingKeys = new KeyboardListener( {
keys: [ 'p', 'ctrl+p' ],

callback: ( event, keysPressed ) => {
Expand All @@ -67,8 +69,9 @@ QUnit.test( 'Basics', assert => {
assert.ok( false, 'never again' );
}
}
} ) );
domElement.dispatchEvent( new KeyboardEvent( 'keydown', {
} );
a.addInputListener( listenerWithOverlappingKeys );
domElementA.dispatchEvent( new KeyboardEvent( 'keydown', {
code: KeyboardUtils.KEY_P,
ctrlKey: true,
bubbles: true
Expand All @@ -78,6 +81,141 @@ QUnit.test( 'Basics', assert => {

//////////////////////////////////////////////////////

// test handle/abort
a.removeInputListener( listenerWithOverlappingKeys );
const b = new Node( { tagName: 'div' } );
a.addChild( b );

const domElementB = b.pdomInstances[ 0 ].peer.primarySibling;

// test handled - event should no longer bubble, b listener should handle and a listener should not fire
let pFiredFromA = false;
let pFiredFromB = false;
const listenerPreventedByHandle = new KeyboardListener( {
keys: [ 'p' ],
callback: ( event, keysPressed ) => {
if ( keysPressed === 'p' ) {
pFiredFromA = true;
}
}
} );
a.addInputListener( listenerPreventedByHandle );

const handlingListener = new KeyboardListener( {
keys: [ 'p' ],
callback: ( event, keysPressed ) => {
if ( keysPressed === 'p' ) {
pFiredFromB = true;

assert.ok( !!event, 'An event should be provided to the callback in this case.' );
event!.handle();
}
}
} );
b.addInputListener( handlingListener );

domElementB.dispatchEvent( new KeyboardEvent( 'keydown', {
code: KeyboardUtils.KEY_P,
ctrlKey: true,
bubbles: true
} ) );

assert.ok( !pFiredFromA, 'A should not have received the event because of event handling' );
assert.ok( pFiredFromB, 'B received the event and handled it (stopping bubbling)' );

a.removeInputListener( listenerPreventedByHandle );
b.removeInputListener( handlingListener );
pFiredFromA = false;
pFiredFromB = false;

// test abort
const listenerPreventedByAbort = new KeyboardListener( {
keys: [ 'p' ],
callback: ( event, keysPressed ) => {
if ( keysPressed === 'p' ) {
pFiredFromA = true;
}
}
} );
a.addInputListener( listenerPreventedByAbort );

const abortingListener = new KeyboardListener( {
keys: [ 'p' ],
callback: ( event, keysPressed ) => {
if ( keysPressed === 'p' ) {
pFiredFromB = true;

assert.ok( !!event, 'An event should be provided to the callback in this case.' );
event!.abort();
}
}
} );
b.addInputListener( abortingListener );

let pFiredFromExtraListener = false;
const otherListenerPreventedByAbort = {
keydown: ( event: SceneryEvent<KeyboardEvent> ) => {
pFiredFromExtraListener = true;
}
};
b.addInputListener( otherListenerPreventedByAbort );

domElementB.dispatchEvent( new KeyboardEvent( 'keydown', {
code: KeyboardUtils.KEY_P,
ctrlKey: true,
bubbles: true
} ) );

assert.ok( !pFiredFromA, 'A should not have received the event because of abort' );
assert.ok( pFiredFromB, 'B received the event and handled it (stopping bubbling)' );
assert.ok( !pFiredFromExtraListener, 'Other listener on B did not fire because of abort (stopping all listeners)' );

a.removeInputListener( listenerPreventedByAbort );
b.removeInputListener( abortingListener );
b.removeInputListener( otherListenerPreventedByAbort );
pFiredFromA = false;
pFiredFromB = false;

//////////////////////////////////////////////////////

// test interrupt/cancel
// TODO: This test fails but that is working as expected. interrupt/cancel are only relevant for the
// listener for press and hold functionality. Interrupt/cancel cannot clear the keystate because the listener
// does not own its KeyStateTracker, it is using the global one.
// let pbFiredFromA = false;
// let pbjFiredFromA = false;
// const listenerToInterrupt = new KeyboardListener( {
// keys: [ 'p+b', 'p+b+j' ],
// callback: ( event, keysPressed ) => {
// if ( keysPressed === 'p+b' ) {
// pbFiredFromA = true;
// listenerToInterrupt.interrupt();
// }
// else if ( keysPressed === 'p+b+j' ) {
// pbjFiredFromA = true;
// }
// }
// } );
// a.addInputListener( listenerToInterrupt );
//
// domElementB.dispatchEvent( new KeyboardEvent( 'keydown', {
// code: KeyboardUtils.KEY_P,
// bubbles: true
// } ) );
// domElementB.dispatchEvent( new KeyboardEvent( 'keydown', {
// code: KeyboardUtils.KEY_B,
// bubbles: true
// } ) );
// domElementB.dispatchEvent( new KeyboardEvent( 'keydown', {
// code: KeyboardUtils.KEY_J,
// bubbles: true
// } ) );
//
// assert.ok( pbFiredFromA, 'p+b receives the event and interrupts the listener' );
// assert.ok( !pbjFiredFromA, 'interruption clears the keystate so p+b+j does not fire' );

//////////////////////////////////////////////////////

document.body.removeChild( display.domElement );
display.dispose();
} );

0 comments on commit feaaddf

Please sign in to comment.