@@ -5975,5 +5975,136 @@ suite('FocusManager', function () {
59755975 ) ;
59765976 assert . strictEqual ( document . activeElement , nodeElem ) ;
59775977 } ) ;
5978+
5979+ test ( 'with focus change callback initially calls focus change callback with initial state' , function ( ) {
5980+ const callback = sinon . fake ( ) ;
5981+ this . focusManager . registerTree ( this . testFocusableTree2 ) ;
5982+ this . focusManager . registerTree ( this . testFocusableGroup2 ) ;
5983+ const ephemeralElement = document . getElementById (
5984+ 'nonTreeElementForEphemeralFocus' ,
5985+ ) ;
5986+
5987+ this . focusManager . takeEphemeralFocus ( ephemeralElement , callback ) ;
5988+
5989+ assert . strictEqual ( callback . callCount , 1 ) ;
5990+ assert . isTrue ( callback . firstCall . calledWithExactly ( true ) ) ;
5991+ } ) ;
5992+
5993+ test ( 'with focus change callback finishes ephemeral does not calls focus change callback again' , function ( ) {
5994+ const callback = sinon . fake ( ) ;
5995+ this . focusManager . registerTree ( this . testFocusableTree2 ) ;
5996+ this . focusManager . registerTree ( this . testFocusableGroup2 ) ;
5997+ const ephemeralElement = document . getElementById (
5998+ 'nonTreeElementForEphemeralFocus' ,
5999+ ) ;
6000+ const finishFocusCallback = this . focusManager . takeEphemeralFocus (
6001+ ephemeralElement ,
6002+ callback ,
6003+ ) ;
6004+ callback . resetHistory ( ) ;
6005+
6006+ finishFocusCallback ( ) ;
6007+
6008+ assert . isFalse ( callback . called ) ;
6009+ } ) ;
6010+
6011+ test ( 'with focus change callback set focus to ephemeral child does not call focus change callback again' , function ( ) {
6012+ const callback = sinon . fake ( ) ;
6013+ this . focusManager . registerTree ( this . testFocusableTree2 ) ;
6014+ this . focusManager . registerTree ( this . testFocusableGroup2 ) ;
6015+ const ephemeralElement = document . getElementById (
6016+ 'nonTreeElementForEphemeralFocus' ,
6017+ ) ;
6018+ const ephemeralElementChild = document . getElementById (
6019+ 'nonTreeElementForEphemeralFocus.child1' ,
6020+ ) ;
6021+ this . focusManager . takeEphemeralFocus ( ephemeralElement , callback ) ;
6022+ callback . resetHistory ( ) ;
6023+
6024+ ephemeralElementChild . focus ( ) ;
6025+
6026+ // Focusing a child element shouldn't invoke the callback since the
6027+ // ephemeral element's tree still holds focus.
6028+ assert . isFalse ( callback . called ) ;
6029+ } ) ;
6030+
6031+ test ( 'with focus change callback set focus to non-ephemeral element calls focus change callback' , function ( ) {
6032+ const callback = sinon . fake ( ) ;
6033+ this . focusManager . registerTree ( this . testFocusableTree2 ) ;
6034+ this . focusManager . registerTree ( this . testFocusableGroup2 ) ;
6035+ const ephemeralElement = document . getElementById (
6036+ 'nonTreeElementForEphemeralFocus' ,
6037+ ) ;
6038+ const ephemeralElement2 = document . getElementById (
6039+ 'nonTreeElementForEphemeralFocus2' ,
6040+ ) ;
6041+ this . focusManager . takeEphemeralFocus ( ephemeralElement , callback ) ;
6042+
6043+ ephemeralElement2 . focus ( ) ;
6044+
6045+ // There should be a second call that indicates focus was lost.
6046+ assert . strictEqual ( callback . callCount , 2 ) ;
6047+ assert . isTrue ( callback . secondCall . calledWithExactly ( false ) ) ;
6048+ } ) ;
6049+
6050+ test ( 'with focus change callback set focus to non-ephemeral element then back calls focus change callback again' , function ( ) {
6051+ const callback = sinon . fake ( ) ;
6052+ this . focusManager . registerTree ( this . testFocusableTree2 ) ;
6053+ this . focusManager . registerTree ( this . testFocusableGroup2 ) ;
6054+ const ephemeralElement = document . getElementById (
6055+ 'nonTreeElementForEphemeralFocus' ,
6056+ ) ;
6057+ const ephemeralElementChild = document . getElementById (
6058+ 'nonTreeElementForEphemeralFocus.child1' ,
6059+ ) ;
6060+ const ephemeralElement2 = document . getElementById (
6061+ 'nonTreeElementForEphemeralFocus2' ,
6062+ ) ;
6063+ this . focusManager . takeEphemeralFocus ( ephemeralElement , callback ) ;
6064+ ephemeralElement2 . focus ( ) ;
6065+
6066+ ephemeralElementChild . focus ( ) ;
6067+
6068+ // The latest call should be returning focus.
6069+ assert . strictEqual ( callback . callCount , 3 ) ;
6070+ assert . isTrue ( callback . thirdCall . calledWithExactly ( true ) ) ;
6071+ } ) ;
6072+
6073+ test ( 'with focus change callback set focus to non-ephemeral element with auto return finishes ephemeral' , function ( ) {
6074+ this . focusManager . registerTree ( this . testFocusableTree2 ) ;
6075+ this . focusManager . registerTree ( this . testFocusableGroup2 ) ;
6076+ this . focusManager . focusNode ( this . testFocusableTree2Node1 ) ;
6077+ const ephemeralElement = document . getElementById (
6078+ 'nonTreeGroupForEphemeralFocus' ,
6079+ ) ;
6080+ const ephemeralElement2 = document . getElementById (
6081+ 'nonTreeElementForEphemeralFocus2' ,
6082+ ) ;
6083+ const finishFocusCallback = this . focusManager . takeEphemeralFocus (
6084+ ephemeralElement ,
6085+ ( hasFocus ) => {
6086+ if ( ! hasFocus ) finishFocusCallback ( ) ;
6087+ } ,
6088+ ) ;
6089+
6090+ // Force focus away, triggering the callback's automatic returning logic.
6091+ ephemeralElement2 . focus ( ) ;
6092+
6093+ // The original focused node should be restored.
6094+ const nodeElem = this . testFocusableTree2Node1 . getFocusableElement ( ) ;
6095+ const activeElems = Array . from (
6096+ document . querySelectorAll ( ACTIVE_FOCUS_NODE_CSS_SELECTOR ) ,
6097+ ) ;
6098+ assert . strictEqual (
6099+ this . focusManager . getFocusedNode ( ) ,
6100+ this . testFocusableTree2Node1 ,
6101+ ) ;
6102+ assert . strictEqual ( activeElems . length , 1 ) ;
6103+ assert . includesClass (
6104+ nodeElem . classList ,
6105+ FocusManager . ACTIVE_FOCUS_NODE_CSS_CLASS_NAME ,
6106+ ) ;
6107+ assert . strictEqual ( document . activeElement , nodeElem ) ;
6108+ } ) ;
59786109 } ) ;
59796110} ) ;
0 commit comments