@@ -4,26 +4,16 @@ import {StyleModule} from './index';
4
4
import { By } from '@angular/platform-browser' ;
5
5
import { TAB } from '../keyboard/keycodes' ;
6
6
import { FocusOriginMonitor } from './focus-classes' ;
7
- import { PlatformModule } from '../platform/index' ;
8
- import { Platform } from '../platform/platform' ;
9
-
10
-
11
- // NOTE: Firefox only fires focus & blur events when it is the currently active window.
12
- // This is not always the case on our CI setup, therefore we disable tests that depend on these
13
- // events firing for Firefox. We may be able to fix this by configuring our CI to start Firefox with
14
- // the following preference: focusmanager.testmode = true
15
-
16
7
17
8
describe ( 'FocusOriginMonitor' , ( ) => {
18
9
let fixture : ComponentFixture < PlainButton > ;
19
10
let buttonElement : HTMLElement ;
20
11
let buttonRenderer : Renderer ;
21
12
let focusOriginMonitor : FocusOriginMonitor ;
22
- let platform : Platform ;
23
13
24
14
beforeEach ( async ( ( ) => {
25
15
TestBed . configureTestingModule ( {
26
- imports : [ StyleModule , PlatformModule ] ,
16
+ imports : [ StyleModule ] ,
27
17
declarations : [
28
18
PlainButton ,
29
19
] ,
@@ -32,21 +22,21 @@ describe('FocusOriginMonitor', () => {
32
22
TestBed . compileComponents ( ) ;
33
23
} ) ) ;
34
24
35
- beforeEach ( inject ( [ FocusOriginMonitor , Platform ] , ( fom : FocusOriginMonitor , pfm : Platform ) => {
25
+ beforeEach ( inject ( [ FocusOriginMonitor ] , ( fom : FocusOriginMonitor ) => {
36
26
fixture = TestBed . createComponent ( PlainButton ) ;
37
27
fixture . detectChanges ( ) ;
38
28
39
29
buttonElement = fixture . debugElement . query ( By . css ( 'button' ) ) . nativeElement ;
40
30
buttonRenderer = fixture . componentInstance . renderer ;
41
31
focusOriginMonitor = fom ;
42
- platform = pfm ;
43
32
44
33
focusOriginMonitor . registerElementForFocusClasses ( buttonElement , buttonRenderer ) ;
34
+
35
+ // Patch the element focus to properly emit focus events when the browser is blurred.
36
+ patchElementFocus ( buttonElement ) ;
45
37
} ) ) ;
46
38
47
39
it ( 'manually registered element should receive focus classes' , async ( ( ) => {
48
- if ( platform . FIREFOX ) { return ; }
49
-
50
40
buttonElement . focus ( ) ;
51
41
fixture . detectChanges ( ) ;
52
42
@@ -59,8 +49,6 @@ describe('FocusOriginMonitor', () => {
59
49
} ) ) ;
60
50
61
51
it ( 'should detect focus via keyboard' , async ( ( ) => {
62
- if ( platform . FIREFOX ) { return ; }
63
-
64
52
// Simulate focus via keyboard.
65
53
dispatchKeydownEvent ( document , TAB ) ;
66
54
buttonElement . focus ( ) ;
@@ -79,8 +67,6 @@ describe('FocusOriginMonitor', () => {
79
67
} ) ) ;
80
68
81
69
it ( 'should detect focus via mouse' , async ( ( ) => {
82
- if ( platform . FIREFOX ) { return ; }
83
-
84
70
// Simulate focus via mouse.
85
71
dispatchMousedownEvent ( document ) ;
86
72
buttonElement . focus ( ) ;
@@ -99,8 +85,6 @@ describe('FocusOriginMonitor', () => {
99
85
} ) ) ;
100
86
101
87
it ( 'should detect programmatic focus' , async ( ( ) => {
102
- if ( platform . FIREFOX ) { return ; }
103
-
104
88
// Programmatically focus.
105
89
buttonElement . focus ( ) ;
106
90
fixture . detectChanges ( ) ;
@@ -118,8 +102,6 @@ describe('FocusOriginMonitor', () => {
118
102
} ) ) ;
119
103
120
104
it ( 'focusVia keyboard should simulate keyboard focus' , async ( ( ) => {
121
- if ( platform . FIREFOX ) { return ; }
122
-
123
105
focusOriginMonitor . focusVia ( buttonElement , buttonRenderer , 'keyboard' ) ;
124
106
fixture . detectChanges ( ) ;
125
107
@@ -136,8 +118,6 @@ describe('FocusOriginMonitor', () => {
136
118
} ) ) ;
137
119
138
120
it ( 'focusVia mouse should simulate mouse focus' , async ( ( ) => {
139
- if ( platform . FIREFOX ) { return ; }
140
-
141
121
focusOriginMonitor . focusVia ( buttonElement , buttonRenderer , 'mouse' ) ;
142
122
fixture . detectChanges ( ) ;
143
123
@@ -154,8 +134,6 @@ describe('FocusOriginMonitor', () => {
154
134
} ) ) ;
155
135
156
136
it ( 'focusVia program should simulate programmatic focus' , async ( ( ) => {
157
- if ( platform . FIREFOX ) { return ; }
158
-
159
137
focusOriginMonitor . focusVia ( buttonElement , buttonRenderer , 'program' ) ;
160
138
fixture . detectChanges ( ) ;
161
139
@@ -176,11 +154,10 @@ describe('FocusOriginMonitor', () => {
176
154
describe ( 'cdkFocusClasses' , ( ) => {
177
155
let fixture : ComponentFixture < ButtonWithFocusClasses > ;
178
156
let buttonElement : HTMLElement ;
179
- let platform : Platform ;
180
157
181
158
beforeEach ( async ( ( ) => {
182
159
TestBed . configureTestingModule ( {
183
- imports : [ StyleModule , PlatformModule ] ,
160
+ imports : [ StyleModule ] ,
184
161
declarations : [
185
162
ButtonWithFocusClasses ,
186
163
] ,
@@ -189,21 +166,21 @@ describe('cdkFocusClasses', () => {
189
166
TestBed . compileComponents ( ) ;
190
167
} ) ) ;
191
168
192
- beforeEach ( inject ( [ Platform ] , ( pfm : Platform ) => {
169
+ beforeEach ( ( ) => {
193
170
fixture = TestBed . createComponent ( ButtonWithFocusClasses ) ;
194
171
fixture . detectChanges ( ) ;
195
172
196
173
buttonElement = fixture . debugElement . query ( By . css ( 'button' ) ) . nativeElement ;
197
- platform = pfm ;
198
- } ) ) ;
174
+
175
+ // Patch the element focus to properly emit focus events when the browser is blurred.
176
+ patchElementFocus ( buttonElement ) ;
177
+ } ) ;
199
178
200
179
it ( 'should initially not be focused' , ( ) => {
201
180
expect ( buttonElement . classList . length ) . toBe ( 0 , 'button should not have focus classes' ) ;
202
181
} ) ;
203
182
204
183
it ( 'should detect focus via keyboard' , async ( ( ) => {
205
- if ( platform . FIREFOX ) { return ; }
206
-
207
184
// Simulate focus via keyboard.
208
185
dispatchKeydownEvent ( document , TAB ) ;
209
186
buttonElement . focus ( ) ;
@@ -222,8 +199,6 @@ describe('cdkFocusClasses', () => {
222
199
} ) ) ;
223
200
224
201
it ( 'should detect focus via mouse' , async ( ( ) => {
225
- if ( platform . FIREFOX ) { return ; }
226
-
227
202
// Simulate focus via mouse.
228
203
dispatchMousedownEvent ( document ) ;
229
204
buttonElement . focus ( ) ;
@@ -242,8 +217,6 @@ describe('cdkFocusClasses', () => {
242
217
} ) ) ;
243
218
244
219
it ( 'should detect programmatic focus' , async ( ( ) => {
245
- if ( platform . FIREFOX ) { return ; }
246
-
247
220
// Programmatically focus.
248
221
buttonElement . focus ( ) ;
249
222
fixture . detectChanges ( ) ;
@@ -271,6 +244,7 @@ class PlainButton {
271
244
@Component ( { template : `<button cdkFocusClasses>focus me!</button>` } )
272
245
class ButtonWithFocusClasses { }
273
246
247
+ // TODO(devversion): move helper functions into a global utility file. See #2902
274
248
275
249
/** Dispatches a mousedown event on the specified element. */
276
250
function dispatchMousedownEvent ( element : Node ) {
@@ -291,3 +265,22 @@ function dispatchKeydownEvent(element: Node, keyCode: number) {
291
265
} ) ;
292
266
element . dispatchEvent ( event ) ;
293
267
}
268
+
269
+ /** Dispatches a focus event on the specified element. */
270
+ function dispatchFocusEvent ( element : Node , type = 'focus' ) {
271
+ let event = document . createEvent ( 'Event' ) ;
272
+ event . initEvent ( type , true , true ) ;
273
+ element . dispatchEvent ( event ) ;
274
+ }
275
+
276
+ /** Patches an elements focus method to properly emit focus events when the browser is blurred. */
277
+ function patchElementFocus ( element : HTMLElement ) {
278
+ // On Saucelabs, browsers will run simultaneously and therefore can't focus all browser windows
279
+ // at the same time. This is problematic when testing focus states. Chrome and Firefox
280
+ // only fire FocusEvents when the window is focused. This issue also appears locally.
281
+ let _nativeButtonFocus = element . focus . bind ( element ) ;
282
+
283
+ element . focus = ( ) => {
284
+ document . hasFocus ( ) ? _nativeButtonFocus ( ) : dispatchFocusEvent ( element ) ;
285
+ } ;
286
+ }
0 commit comments