1- import { ComponentFixture , TestBed , waitForAsync } from '@angular/core/testing' ;
1+ import { ComponentFixture , TestBed , waitForAsync , fakeAsync , flush } from '@angular/core/testing' ;
22
33import { ExpandableNavbarSectionComponent } from './expandable-navbar-section.component' ;
44import { By } from '@angular/platform-browser' ;
55import { MenuServiceStub } from '../../shared/testing/menu-service.stub' ;
6- import { Component } from '@angular/core' ;
6+ import { Component , DebugElement } from '@angular/core' ;
77import { of as observableOf } from 'rxjs' ;
88import { HostWindowService } from '../../shared/host-window.service' ;
99import { MenuService } from '../../shared/menu/menu.service' ;
10+ import { LinkMenuItemModel } from '../../shared/menu/menu-item/models/link.model' ;
11+ import { MenuSection } from '../../shared/menu/menu-section.model' ;
1012import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub' ;
1113import { NoopAnimationsModule } from '@angular/platform-browser/animations' ;
12- import { VarDirective } from '../../shared/utils/var .directive' ;
14+ import { HoverOutsideDirective } from '../../shared/utils/hover-outside .directive' ;
1315
1416describe ( 'ExpandableNavbarSectionComponent' , ( ) => {
1517 let component : ExpandableNavbarSectionComponent ;
@@ -20,18 +22,18 @@ describe('ExpandableNavbarSectionComponent', () => {
2022 beforeEach ( waitForAsync ( ( ) => {
2123 TestBed . configureTestingModule ( {
2224 imports : [ NoopAnimationsModule ] ,
23- declarations : [ ExpandableNavbarSectionComponent , TestComponent , VarDirective ] ,
25+ declarations : [
26+ ExpandableNavbarSectionComponent ,
27+ HoverOutsideDirective ,
28+ TestComponent ,
29+ ] ,
2430 providers : [
2531 { provide : 'sectionDataProvider' , useValue : { } } ,
2632 { provide : MenuService , useValue : menuService } ,
27- { provide : HostWindowService , useValue : new HostWindowServiceStub ( 800 ) }
28- ]
29- } ) . overrideComponent ( ExpandableNavbarSectionComponent , {
30- set : {
31- entryComponents : [ TestComponent ]
32- }
33- } )
34- . compileComponents ( ) ;
33+ { provide : HostWindowService , useValue : new HostWindowServiceStub ( 800 ) } ,
34+ TestComponent ,
35+ ] ,
36+ } ) . compileComponents ( ) ;
3537 } ) ) ;
3638
3739 beforeEach ( ( ) => {
@@ -43,10 +45,6 @@ describe('ExpandableNavbarSectionComponent', () => {
4345 fixture . detectChanges ( ) ;
4446 } ) ;
4547
46- it ( 'should create' , ( ) => {
47- expect ( component ) . toBeTruthy ( ) ;
48- } ) ;
49-
5048 describe ( 'when the mouse enters the section header (while inactive)' , ( ) => {
5149 beforeEach ( ( ) => {
5250 spyOn ( component , 'onMouseEnter' ) . and . callThrough ( ) ;
@@ -143,6 +141,8 @@ describe('ExpandableNavbarSectionComponent', () => {
143141 } ) ;
144142
145143 describe ( 'when spacebar is pressed on section header (while inactive)' , ( ) => {
144+ let sidebarToggler : DebugElement ;
145+
146146 beforeEach ( ( ) => {
147147 spyOn ( component , 'toggleSection' ) . and . callThrough ( ) ;
148148 spyOn ( menuService , 'toggleActiveSection' ) ;
@@ -151,15 +151,27 @@ describe('ExpandableNavbarSectionComponent', () => {
151151 component . ngOnInit ( ) ;
152152 fixture . detectChanges ( ) ;
153153
154- const sidebarToggler = fixture . debugElement . query ( By . css ( '[data-test="navbar-section-toggler"]' ) ) ;
155- // dispatch the (keyup.space) action used in our component HTML
156- sidebarToggler . nativeElement . dispatchEvent ( new KeyboardEvent ( 'keyup' , { key : ' ' } ) ) ;
154+ sidebarToggler = fixture . debugElement . query ( By . css ( '[data-test="navbar-section-toggler"]' ) ) ;
157155 } ) ;
158156
159157 it ( 'should call toggleSection on the menuService' , ( ) => {
158+ // dispatch the (keyup.space) action used in our component HTML
159+ sidebarToggler . nativeElement . dispatchEvent ( new KeyboardEvent ( 'keyup' , { code : 'Space' , key : ' ' } ) ) ;
160+
160161 expect ( component . toggleSection ) . toHaveBeenCalled ( ) ;
161162 expect ( menuService . toggleActiveSection ) . toHaveBeenCalled ( ) ;
162163 } ) ;
164+
165+ // Should not do anything in order to work correctly with NVDA: https://www.nvaccess.org/
166+ it ( 'should not do anything on keydown space' , ( ) => {
167+ const event : Event = new KeyboardEvent ( 'keydown' , { code : 'Space' , key : ' ' } ) ;
168+ spyOn ( event , 'preventDefault' ) . and . callThrough ( ) ;
169+
170+ // dispatch the (keyup.space) action used in our component HTML
171+ sidebarToggler . nativeElement . dispatchEvent ( event ) ;
172+
173+ expect ( event . preventDefault ) . toHaveBeenCalled ( ) ;
174+ } ) ;
163175 } ) ;
164176
165177 describe ( 'when spacebar is pressed on section header (while active)' , ( ) => {
@@ -181,13 +193,116 @@ describe('ExpandableNavbarSectionComponent', () => {
181193 expect ( menuService . toggleActiveSection ) . toHaveBeenCalled ( ) ;
182194 } ) ;
183195 } ) ;
196+
197+ describe ( 'when enter is pressed on section header (while inactive)' , ( ) => {
198+ let sidebarToggler : DebugElement ;
199+
200+ beforeEach ( ( ) => {
201+ spyOn ( component , 'toggleSection' ) . and . callThrough ( ) ;
202+ spyOn ( menuService , 'toggleActiveSection' ) ;
203+ // Make sure section is 'inactive'. Requires calling ngOnInit() to update component 'active' property.
204+ spyOn ( menuService , 'isSectionActive' ) . and . returnValue ( observableOf ( false ) ) ;
205+ component . ngOnInit ( ) ;
206+ fixture . detectChanges ( ) ;
207+
208+ sidebarToggler = fixture . debugElement . query ( By . css ( '[data-test="navbar-section-toggler"]' ) ) ;
209+ } ) ;
210+
211+ // Should not do anything in order to work correctly with NVDA: https://www.nvaccess.org/
212+ it ( 'should not do anything on keydown space' , ( ) => {
213+ const event : Event = new KeyboardEvent ( 'keydown' , { code : 'Enter' } ) ;
214+ spyOn ( event , 'preventDefault' ) . and . callThrough ( ) ;
215+
216+ // dispatch the (keyup.space) action used in our component HTML
217+ sidebarToggler . nativeElement . dispatchEvent ( event ) ;
218+
219+ expect ( event . preventDefault ) . toHaveBeenCalled ( ) ;
220+ } ) ;
221+ } ) ;
222+
223+ describe ( 'when arrow down is pressed on section header' , ( ) => {
224+ it ( 'should call activateSection' , ( ) => {
225+ spyOn ( component , 'activateSection' ) . and . callThrough ( ) ;
226+
227+ const sidebarToggler : DebugElement = fixture . debugElement . query ( By . css ( '[data-test="navbar-section-toggler"]' ) ) ;
228+ // dispatch the (keydown.ArrowDown) action used in our component HTML
229+ sidebarToggler . nativeElement . dispatchEvent ( new KeyboardEvent ( 'keydown' , { code : 'ArrowDown' } ) ) ;
230+
231+ expect ( component . focusOnFirstChildSection ) . toBe ( true ) ;
232+ expect ( component . activateSection ) . toHaveBeenCalled ( ) ;
233+ } ) ;
234+ } ) ;
235+
236+ describe ( 'when tab is pressed on section header' , ( ) => {
237+ it ( 'should call deactivateSection' , ( ) => {
238+ spyOn ( component , 'deactivateSection' ) . and . callThrough ( ) ;
239+
240+ const sidebarToggler : DebugElement = fixture . debugElement . query ( By . css ( '[data-test="navbar-section-toggler"]' ) ) ;
241+ // dispatch the (keydown.ArrowDown) action used in our component HTML
242+ sidebarToggler . nativeElement . dispatchEvent ( new KeyboardEvent ( 'keydown' , { code : 'Tab' } ) ) ;
243+
244+ expect ( component . deactivateSection ) . toHaveBeenCalled ( ) ;
245+ } ) ;
246+ } ) ;
247+
248+ describe ( 'navigateDropdown' , ( ) => {
249+ beforeEach ( fakeAsync ( ( ) => {
250+ jasmine . getEnv ( ) . allowRespy ( true ) ;
251+ spyOn ( menuService , 'getSubSectionsByParentID' ) . and . returnValue ( observableOf ( [
252+ Object . assign ( new MenuSection ( ) , {
253+ id : 'subSection1' ,
254+ model : Object . assign ( new LinkMenuItemModel ( ) , {
255+ type : 'TEST_LINK' ,
256+ } ) ,
257+ parentId : component . section . id ,
258+ } ) ,
259+ Object . assign ( new MenuSection ( ) , {
260+ id : 'subSection2' ,
261+ model : Object . assign ( new LinkMenuItemModel ( ) , {
262+ type : 'TEST_LINK' ,
263+ } ) ,
264+ parentId : component . section . id ,
265+ } ) ,
266+ ] ) ) ;
267+ component . ngOnInit ( ) ;
268+ flush ( ) ;
269+ fixture . detectChanges ( ) ;
270+ component . focusOnFirstChildSection = true ;
271+ component . active$ . next ( true ) ;
272+ fixture . detectChanges ( ) ;
273+ } ) ) ;
274+
275+ it ( 'should close the modal on Tab' , ( ) => {
276+ spyOn ( menuService , 'deactivateSection' ) . and . callThrough ( ) ;
277+
278+ const firstSubsection : DebugElement = fixture . debugElement . queryAll ( By . css ( '.dropdown-menu a[role="menuitem"]' ) ) [ 0 ] ;
279+ firstSubsection . nativeElement . focus ( ) ;
280+ firstSubsection . nativeElement . dispatchEvent ( new KeyboardEvent ( 'keydown' , { code : 'Tab' } ) ) ;
281+
282+ expect ( menuService . deactivateSection ) . toHaveBeenCalled ( ) ;
283+ } ) ;
284+
285+ it ( 'should close the modal on Escape' , ( ) => {
286+ spyOn ( menuService , 'deactivateSection' ) . and . callThrough ( ) ;
287+
288+ const firstSubsection : DebugElement = fixture . debugElement . queryAll ( By . css ( '.dropdown-menu a[role="menuitem"]' ) ) [ 0 ] ;
289+ firstSubsection . nativeElement . focus ( ) ;
290+ firstSubsection . nativeElement . dispatchEvent ( new KeyboardEvent ( 'keydown' , { code : 'Escape' } ) ) ;
291+
292+ expect ( menuService . deactivateSection ) . toHaveBeenCalled ( ) ;
293+ } ) ;
294+ } ) ;
184295 } ) ;
185296
186297 describe ( 'on smaller, mobile screens' , ( ) => {
187298 beforeEach ( waitForAsync ( ( ) => {
188299 TestBed . configureTestingModule ( {
189300 imports : [ NoopAnimationsModule ] ,
190- declarations : [ ExpandableNavbarSectionComponent , TestComponent , VarDirective ] ,
301+ declarations : [
302+ ExpandableNavbarSectionComponent ,
303+ HoverOutsideDirective ,
304+ TestComponent ,
305+ ] ,
191306 providers : [
192307 { provide : 'sectionDataProvider' , useValue : { } } ,
193308 { provide : MenuService , useValue : menuService } ,
@@ -261,7 +376,9 @@ describe('ExpandableNavbarSectionComponent', () => {
261376// declare a test component
262377@Component ( {
263378 selector : 'ds-test-cmp' ,
264- template : ``
379+ template : `
380+ <a role="menuitem">link</a>
381+ ` ,
265382} )
266383class TestComponent {
267384}
0 commit comments