1
1
import { AfterViewInit , Component , ElementRef , Type , ViewChild } from '@angular/core' ;
2
2
import { ComponentFixture , fakeAsync , flush , TestBed } from '@angular/core/testing' ;
3
+ import { patchElementFocus } from '@angular/cdk/testing/private' ;
3
4
import {
4
5
A11yModule ,
5
6
ConfigurableFocusTrapFactory ,
@@ -22,7 +23,7 @@ describe('EventListenerFocusTrapInertStrategy', () => {
22
23
componentInstance . outsideFocusableElement . nativeElement . focus ( ) ;
23
24
flush ( ) ;
24
25
25
- expect ( document . activeElement ) . toBe (
26
+ expect ( componentInstance . activeElement ) . toBe (
26
27
componentInstance . firstFocusableElement . nativeElement ,
27
28
'Expected first focusable element to be focused' ) ;
28
29
} ) ) ;
@@ -36,7 +37,7 @@ describe('EventListenerFocusTrapInertStrategy', () => {
36
37
componentInstance . secondFocusableElement . nativeElement . focus ( ) ;
37
38
flush ( ) ;
38
39
39
- expect ( document . activeElement ) . toBe (
40
+ expect ( componentInstance . activeElement ) . toBe (
40
41
componentInstance . secondFocusableElement . nativeElement ,
41
42
'Expected second focusable element to be focused' ) ;
42
43
} ) ) ;
@@ -63,17 +64,32 @@ function createComponent<T>(componentType: Type<T>, providers: Array<Object> = [
63
64
`
64
65
} )
65
66
class SimpleFocusTrap implements AfterViewInit {
66
- @ViewChild ( 'focusTrapElement' ) focusTrapElement ! : ElementRef ;
67
- @ViewChild ( 'outsideFocusable' ) outsideFocusableElement ! : ElementRef ;
68
- @ViewChild ( 'firstFocusable' ) firstFocusableElement ! : ElementRef ;
69
- @ViewChild ( 'secondFocusable' ) secondFocusableElement ! : ElementRef ;
67
+ @ViewChild ( 'focusTrapElement' ) focusTrapElement ! : ElementRef < HTMLElement > ;
68
+ @ViewChild ( 'outsideFocusable' ) outsideFocusableElement ! : ElementRef < HTMLElement > ;
69
+ @ViewChild ( 'firstFocusable' ) firstFocusableElement ! : ElementRef < HTMLElement > ;
70
+ @ViewChild ( 'secondFocusable' ) secondFocusableElement ! : ElementRef < HTMLElement > ;
70
71
71
72
focusTrap : ConfigurableFocusTrap ;
72
73
74
+ // Since our custom stubbing in `patchElementFocus` won't update
75
+ // the `document.activeElement`, we need to keep track of it here.
76
+ activeElement : EventTarget | null ;
77
+
73
78
constructor ( private _focusTrapFactory : ConfigurableFocusTrapFactory ) {
74
79
}
75
80
76
81
ngAfterViewInit ( ) {
82
+ // Ensure consistent focus timing across browsers.
83
+ [
84
+ this . focusTrapElement ,
85
+ this . outsideFocusableElement ,
86
+ this . firstFocusableElement ,
87
+ this . secondFocusableElement
88
+ ] . forEach ( ( { nativeElement} ) => {
89
+ patchElementFocus ( nativeElement ) ;
90
+ nativeElement . addEventListener ( 'focus' , event => this . activeElement = event . target ) ;
91
+ } ) ;
92
+
77
93
this . focusTrap = this . _focusTrapFactory . create ( this . focusTrapElement . nativeElement ) ;
78
94
this . focusTrap . focusFirstTabbableElementWhenReady ( ) ;
79
95
}
0 commit comments