import { Component } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { AccordionConfig } from '../accordion/accordion.config'; import { AccordionModule } from '../accordion/accordion.module'; @Component({ selector: 'accordion-test', template: '' }) class TestAccordionComponent { oneAtATime = true; panels: any[] = [ {isOpen: false, isDisabled: false}, {isOpen: false, isDisabled: false}, {isOpen: false, isDisabled: false} ]; constructor(config: AccordionConfig) { Object.assign(this, config); } } const html = ` Content of panel 1 Content of panel 2 Content of panel 3 `; function getPanels(element: HTMLElement): Element[] { return Array.from(element.querySelectorAll('accordion-group')); } function expectOpenPanels(nativeEl: HTMLElement, openPanelsDef: boolean[]): void { const panels = getPanels(nativeEl); expect(panels.length).toBe(openPanelsDef.length); for (let i = 0; i < panels.length; i++) { if (openPanelsDef[i]) { expect(panels[i].classList).toContain('panel-open'); } else { expect(panels[i].classList).not.toContain('panel-open'); } } } function hasTitle(element: HTMLElement, str: string): boolean { return element.textContent === str; } describe('Component: Accordion', () => { let fixture: ComponentFixture; let context: any; let element: any; beforeEach(() => { TestBed.configureTestingModule({ declarations: [TestAccordionComponent], imports: [AccordionModule.forRoot()] }); TestBed.overrideComponent(TestAccordionComponent, { set: {template: html} }); fixture = TestBed.createComponent(TestAccordionComponent); context = fixture.componentInstance; element = fixture.nativeElement; fixture.detectChanges(); }); it('should have no open panels', () => { expectOpenPanels(element, [false, false, false]); }); it('should have open panel based on binding', () => { context.panels[0].isOpen = true; fixture.detectChanges(); expectOpenPanels(element, [true, false, false]); }); it('should toggle panels independently', () => { context.oneAtATime = false; context.panels[1].isOpen = true; fixture.detectChanges(); expectOpenPanels(element, [false, true, false]); context.panels[0].isOpen = true; fixture.detectChanges(); expectOpenPanels(element, [true, true, false]); context.panels[1].isOpen = false; fixture.detectChanges(); expectOpenPanels(element, [true, false, false]); context.panels[2].isOpen = true; fixture.detectChanges(); expectOpenPanels(element, [true, false, true]); context.panels[0].isOpen = false; fixture.detectChanges(); expectOpenPanels(element, [false, false, true]); context.panels[2].isOpen = false; fixture.detectChanges(); expectOpenPanels(element, [false, false, false]); }); it('should have the appropriate heading', () => { const titles = Array.from( element.querySelectorAll('.panel-heading .accordion-toggle span') ); titles.forEach((title: HTMLElement, idx: number) => expect(hasTitle(title, `Panel ${idx + 1}`)).toBe(true) ); }); it('should only open one at a time', () => { const headingLinks = element.querySelectorAll('.accordion-toggle'); headingLinks[0].click(); fixture.detectChanges(); expectOpenPanels(element, [true, false, false]); headingLinks[2].click(); fixture.detectChanges(); expectOpenPanels(element, [false, false, true]); headingLinks[2].click(); fixture.detectChanges(); expectOpenPanels(element, [false, false, false]); }); it('should have only one open panel even if binding says otherwise', () => { context.panels[0].isOpen = true; context.panels[1].isOpen = true; // which of panels should be opened there? the first or the last one? (now - last) fixture.detectChanges(); expectOpenPanels(element, [false, true, false]); }); it('should not open disabled panels from click', () => { context.panels[0].isDisabled = true; fixture.detectChanges(); const headingLinks = element.querySelectorAll( '.panel-title .accordion-toggle' ); headingLinks[0].click(); fixture.detectChanges(); expectOpenPanels(element, [false, false, false]); }); it('should modify the parent isOpen state when changed internally (2 way binding)', fakeAsync(() => { const headingLinks = element.querySelectorAll('.accordion-toggle'); // Clicking (internal state modified) headingLinks[0].click(); tick(); fixture.detectChanges(); expect(context.panels[0].isOpen).toBe(true); expect(context.panels[1].isOpen).toBe(false); expect(context.panels[2].isOpen).toBe(false); // State modified by parent component headingLinks[2].click(); tick(); fixture.detectChanges(); expect(context.panels[0].isOpen).toBe(false); expect(context.panels[1].isOpen).toBe(false); expect(context.panels[2].isOpen).toBe(true); // Modified by binding context.panels[1].isOpen = true; fixture.detectChanges(); tick(); expect(context.panels[0].isOpen).toBe(false); expect(context.panels[1].isOpen).toBe(true); expect(context.panels[2].isOpen).toBe(false); })); });