UNPKG

igniteui-angular-sovn

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

1,007 lines (893 loc) 76.5 kB
import { Component, ViewChild } from '@angular/core'; import { TestBed, ComponentFixture, tick, fakeAsync, waitForAsync } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { IgxExpansionPanelComponent } from './expansion-panel.component'; import { ExpansionPanelHeaderIconPosition, IgxExpansionPanelHeaderComponent } from './expansion-panel-header.component'; import { IgxGridComponent } from '../grids/grid/public_api'; import { IgxExpansionPanelDescriptionDirective, IgxExpansionPanelIconDirective, IgxExpansionPanelTitleDirective } from './expansion-panel.directives'; import { configureTestSuite } from '../test-utils/configure-suite'; import { By } from '@angular/platform-browser'; import { IgxExpansionPanelBodyComponent } from './expansion-panel-body.component'; import { IgxListComponent } from '../list/list.component'; import { IgxListItemComponent } from '../list/list-item.component'; import { NgIf } from '@angular/common'; import { IGX_EXPANSION_PANEL_DIRECTIVES } from './public_api'; const CSS_CLASS_EXPANSION_PANEL = 'igx-expansion-panel'; const CSS_CLASS_PANEL_HEADER = 'igx-expansion-panel__header'; const CSS_CLASS_PANEL_HEADER_TITLE = 'igx-expansion-panel__header-title'; const CSS_CLASS_PANEL_HEADER_DESCRIPTION = 'igx-expansion-panel__header-description'; const CSS_CLASS_PANEL_TITLE_WRAPPER = 'igx-expansion-panel__title-wrapper'; const CSS_CLASS_PANEL_BODY = 'igx-expansion-panel-body'; const CSS_CLASS_HEADER_EXPANDED = 'igx-expansion-panel__header--expanded'; const CSS_CLASS_HEADER_ICON_START = 'igx-expansion-panel__header-icon--start'; const CSS_CLASS_HEADER_ICON_END = 'igx-expansion-panel__header-icon--end'; const CSS_CLASS_HEADER_ICON_NONE = 'igx-expansion-panel__header-icon--none'; const CSS_CLASS_PANEL_ICON = 'igx-icon'; const CSS_CLASS_LIST = 'igx-list'; const CSS_CLASS_GRID = 'igx-grid'; const enum IconPositionClass { LEFT = 'igx-expansion-panel__header-icon--start', RIGHT = 'igx-expansion-panel__header-icon--end', NONE = 'igx-expansion-panel__header-icon--none', } describe('igxExpansionPanel', () => { configureTestSuite(); beforeAll(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, IgxExpansionPanelGridComponent, IgxExpansionPanelListComponent, IgxExpansionPanelSampleComponent, IgxExpansionPanelImageComponent, IgxExpansionPanelTooltipComponent ] }).compileComponents(); })); describe('General tests: ', () => { // configureTestSuite(); it('Should initialize the expansion panel component properly', () => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const header = fixture.componentInstance.header; expect(fixture.componentInstance).toBeDefined(); expect(panel).toBeDefined(); // expect(panel.toggleBtn).toBeDefined(); expect(header.disabled).toBeDefined(); expect(header.disabled).toEqual(false); // expect(panel.ariaLabelledBy).toBeDefined(); // expect(panel.ariaLabelledBy).toEqual(''); expect(panel.animationSettings).toBeDefined(); expect(panel.collapsed).toBeDefined(); expect(panel.collapsed).toBeTruthy(); panel.toggle(); fixture.detectChanges(); expect(panel.collapsed).toEqual(false); }); it('Should properly accept input properties', () => { const fixture = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; // expect(panel.disabled).toEqual(false); // expect(panel.collapsed).toEqual(true); // // expect(panel.ariaLabelledBy).toEqual(''); // panel.disabled = true; // expect(panel.disabled).toEqual(true); panel.collapsed = false; expect(panel.collapsed).toEqual(false); // panel.labelledby = 'test label area'; // expect(panel.labelledby).toEqual('test label area'); }); it('Should properly set base classes', () => { const fixture = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const header = document.getElementsByClassName(CSS_CLASS_PANEL_HEADER); const headerExpanded = document.getElementsByClassName(CSS_CLASS_HEADER_EXPANDED); const panelClass = document.getElementsByClassName(CSS_CLASS_EXPANSION_PANEL); expect(header.length).toEqual(1); expect(headerExpanded.length).toEqual(0); expect(panelClass.length).toEqual(1); }); it('Should properly emit events', fakeAsync(() => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); const panel = fixture.componentInstance.panel; const header = fixture.componentInstance.header; const mockEvent = new Event('click'); expect(panel).toBeTruthy(); expect(header).toBeTruthy(); expect(header.disabled).toEqual(false); expect(header.panel).toEqual(panel); expect(header.interaction).toBeDefined(); spyOn(panel.contentCollapsed, 'emit'); spyOn(panel.contentExpanded, 'emit'); spyOn(panel.contentCollapsing, 'emit'); spyOn(panel.contentExpanding, 'emit'); spyOn(header.interaction, 'emit').and.callThrough(); spyOn(panel, 'toggle').and.callThrough(); spyOn(panel, 'expand').and.callThrough(); spyOn(panel, 'collapse').and.callThrough(); header.onAction(mockEvent); tick(); fixture.detectChanges(); expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(0); // Initially collapsed expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(0); expect(header.interaction.emit).toHaveBeenCalledTimes(1); expect(panel.toggle).toHaveBeenCalledTimes(1); expect(panel.toggle).toHaveBeenCalledWith(mockEvent); expect(panel.expand).toHaveBeenCalledTimes(1); expect(panel.expand).toHaveBeenCalledWith(mockEvent); expect(panel.collapse).toHaveBeenCalledTimes(0); expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1); expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1); expect(header.interaction.emit).toHaveBeenCalledWith({ event: mockEvent, owner: header.panel, cancel: false }); header.onAction(mockEvent); tick(); fixture.detectChanges(); expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1); // First Collapse expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(1); expect(header.interaction.emit).toHaveBeenCalledTimes(2); expect(panel.toggle).toHaveBeenCalledTimes(2); expect(panel.toggle).toHaveBeenCalledWith(mockEvent); expect(panel.expand).toHaveBeenCalledTimes(1); expect(panel.collapse).toHaveBeenCalledTimes(1); expect(panel.collapse).toHaveBeenCalledWith(mockEvent); header.disabled = true; header.onAction(mockEvent); tick(); fixture.detectChanges(); // No additional calls, because panel.disabled === true expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1); expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(1); expect(header.interaction.emit).toHaveBeenCalledTimes(2); expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1); expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1); // cancel event header.disabled = false; const headerSub = header.interaction.subscribe((event) => { event.cancel = true; }); // currently collapsed expect(panel.collapsed).toBeTruthy(); header.onAction(mockEvent); tick(); fixture.detectChanges(); // still collapsed, no additional contentExpanded calls expect(panel.collapsed).toBeTruthy(); expect(header.interaction.emit).toHaveBeenCalledTimes(3); expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1); expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1); // expand via API panel.expand(); tick(); fixture.detectChanges(); // currently expanded expect(panel.collapsed).toBeFalsy(); header.onAction(mockEvent); tick(); fixture.detectChanges(); // still expanded, no additional contentCollapsed calls headerSub.unsubscribe(); expect(panel.collapsed).toBeFalsy(); expect(header.interaction.emit).toHaveBeenCalledTimes(4); expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1); // collapse when the panel has already started collapsing header.onAction(mockEvent); header.onAction(mockEvent); tick(); fixture.detectChanges(); expect(panel.collapsed).toBeTruthy(); expect(header.interaction.emit).toHaveBeenCalledTimes(6); expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(2); })); it('Should expand/collapse without animation when animationSettings === null', fakeAsync(() => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); const panel = fixture.componentInstance.panel; panel.animationSettings = null; expect(panel).toBeTruthy(); spyOn(panel.contentCollapsed, 'emit'); spyOn(panel.contentExpanded, 'emit'); spyOn(panel.contentCollapsing, 'emit'); spyOn(panel.contentExpanding, 'emit'); panel.toggle(); tick(); fixture.detectChanges(); expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(0); // Initially collapsed expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(0); expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1); expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1); expect(panel.contentExpanding.emit).toHaveBeenCalledBefore(panel.contentExpanded.emit); expect(panel.collapsed).toBeFalsy(); panel.toggle(); tick(); fixture.detectChanges(); expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1); expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(1); expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1); expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1); expect(panel.contentCollapsing.emit).toHaveBeenCalledBefore(panel.contentCollapsed.emit); expect(panel.collapsed).toBeTruthy(); })); it('Should allow expanding and collapsing events to be cancelled', fakeAsync(() => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); const panel = fixture.componentInstance.panel; spyOn(panel.contentExpanded, 'emit').and.callThrough(); spyOn(panel.contentCollapsed, 'emit').and.callThrough(); expect(panel).toBeDefined(); expect(panel.collapsed).toBeTruthy(); expect(panel.contentExpanded.emit).not.toHaveBeenCalled(); expect(panel.contentCollapsed.emit).not.toHaveBeenCalled(); let sub = panel.contentExpanding.subscribe((e) => e.cancel = true); panel.expand(); tick(); fixture.detectChanges(); expect(panel.collapsed).toBeTruthy(); expect(panel.contentExpanded.emit).not.toHaveBeenCalled(); sub.unsubscribe(); panel.expand(); tick(); fixture.detectChanges(); expect(panel.collapsed).toBeFalsy(); expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1); sub = panel.contentCollapsing.subscribe((e) => e.cancel = true); panel.collapse(); tick(); fixture.detectChanges(); expect(panel.collapsed).toBeFalsy(); expect(panel.contentCollapsed.emit).not.toHaveBeenCalled(); sub.unsubscribe(); panel.collapse(); tick(); fixture.detectChanges(); expect(panel.collapsed).toBeTruthy(); expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1); })); it('Should NOT assign tabIndex to header when disabled', () => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); const panelHeader = fixture.componentInstance.header; expect(panelHeader).toBeDefined(); expect(panelHeader.disabled).toBeFalsy(); let innerElement = fixture.debugElement.queryAll(By.css('.igx-expansion-panel__header-inner'))[0]; expect(innerElement).toBeDefined(); expect(innerElement.nativeElement.attributes['tabindex'].value).toBe('0'); panelHeader.disabled = true; fixture.detectChanges(); innerElement = fixture.debugElement.queryAll(By.css('.igx-expansion-panel__header-inner'))[0]; expect(innerElement).toBeDefined(); expect(innerElement.nativeElement.attributes['tabindex']).toBeUndefined(); panelHeader.disabled = false; fixture.detectChanges(); innerElement = fixture.debugElement.queryAll(By.css('.igx-expansion-panel__header-inner'))[0]; expect(innerElement).toBeDefined(); expect(innerElement.nativeElement.attributes['tabindex'].value).toBe('0'); }); }); describe('Expansion tests: ', () => { // configureTestSuite(); const verifyPanelExpansionState = ( collapsed: boolean, panel: IgxExpansionPanelComponent, panelContainer: any, panelHeader: HTMLElement, button: HTMLElement, timesCollapsed = 0, timesExpanded = 0) => { expect(panel.collapsed).toEqual(collapsed); const ariaExpanded = collapsed ? 'false' : 'true'; expect(panelHeader.querySelector('div [role = \'button\']').getAttribute('aria-expanded')).toMatch(ariaExpanded); expect(panelHeader.classList.contains(CSS_CLASS_HEADER_EXPANDED)).toEqual(!collapsed); if (button.children.length > 1) { const iconName = collapsed ? 'expand_more' : 'expand_less'; expect(button.getAttribute('ng-reflect-icon-name')).toMatch(iconName); } if (collapsed) { expect(panelContainer.lastElementChild.nodeName).toEqual('IGX-EXPANSION-PANEL-HEADER'); } else { const panelBody = panelContainer.getElementsByTagName(CSS_CLASS_PANEL_BODY)[0]; expect(panelBody).toBeDefined(); const list = panelBody.getElementsByTagName(CSS_CLASS_LIST)[0]; expect(list).toBeDefined(); } expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(timesExpanded); expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(timesCollapsed); }; it('Should change panel expansion state on header interaction', fakeAsync(() => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const header = fixture.componentInstance.header; const panelContainer = fixture.nativeElement.querySelector('.' + CSS_CLASS_EXPANSION_PANEL); const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; let timesCollapsed = 0; let timesExpanded = 0; spyOn(panel.contentCollapsed, 'emit').and.callThrough(); spyOn(panel.contentExpanded, 'emit').and.callThrough(); spyOn(header.interaction, 'emit'); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panelHeader.click(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(1); panelHeader.click(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(2); panelHeader.click(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(3); // Remove expand/collapse button header.iconPosition = ExpansionPanelHeaderIconPosition.NONE; tick(); fixture.detectChanges(); tick(); panelHeader.click(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(4); panelHeader.click(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(5); })); it('Should change panel expansion state on button clicking', fakeAsync(() => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const header = fixture.componentInstance.header; const panelContainer = fixture.nativeElement.querySelector('.' + CSS_CLASS_EXPANSION_PANEL); const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; let button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; let timesCollapsed = 0; let timesExpanded = 0; spyOn(panel.contentCollapsed, 'emit').and.callThrough(); spyOn(panel.contentExpanded, 'emit').and.callThrough(); spyOn(header.interaction, 'emit'); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); button.click(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(1); button.click(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(2); button.click(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(3); // Change expand/collapse button position header.iconPosition = ExpansionPanelHeaderIconPosition.RIGHT; tick(); fixture.detectChanges(); tick(); button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; button.click(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(4); button.click(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(5); button.click(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(6); })); it('Should change panel expansion state on collapsed property setting', fakeAsync(() => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const panelContainer = fixture.nativeElement.querySelector('.' + CSS_CLASS_EXPANSION_PANEL); const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; spyOn(panel.contentCollapsed, 'emit').and.callThrough(); spyOn(panel.contentExpanded, 'emit').and.callThrough(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button); panel.collapsed = false; tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button); panel.collapsed = true; tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button); panel.collapsed = false; tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button); })); it('Should change panel expansion state using API methods', fakeAsync(() => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const panelContainer = fixture.nativeElement.querySelector('.' + CSS_CLASS_EXPANSION_PANEL); const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; let timesCollapsed = 0; let timesExpanded = 0; spyOn(panel.contentCollapsed, 'emit').and.callThrough(); spyOn(panel.contentExpanded, 'emit').and.callThrough(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.expand(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.collapse(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.expand(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.collapse(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); })); it('Should change panel expansion state using toggle method', fakeAsync(() => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const panelContainer = fixture.nativeElement.querySelector('.' + CSS_CLASS_EXPANSION_PANEL); const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; let timesCollapsed = 0; let timesExpanded = 0; spyOn(panel.contentCollapsed, 'emit').and.callThrough(); spyOn(panel.contentExpanded, 'emit').and.callThrough(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.toggle(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.toggle(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.toggle(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.toggle(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); })); it('Should change panel expansion state on key interaction', fakeAsync(() => { const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' }); const spaceEvent = new KeyboardEvent('keydown', { key: 'Space' }); const arrowUpEvent = new KeyboardEvent('keydown', { key: 'ArrowUp', altKey: true }); const arrowDownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', altKey: true }); const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const header = fixture.componentInstance.header; const panelContainer = fixture.nativeElement.querySelector('.' + CSS_CLASS_EXPANSION_PANEL); const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; let timesCollapsed = 0; let timesExpanded = 0; spyOn(panel.contentCollapsed, 'emit').and.callThrough(); spyOn(panel.contentExpanded, 'emit').and.callThrough(); spyOn(header.interaction, 'emit').and.callThrough(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panelHeader.dispatchEvent(enterEvent); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(1); panelHeader.dispatchEvent(spaceEvent); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(2); panelHeader.dispatchEvent(enterEvent); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(3); panelHeader.dispatchEvent(spaceEvent); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(4); panelHeader.dispatchEvent(arrowUpEvent); tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(5); panelHeader.dispatchEvent(arrowDownEvent); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(6); panelHeader.dispatchEvent(arrowDownEvent); tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(7); panelHeader.dispatchEvent(arrowUpEvent); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(8); // disabled interaction const headerSub = header.interaction.subscribe((event) => { event.cancel = true; }); // currently collapsed expect(panel.collapsed).toEqual(true); // cancel openening panelHeader.dispatchEvent(arrowDownEvent); fixture.detectChanges(); tick(); // do not iterate timesExpanded verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(9); // open through API panel.expand(); timesExpanded++; tick(); fixture.detectChanges(); // currently expanded expect(panel.collapsed).toEqual(false); // cancel closing panelHeader.dispatchEvent(arrowUpEvent); fixture.detectChanges(); tick(); // do not iterate timesCollapsed verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(10); headerSub.unsubscribe(); })); it('Should change panel expansion when using different methods', fakeAsync(() => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const header = fixture.componentInstance.header; const panelContainer = fixture.nativeElement.querySelector('.' + CSS_CLASS_EXPANSION_PANEL); const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; let timesCollapsed = 0; let timesExpanded = 0; spyOn(panel.contentCollapsed, 'emit').and.callThrough(); spyOn(panel.contentExpanded, 'emit').and.callThrough(); spyOn(header.interaction, 'emit'); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.expand(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panelHeader.click(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(1); button.click(); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(2); panelHeader.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' })); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(3); panel.collapsed = false; tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panel.toggle(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panelHeader.dispatchEvent(new KeyboardEvent('keydown', { key: 'Space' })); tick(); fixture.detectChanges(); tick(); timesExpanded++; verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(4); panel.collapse(); tick(); fixture.detectChanges(); tick(); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); })); it('Should not be interactable when disabled', fakeAsync(() => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const header = fixture.componentInstance.header; const panelContainer = fixture.nativeElement.querySelector('.' + CSS_CLASS_EXPANSION_PANEL); const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const button = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_ICON) as HTMLElement; const headerButton = panelHeader.querySelector('div [role = \'button\']'); let timesCollapsed = 0; const timesExpanded = 1; spyOn(panel.contentCollapsed, 'emit').and.callThrough(); spyOn(panel.contentExpanded, 'emit').and.callThrough(); spyOn(header.interaction, 'emit'); panel.expand(); tick(); fixture.detectChanges(); tick(); expect(headerButton.getAttribute('aria-disabled')).toMatch('false'); verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); header.disabled = true; tick(); fixture.detectChanges(); tick(); expect(headerButton.getAttribute('aria-disabled')).toMatch('true'); panelHeader.click(); tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(0); button.click(); tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(0); panelHeader.dispatchEvent(new KeyboardEvent('keydown', { key: 'Space' })); tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(false, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(0); panel.toggle(); tick(); fixture.detectChanges(); tick(); expect(headerButton.getAttribute('aria-disabled')).toMatch('true'); timesCollapsed++; verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); panelHeader.click(); tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(0); button.click(); tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(0); panelHeader.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' })); tick(); fixture.detectChanges(); tick(); verifyPanelExpansionState(true, panel, panelContainer, panelHeader, button, timesCollapsed, timesExpanded); expect(header.interaction.emit).toHaveBeenCalledTimes(0); header.disabled = false; tick(); fixture.detectChanges(); tick(); expect(headerButton.getAttribute('aria-disabled')).toMatch('false'); })); it('Should display expand/collapse button according to its position', () => { const fixture: ComponentFixture<IgxExpansionPanelListComponent> = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const header = fixture.componentInstance.header; const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const headerButton = panelHeader.querySelector('div [role = \'button\']'); expect(header.iconPosition).toEqual('left'); expect(headerButton.children[0].className).toEqual(CSS_CLASS_PANEL_TITLE_WRAPPER); expect(headerButton.children[1].className).toEqual(CSS_CLASS_HEADER_ICON_START); expect(headerButton.children[1].getBoundingClientRect().left). toBeLessThan(headerButton.children[0].getBoundingClientRect().left); header.iconPosition = ExpansionPanelHeaderIconPosition.NONE; fixture.detectChanges(); expect(header.iconPosition).toEqual('none'); expect(headerButton.children[1].className).toEqual(CSS_CLASS_HEADER_ICON_NONE); header.iconPosition = ExpansionPanelHeaderIconPosition.RIGHT; fixture.detectChanges(); expect(header.iconPosition).toEqual('right'); expect(headerButton.children[0].className).toEqual(CSS_CLASS_PANEL_TITLE_WRAPPER); expect(headerButton.children[1].className).toEqual(CSS_CLASS_HEADER_ICON_END); expect(headerButton.children[0].getBoundingClientRect().left). toBeLessThan(headerButton.children[1].getBoundingClientRect().left); header.iconPosition = ExpansionPanelHeaderIconPosition.NONE; fixture.detectChanges(); expect(header.iconPosition).toEqual('none'); expect(headerButton.children[1].className).toEqual(CSS_CLASS_HEADER_ICON_NONE); header.iconPosition = ExpansionPanelHeaderIconPosition.LEFT; fixture.detectChanges(); expect(header.iconPosition).toEqual('left'); expect(headerButton.children[0].className).toEqual(CSS_CLASS_PANEL_TITLE_WRAPPER); expect(headerButton.children[1].className).toEqual(CSS_CLASS_HEADER_ICON_START); expect(headerButton.children[1].getBoundingClientRect().left). toBeLessThan(headerButton.children[0].getBoundingClientRect().left); }); it('Should override the default icon when an icon template is passed', () => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); const header = fixture.componentInstance.header; const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const headerButton = panelHeader.querySelector('div [role = \'button\']'); header.iconPosition = ExpansionPanelHeaderIconPosition.LEFT; fixture.detectChanges(); // Buttons are wrapper in wrapper div to hold positioning class const iconContainer = headerButton.children[1]; const titleContainer = headerButton.children[0]; expect(headerButton.children.length).toEqual(2); expect(iconContainer.firstElementChild.nodeName).toEqual('IGX-ICON'); expect(titleContainer.firstElementChild.nodeName).toEqual('IGX-EXPANSION-PANEL-TITLE'); expect(header.iconRef).not.toBe(null); expect(header.iconRef.nativeElement).toEqual(iconContainer.firstElementChild); fixture.componentInstance.customIcon = true; fixture.detectChanges(); expect(iconContainer.firstElementChild.nodeName).toEqual('IGX-EXPANSION-PANEL-ICON'); expect(titleContainer.firstElementChild.nodeName).toEqual('IGX-EXPANSION-PANEL-TITLE'); expect(header.iconRef).not.toBe(null); expect(header.iconRef.nativeElement).toEqual(iconContainer.firstElementChild); fixture.componentInstance.header.iconPosition = ExpansionPanelHeaderIconPosition.NONE; fixture.detectChanges(); expect(header.iconRef).toEqual(null); fixture.componentInstance.customIcon = false; fixture.detectChanges(); expect(header.iconRef).toEqual(null); fixture.componentInstance.header.iconPosition = ExpansionPanelHeaderIconPosition.LEFT; fixture.detectChanges(); expect(header.iconRef).not.toBe(null); expect(iconContainer.firstElementChild.nodeName).toEqual('IGX-ICON'); expect(titleContainer.firstElementChild.nodeName).toEqual('IGX-EXPANSION-PANEL-TITLE'); }); it('Should properly appy positioning classes to icon', () => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); const header = fixture.componentInstance.header; const panelHeader = fixture.nativeElement.querySelector('.' + CSS_CLASS_PANEL_HEADER) as HTMLElement; const headerButton = panelHeader.querySelector('div [role = \'button\']'); header.iconPosition = ExpansionPanelHeaderIconPosition.LEFT; fixture.detectChanges(); expect(headerButton.children[1].classList).toContain(IconPositionClass.LEFT); header.iconPosition = ExpansionPanelHeaderIconPosition.RIGHT; fixture.detectChanges(); expect(headerButton.children[1].classList).toContain(IconPositionClass.RIGHT); header.iconPosition = ExpansionPanelHeaderIconPosition.NONE; fixture.detectChanges(); expect(headerButton.children[1].classList).toContain(IconPositionClass.NONE); }); it('Should not call animate method when `collapse` is called on a collapsed panel', () => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); const panel = fixture.componentInstance.panel; const animationSpy = spyOn<any>(panel, 'playCloseAnimation'); panel.collapse(); expect(animationSpy).not.toHaveBeenCalled(); }); it('Should not call animate method when `expand` is called on an expanded panel', () => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); const panel = fixture.componentInstance.panel; const animationSpy = spyOn<any>(panel, 'playOpenAnimation'); panel.collapse(); expect(animationSpy).not.toHaveBeenCalled(); }); }); describe('Aria tests', () => { // configureTestSuite(); it('Should properly apply default aria properties', fakeAsync(() => { const fixture = TestBed.createComponent(IgxExpansionPanelListComponent); fixture.detectChanges(); const panel = fixture.componentInstance.expansionPanel; const panelElement = fixture.debugElement.query(By.css('igx-expansion-panel')).nativeElement; const header = fixture.componentInstance.header; const headerElement = header.elementRef.nativeElement; const title = fixture.componentInstance.expansionPanel.header; fixture.detectChanges(); // IgxExpansionPanelHeaderComponent host expect(headerElement.getAttribute('aria-level')).toEqual('3'); expect(headerElement.getAttribute('role')).toEqual('heading'); // Body of IgxExpansionPanelComponent panel.expand(); tick(); fixture.detectChanges(); tick(); expect(panelElement.lastElementChild.getAttribute('role')).toEqual('region'); expect(panelElement.lastElementChild.getAttribute('aria-labelledby')).toEqual(title.id); // Button of IgxExpansionPanelHeaderComponent expect(headerElement.lastElementChild.getAttribute('role')).toEqual('button'); expect(headerElement.firstElementChild.getAttribute('aria-controls')).toEqual(panel.id); expect(headerElement.firstElementChild.getAttribute('aria-expanded')).toEqual('true'); expect(headerElement.firstElementChild.getAttribute('aria-disabled')).toEqual('false'); // Disabled header.disabled = true; expect(headerElement.firstElementChild.getAttribute('aria-disabled')).toEqual('false'); })); it('Should properly apply aria properties if no header is shown', fakeAsync(() => { const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent); fixture.detectChanges(); fi