@@ -4,26 +4,16 @@ import {StyleModule} from './index';
44import { By } from '@angular/platform-browser' ;
55import { TAB } from '../keyboard/keycodes' ;
66import { 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-
167
178describe ( 'FocusOriginMonitor' , ( ) => {
189 let fixture : ComponentFixture < PlainButton > ;
1910 let buttonElement : HTMLElement ;
2011 let buttonRenderer : Renderer ;
2112 let focusOriginMonitor : FocusOriginMonitor ;
22- let platform : Platform ;
2313
2414 beforeEach ( async ( ( ) => {
2515 TestBed . configureTestingModule ( {
26- imports : [ StyleModule , PlatformModule ] ,
16+ imports : [ StyleModule ] ,
2717 declarations : [
2818 PlainButton ,
2919 ] ,
@@ -32,21 +22,21 @@ describe('FocusOriginMonitor', () => {
3222 TestBed . compileComponents ( ) ;
3323 } ) ) ;
3424
35- beforeEach ( inject ( [ FocusOriginMonitor , Platform ] , ( fom : FocusOriginMonitor , pfm : Platform ) => {
25+ beforeEach ( inject ( [ FocusOriginMonitor ] , ( fom : FocusOriginMonitor ) => {
3626 fixture = TestBed . createComponent ( PlainButton ) ;
3727 fixture . detectChanges ( ) ;
3828
3929 buttonElement = fixture . debugElement . query ( By . css ( 'button' ) ) . nativeElement ;
4030 buttonRenderer = fixture . componentInstance . renderer ;
4131 focusOriginMonitor = fom ;
42- platform = pfm ;
4332
4433 focusOriginMonitor . registerElementForFocusClasses ( buttonElement , buttonRenderer ) ;
34+
35+ // Patch the element focus to properly emit focus events when the browser is blurred.
36+ patchElementFocus ( buttonElement ) ;
4537 } ) ) ;
4638
4739 it ( 'manually registered element should receive focus classes' , async ( ( ) => {
48- if ( platform . FIREFOX ) { return ; }
49-
5040 buttonElement . focus ( ) ;
5141 fixture . detectChanges ( ) ;
5242
@@ -59,8 +49,6 @@ describe('FocusOriginMonitor', () => {
5949 } ) ) ;
6050
6151 it ( 'should detect focus via keyboard' , async ( ( ) => {
62- if ( platform . FIREFOX ) { return ; }
63-
6452 // Simulate focus via keyboard.
6553 dispatchKeydownEvent ( document , TAB ) ;
6654 buttonElement . focus ( ) ;
@@ -79,8 +67,6 @@ describe('FocusOriginMonitor', () => {
7967 } ) ) ;
8068
8169 it ( 'should detect focus via mouse' , async ( ( ) => {
82- if ( platform . FIREFOX ) { return ; }
83-
8470 // Simulate focus via mouse.
8571 dispatchMousedownEvent ( document ) ;
8672 buttonElement . focus ( ) ;
@@ -99,8 +85,6 @@ describe('FocusOriginMonitor', () => {
9985 } ) ) ;
10086
10187 it ( 'should detect programmatic focus' , async ( ( ) => {
102- if ( platform . FIREFOX ) { return ; }
103-
10488 // Programmatically focus.
10589 buttonElement . focus ( ) ;
10690 fixture . detectChanges ( ) ;
@@ -118,8 +102,6 @@ describe('FocusOriginMonitor', () => {
118102 } ) ) ;
119103
120104 it ( 'focusVia keyboard should simulate keyboard focus' , async ( ( ) => {
121- if ( platform . FIREFOX ) { return ; }
122-
123105 focusOriginMonitor . focusVia ( buttonElement , buttonRenderer , 'keyboard' ) ;
124106 fixture . detectChanges ( ) ;
125107
@@ -136,8 +118,6 @@ describe('FocusOriginMonitor', () => {
136118 } ) ) ;
137119
138120 it ( 'focusVia mouse should simulate mouse focus' , async ( ( ) => {
139- if ( platform . FIREFOX ) { return ; }
140-
141121 focusOriginMonitor . focusVia ( buttonElement , buttonRenderer , 'mouse' ) ;
142122 fixture . detectChanges ( ) ;
143123
@@ -154,8 +134,6 @@ describe('FocusOriginMonitor', () => {
154134 } ) ) ;
155135
156136 it ( 'focusVia program should simulate programmatic focus' , async ( ( ) => {
157- if ( platform . FIREFOX ) { return ; }
158-
159137 focusOriginMonitor . focusVia ( buttonElement , buttonRenderer , 'program' ) ;
160138 fixture . detectChanges ( ) ;
161139
@@ -176,11 +154,10 @@ describe('FocusOriginMonitor', () => {
176154describe ( 'cdkFocusClasses' , ( ) => {
177155 let fixture : ComponentFixture < ButtonWithFocusClasses > ;
178156 let buttonElement : HTMLElement ;
179- let platform : Platform ;
180157
181158 beforeEach ( async ( ( ) => {
182159 TestBed . configureTestingModule ( {
183- imports : [ StyleModule , PlatformModule ] ,
160+ imports : [ StyleModule ] ,
184161 declarations : [
185162 ButtonWithFocusClasses ,
186163 ] ,
@@ -189,21 +166,21 @@ describe('cdkFocusClasses', () => {
189166 TestBed . compileComponents ( ) ;
190167 } ) ) ;
191168
192- beforeEach ( inject ( [ Platform ] , ( pfm : Platform ) => {
169+ beforeEach ( ( ) => {
193170 fixture = TestBed . createComponent ( ButtonWithFocusClasses ) ;
194171 fixture . detectChanges ( ) ;
195172
196173 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+ } ) ;
199178
200179 it ( 'should initially not be focused' , ( ) => {
201180 expect ( buttonElement . classList . length ) . toBe ( 0 , 'button should not have focus classes' ) ;
202181 } ) ;
203182
204183 it ( 'should detect focus via keyboard' , async ( ( ) => {
205- if ( platform . FIREFOX ) { return ; }
206-
207184 // Simulate focus via keyboard.
208185 dispatchKeydownEvent ( document , TAB ) ;
209186 buttonElement . focus ( ) ;
@@ -222,8 +199,6 @@ describe('cdkFocusClasses', () => {
222199 } ) ) ;
223200
224201 it ( 'should detect focus via mouse' , async ( ( ) => {
225- if ( platform . FIREFOX ) { return ; }
226-
227202 // Simulate focus via mouse.
228203 dispatchMousedownEvent ( document ) ;
229204 buttonElement . focus ( ) ;
@@ -242,8 +217,6 @@ describe('cdkFocusClasses', () => {
242217 } ) ) ;
243218
244219 it ( 'should detect programmatic focus' , async ( ( ) => {
245- if ( platform . FIREFOX ) { return ; }
246-
247220 // Programmatically focus.
248221 buttonElement . focus ( ) ;
249222 fixture . detectChanges ( ) ;
@@ -271,6 +244,7 @@ class PlainButton {
271244@Component ( { template : `<button cdkFocusClasses>focus me!</button>` } )
272245class ButtonWithFocusClasses { }
273246
247+ // TODO(devversion): move helper functions into a global utility file. See #2902
274248
275249/** Dispatches a mousedown event on the specified element. */
276250function dispatchMousedownEvent ( element : Node ) {
@@ -291,3 +265,22 @@ function dispatchKeydownEvent(element: Node, keyCode: number) {
291265 } ) ;
292266 element . dispatchEvent ( event ) ;
293267}
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