680 lines
22 KiB
TypeScript
680 lines
22 KiB
TypeScript
|
|
import {ENTER, SPACE} from '@angular/cdk/keycodes';
|
||
|
|
import {
|
||
|
|
createKeyboardEvent,
|
||
|
|
dispatchEvent,
|
||
|
|
dispatchKeyboardEvent,
|
||
|
|
} from '@angular/cdk/testing/private';
|
||
|
|
import {Component, ViewChild} from '@angular/core';
|
||
|
|
import {
|
||
|
|
ComponentFixture,
|
||
|
|
TestBed,
|
||
|
|
fakeAsync,
|
||
|
|
flush,
|
||
|
|
tick,
|
||
|
|
waitForAsync,
|
||
|
|
} from '@angular/core/testing';
|
||
|
|
import {By} from '@angular/platform-browser';
|
||
|
|
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||
|
|
import {
|
||
|
|
MAT_EXPANSION_PANEL_DEFAULT_OPTIONS,
|
||
|
|
MatExpansionModule,
|
||
|
|
MatExpansionPanel,
|
||
|
|
MatExpansionPanelHeader,
|
||
|
|
} from './index';
|
||
|
|
|
||
|
|
describe('MatExpansionPanel', () => {
|
||
|
|
beforeEach(waitForAsync(() => {
|
||
|
|
TestBed.configureTestingModule({
|
||
|
|
imports: [
|
||
|
|
MatExpansionModule,
|
||
|
|
NoopAnimationsModule,
|
||
|
|
PanelWithContent,
|
||
|
|
PanelWithContentInNgIf,
|
||
|
|
PanelWithCustomMargin,
|
||
|
|
LazyPanelWithContent,
|
||
|
|
LazyPanelOpenOnLoad,
|
||
|
|
PanelWithTwoWayBinding,
|
||
|
|
PanelWithHeaderTabindex,
|
||
|
|
NestedLazyPanelWithContent,
|
||
|
|
],
|
||
|
|
});
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should expand and collapse the panel', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
const headerEl = fixture.nativeElement.querySelector('.mat-expansion-panel-header');
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(headerEl.classList).not.toContain('mat-expanded');
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(headerEl.classList).toContain('mat-expanded');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should add strong focus indication', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(fixture.nativeElement.querySelector('.mat-expansion-panel-header').classList).toContain(
|
||
|
|
'mat-focus-indicator',
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should be able to render panel content lazily', () => {
|
||
|
|
const fixture = TestBed.createComponent(LazyPanelWithContent);
|
||
|
|
const content = fixture.debugElement.query(
|
||
|
|
By.css('.mat-expansion-panel-content'),
|
||
|
|
)!.nativeElement;
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(content.textContent.trim())
|
||
|
|
.withContext('Expected content element to be empty.')
|
||
|
|
.toBe('');
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(content.textContent.trim())
|
||
|
|
.withContext('Expected content to be rendered.')
|
||
|
|
.toContain('Some content');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should render the content for a lazy-loaded panel that is opened on init', () => {
|
||
|
|
const fixture = TestBed.createComponent(LazyPanelOpenOnLoad);
|
||
|
|
const content = fixture.debugElement.query(
|
||
|
|
By.css('.mat-expansion-panel-content'),
|
||
|
|
)!.nativeElement;
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(content.textContent.trim())
|
||
|
|
.withContext('Expected content to be rendered.')
|
||
|
|
.toContain('Some content');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should not render lazy content from a child panel inside the parent', () => {
|
||
|
|
const fixture = TestBed.createComponent(NestedLazyPanelWithContent);
|
||
|
|
fixture.componentInstance.parentExpanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const parentContent: HTMLElement = fixture.nativeElement.querySelector(
|
||
|
|
'.parent-panel .mat-expansion-panel-content',
|
||
|
|
);
|
||
|
|
const childContent: HTMLElement = fixture.nativeElement.querySelector(
|
||
|
|
'.child-panel .mat-expansion-panel-content',
|
||
|
|
);
|
||
|
|
|
||
|
|
expect(parentContent.textContent!.trim()).toBe(
|
||
|
|
'Parent content',
|
||
|
|
'Expected only parent content to be rendered.',
|
||
|
|
);
|
||
|
|
expect(childContent.textContent!.trim()).toBe(
|
||
|
|
'',
|
||
|
|
'Expected child content element to be empty.',
|
||
|
|
);
|
||
|
|
|
||
|
|
fixture.componentInstance.childExpanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(childContent.textContent!.trim()).toBe(
|
||
|
|
'Child content',
|
||
|
|
'Expected child content element to be rendered.',
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('emit correct events for change in panel expanded state', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(fixture.componentInstance.openCallback).toHaveBeenCalled();
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = false;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(fixture.componentInstance.closeCallback).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should create a unique panel id for each panel', () => {
|
||
|
|
const fixtureOne = TestBed.createComponent(PanelWithContent);
|
||
|
|
const headerElOne = fixtureOne.nativeElement.querySelector('.mat-expansion-panel-header');
|
||
|
|
const fixtureTwo = TestBed.createComponent(PanelWithContent);
|
||
|
|
const headerElTwo = fixtureTwo.nativeElement.querySelector('.mat-expansion-panel-header');
|
||
|
|
fixtureOne.detectChanges();
|
||
|
|
fixtureTwo.detectChanges();
|
||
|
|
|
||
|
|
const panelIdOne = headerElOne.getAttribute('aria-controls');
|
||
|
|
const panelIdTwo = headerElTwo.getAttribute('aria-controls');
|
||
|
|
expect(panelIdOne).not.toBe(panelIdTwo);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should set `aria-labelledby` of the content to the header id', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
const headerEl = fixture.nativeElement.querySelector('.mat-expansion-panel-header');
|
||
|
|
const contentEl = fixture.nativeElement.querySelector('.mat-expansion-panel-content');
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const headerId = headerEl.getAttribute('id');
|
||
|
|
const contentLabel = contentEl.getAttribute('aria-labelledby');
|
||
|
|
|
||
|
|
expect(headerId).toBeTruthy();
|
||
|
|
expect(contentLabel).toBeTruthy();
|
||
|
|
expect(headerId).toBe(contentLabel);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should set the proper role on the content element', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
const contentEl = fixture.nativeElement.querySelector('.mat-expansion-panel-content');
|
||
|
|
|
||
|
|
expect(contentEl.getAttribute('role')).toBe('region');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should toggle the panel when pressing SPACE on the header', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.detectChanges();
|
||
|
|
const headerEl = fixture.nativeElement.querySelector('.mat-expansion-panel-header');
|
||
|
|
|
||
|
|
spyOn(fixture.componentInstance.panel, 'toggle');
|
||
|
|
|
||
|
|
const event = dispatchKeyboardEvent(headerEl, 'keydown', SPACE);
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(fixture.componentInstance.panel.toggle).toHaveBeenCalled();
|
||
|
|
expect(event.defaultPrevented).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should toggle the panel when pressing ENTER on the header', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.detectChanges();
|
||
|
|
const headerEl = fixture.nativeElement.querySelector('.mat-expansion-panel-header');
|
||
|
|
|
||
|
|
spyOn(fixture.componentInstance.panel, 'toggle');
|
||
|
|
|
||
|
|
const event = dispatchKeyboardEvent(headerEl, 'keydown', ENTER);
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(fixture.componentInstance.panel.toggle).toHaveBeenCalled();
|
||
|
|
expect(event.defaultPrevented).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should not toggle if a modifier key is pressed', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.detectChanges();
|
||
|
|
const headerEl = fixture.nativeElement.querySelector('.mat-expansion-panel-header');
|
||
|
|
|
||
|
|
spyOn(fixture.componentInstance.panel, 'toggle');
|
||
|
|
|
||
|
|
['altKey', 'metaKey', 'shiftKey', 'ctrlKey'].forEach(modifier => {
|
||
|
|
const event = createKeyboardEvent('keydown', ENTER);
|
||
|
|
Object.defineProperty(event, modifier, {get: () => true});
|
||
|
|
|
||
|
|
dispatchEvent(headerEl, event);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(fixture.componentInstance.panel.toggle).not.toHaveBeenCalled();
|
||
|
|
expect(event.defaultPrevented).toBe(false);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should not be able to focus content while closed', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
const wrapper = fixture.nativeElement.querySelector('.mat-expansion-panel-content-wrapper');
|
||
|
|
expect(wrapper.hasAttribute('inert')).toBe(false);
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = false;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(wrapper.hasAttribute('inert')).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should restore focus to header if focused element is inside panel on close', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick(250);
|
||
|
|
|
||
|
|
const button = fixture.debugElement.query(By.css('button'))!.nativeElement;
|
||
|
|
const header = fixture.debugElement.query(By.css('mat-expansion-panel-header'))!.nativeElement;
|
||
|
|
|
||
|
|
button.focus();
|
||
|
|
expect(document.activeElement)
|
||
|
|
.withContext('Expected button to start off focusable.')
|
||
|
|
.toBe(button);
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = false;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick(250);
|
||
|
|
|
||
|
|
expect(document.activeElement).withContext('Expected header to be focused.').toBe(header);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not change focus origin if origin not specified', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick(250);
|
||
|
|
|
||
|
|
const header = fixture.debugElement.query(By.css('mat-expansion-panel-header'))!;
|
||
|
|
const headerInstance = header.componentInstance;
|
||
|
|
|
||
|
|
headerInstance.focus('mouse');
|
||
|
|
headerInstance.focus();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick(250);
|
||
|
|
|
||
|
|
expect(header.nativeElement.classList).toContain('cdk-focused');
|
||
|
|
expect(header.nativeElement.classList).toContain('cdk-mouse-focused');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not override the panel margin if it is not inside an accordion', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithCustomMargin);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const panel = fixture.debugElement.query(By.css('mat-expansion-panel'))!;
|
||
|
|
let styles = getComputedStyle(panel.nativeElement);
|
||
|
|
|
||
|
|
expect(panel.componentInstance._hasSpacing()).toBe(false);
|
||
|
|
expect(styles.marginTop).toBe('13px');
|
||
|
|
expect(styles.marginBottom).toBe('13px');
|
||
|
|
expect(styles.marginLeft).toBe('37px');
|
||
|
|
expect(styles.marginRight).toBe('37px');
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick(250);
|
||
|
|
|
||
|
|
styles = getComputedStyle(panel.nativeElement);
|
||
|
|
|
||
|
|
expect(panel.componentInstance._hasSpacing()).toBe(false);
|
||
|
|
expect(styles.marginTop).toBe('13px');
|
||
|
|
expect(styles.marginBottom).toBe('13px');
|
||
|
|
expect(styles.marginLeft).toBe('37px');
|
||
|
|
expect(styles.marginRight).toBe('37px');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should be able to hide the toggle', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
const header = fixture.debugElement.query(By.css('.mat-expansion-panel-header'))!.nativeElement;
|
||
|
|
const content = fixture.debugElement.query(By.css('.mat-content'))!.nativeElement;
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(header.querySelector('.mat-expansion-indicator'))
|
||
|
|
.withContext('Expected indicator to be shown.')
|
||
|
|
.toBeTruthy();
|
||
|
|
expect(content.classList).not.toContain('mat-content-hide-toggle');
|
||
|
|
|
||
|
|
fixture.componentInstance.hideToggle = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(header.querySelector('.mat-expansion-indicator'))
|
||
|
|
.withContext('Expected indicator to be hidden.')
|
||
|
|
.toBeFalsy();
|
||
|
|
expect(content.classList).toContain('mat-content-hide-toggle');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should make sure accordion item runs ngOnDestroy when expansion panel is destroyed', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContentInNgIf);
|
||
|
|
fixture.detectChanges();
|
||
|
|
let destroyedOk = false;
|
||
|
|
fixture.componentInstance.panel.destroyed.subscribe(() => (destroyedOk = true));
|
||
|
|
fixture.componentInstance.expansionShown = false;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(destroyedOk).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should support two-way binding of the `expanded` property', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithTwoWayBinding);
|
||
|
|
const header = fixture.debugElement.query(By.css('mat-expansion-panel-header'))!.nativeElement;
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(fixture.componentInstance.expanded).toBe(false);
|
||
|
|
|
||
|
|
header.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(fixture.componentInstance.expanded).toBe(true);
|
||
|
|
|
||
|
|
header.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(fixture.componentInstance.expanded).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should emit events for body expanding and collapsing animations', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.detectChanges();
|
||
|
|
let afterExpand = 0;
|
||
|
|
let afterCollapse = 0;
|
||
|
|
fixture.componentInstance.panel.afterExpand.subscribe(() => afterExpand++);
|
||
|
|
fixture.componentInstance.panel.afterCollapse.subscribe(() => afterCollapse++);
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
expect(afterExpand).toBe(1);
|
||
|
|
expect(afterCollapse).toBe(0);
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = false;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
expect(afterExpand).toBe(1);
|
||
|
|
expect(afterCollapse).toBe(1);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should be able to set the default options through the injection token', () => {
|
||
|
|
TestBed.resetTestingModule().configureTestingModule({
|
||
|
|
imports: [MatExpansionModule, NoopAnimationsModule],
|
||
|
|
providers: [
|
||
|
|
{
|
||
|
|
provide: MAT_EXPANSION_PANEL_DEFAULT_OPTIONS,
|
||
|
|
useValue: {
|
||
|
|
hideToggle: true,
|
||
|
|
expandedHeight: '10px',
|
||
|
|
collapsedHeight: '16px',
|
||
|
|
},
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
|
||
|
|
const fixture = TestBed.createComponent(PanelWithTwoWayBinding);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const panel = fixture.debugElement.query(By.directive(MatExpansionPanel))!;
|
||
|
|
const header = fixture.debugElement.query(By.directive(MatExpansionPanelHeader))!;
|
||
|
|
|
||
|
|
expect(panel.componentInstance.hideToggle).toBe(true);
|
||
|
|
expect(header.componentInstance.expandedHeight).toBe('10px');
|
||
|
|
expect(header.componentInstance.collapsedHeight).toBe('16px');
|
||
|
|
expect(header.nativeElement.style.height).toBe('16px');
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(header.nativeElement.style.height).toBe('10px');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should be able to set a custom tabindex on the header', () => {
|
||
|
|
const fixture = TestBed.createComponent(PanelWithHeaderTabindex);
|
||
|
|
const headerEl = fixture.nativeElement.querySelector('.mat-expansion-panel-header');
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(headerEl.getAttribute('tabindex')).toBe('7');
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('disabled state', () => {
|
||
|
|
let fixture: ComponentFixture<PanelWithContent>;
|
||
|
|
let panel: HTMLElement;
|
||
|
|
let header: HTMLElement;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
fixture = TestBed.createComponent(PanelWithContent);
|
||
|
|
fixture.detectChanges();
|
||
|
|
panel = fixture.debugElement.query(By.css('mat-expansion-panel'))!.nativeElement;
|
||
|
|
header = fixture.debugElement.query(By.css('mat-expansion-panel-header'))!.nativeElement;
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should toggle the aria-disabled attribute on the header', () => {
|
||
|
|
expect(header.getAttribute('aria-disabled')).toBe('false');
|
||
|
|
|
||
|
|
fixture.componentInstance.disabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(header.getAttribute('aria-disabled')).toBe('true');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should toggle the expansion indicator', () => {
|
||
|
|
expect(panel.querySelector('.mat-expansion-indicator')).toBeTruthy();
|
||
|
|
|
||
|
|
fixture.componentInstance.disabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(panel.querySelector('.mat-expansion-indicator')).toBeFalsy();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should not be able to toggle the panel via a user action if disabled', () => {
|
||
|
|
expect(fixture.componentInstance.panel.expanded).toBe(false);
|
||
|
|
expect(header.classList).not.toContain('mat-expanded');
|
||
|
|
|
||
|
|
fixture.componentInstance.disabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
header.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(fixture.componentInstance.panel.expanded).toBe(false);
|
||
|
|
expect(header.classList).not.toContain('mat-expanded');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should be able to toggle a disabled expansion panel programmatically', () => {
|
||
|
|
expect(fixture.componentInstance.panel.expanded).toBe(false);
|
||
|
|
expect(header.classList).not.toContain('mat-expanded');
|
||
|
|
|
||
|
|
fixture.componentInstance.disabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
fixture.componentInstance.expanded = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(fixture.componentInstance.panel.expanded).toBe(true);
|
||
|
|
expect(header.classList).toContain('mat-expanded');
|
||
|
|
});
|
||
|
|
|
||
|
|
it(
|
||
|
|
'should be able to toggle a disabled expansion panel programmatically via the ' +
|
||
|
|
'open/close methods',
|
||
|
|
() => {
|
||
|
|
const panelInstance = fixture.componentInstance.panel;
|
||
|
|
|
||
|
|
expect(panelInstance.expanded).toBe(false);
|
||
|
|
expect(header.classList).not.toContain('mat-expanded');
|
||
|
|
|
||
|
|
fixture.componentInstance.disabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
panelInstance.open();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(panelInstance.expanded).toBe(true);
|
||
|
|
expect(header.classList).toContain('mat-expanded');
|
||
|
|
|
||
|
|
panelInstance.close();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(panelInstance.expanded).toBe(false);
|
||
|
|
expect(header.classList).not.toContain('mat-expanded');
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
it(
|
||
|
|
'should be able to toggle a disabled expansion panel programmatically via the ' +
|
||
|
|
'toggle method',
|
||
|
|
() => {
|
||
|
|
const panelInstance = fixture.componentInstance.panel;
|
||
|
|
|
||
|
|
expect(panelInstance.expanded).toBe(false);
|
||
|
|
expect(header.classList).not.toContain('mat-expanded');
|
||
|
|
|
||
|
|
fixture.componentInstance.disabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
panelInstance.toggle();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(panelInstance.expanded).toBe(true);
|
||
|
|
expect(header.classList).toContain('mat-expanded');
|
||
|
|
|
||
|
|
panelInstance.toggle();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(panelInstance.expanded).toBe(false);
|
||
|
|
expect(header.classList).not.toContain('mat-expanded');
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
it('should update the tabindex if the header becomes disabled', () => {
|
||
|
|
expect(header.getAttribute('tabindex')).toBe('0');
|
||
|
|
|
||
|
|
fixture.componentInstance.disabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(header.getAttribute('tabindex')).toBe('-1');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-expansion-panel [expanded]="expanded"
|
||
|
|
[hideToggle]="hideToggle"
|
||
|
|
[disabled]="disabled"
|
||
|
|
(opened)="openCallback()"
|
||
|
|
(closed)="closeCallback()">
|
||
|
|
<mat-expansion-panel-header>Panel Title</mat-expansion-panel-header>
|
||
|
|
<p>Some content</p>
|
||
|
|
<button>I am a button</button>
|
||
|
|
</mat-expansion-panel>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatExpansionModule],
|
||
|
|
})
|
||
|
|
class PanelWithContent {
|
||
|
|
expanded = false;
|
||
|
|
hideToggle = false;
|
||
|
|
disabled = false;
|
||
|
|
openCallback = jasmine.createSpy('openCallback');
|
||
|
|
closeCallback = jasmine.createSpy('closeCallback');
|
||
|
|
@ViewChild(MatExpansionPanel) panel: MatExpansionPanel;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
@if (expansionShown) {
|
||
|
|
<div>
|
||
|
|
<mat-expansion-panel>
|
||
|
|
<mat-expansion-panel-header>Panel Title</mat-expansion-panel-header>
|
||
|
|
</mat-expansion-panel>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatExpansionModule],
|
||
|
|
})
|
||
|
|
class PanelWithContentInNgIf {
|
||
|
|
expansionShown = true;
|
||
|
|
@ViewChild(MatExpansionPanel) panel: MatExpansionPanel;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
styles: `mat-expansion-panel {
|
||
|
|
margin: 13px 37px;
|
||
|
|
}`,
|
||
|
|
template: `
|
||
|
|
<mat-expansion-panel [expanded]="expanded">
|
||
|
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolores officia, aliquam dicta
|
||
|
|
corrupti maxime voluptate accusamus impedit atque incidunt pariatur.
|
||
|
|
</mat-expansion-panel>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatExpansionModule],
|
||
|
|
})
|
||
|
|
class PanelWithCustomMargin {
|
||
|
|
expanded = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-expansion-panel [expanded]="expanded">
|
||
|
|
<mat-expansion-panel-header>Panel Title</mat-expansion-panel-header>
|
||
|
|
|
||
|
|
<ng-template matExpansionPanelContent>
|
||
|
|
<p>Some content</p>
|
||
|
|
<button>I am a button</button>
|
||
|
|
</ng-template>
|
||
|
|
</mat-expansion-panel>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatExpansionModule],
|
||
|
|
})
|
||
|
|
class LazyPanelWithContent {
|
||
|
|
expanded = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-expansion-panel [expanded]="true">
|
||
|
|
<mat-expansion-panel-header>Panel Title</mat-expansion-panel-header>
|
||
|
|
|
||
|
|
<ng-template matExpansionPanelContent>
|
||
|
|
<p>Some content</p>
|
||
|
|
</ng-template>
|
||
|
|
</mat-expansion-panel>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatExpansionModule],
|
||
|
|
})
|
||
|
|
class LazyPanelOpenOnLoad {}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-expansion-panel [(expanded)]="expanded">
|
||
|
|
<mat-expansion-panel-header>Panel Title</mat-expansion-panel-header>
|
||
|
|
</mat-expansion-panel>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatExpansionModule],
|
||
|
|
})
|
||
|
|
class PanelWithTwoWayBinding {
|
||
|
|
expanded = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-expansion-panel>
|
||
|
|
<mat-expansion-panel-header tabindex="7">Panel Title</mat-expansion-panel-header>
|
||
|
|
</mat-expansion-panel>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatExpansionModule],
|
||
|
|
})
|
||
|
|
class PanelWithHeaderTabindex {}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-expansion-panel class="parent-panel" [expanded]="parentExpanded">
|
||
|
|
Parent content
|
||
|
|
|
||
|
|
<mat-expansion-panel class="child-panel" [expanded]="childExpanded">
|
||
|
|
<ng-template matExpansionPanelContent>Child content</ng-template>
|
||
|
|
</mat-expansion-panel>
|
||
|
|
</mat-expansion-panel>
|
||
|
|
`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatExpansionModule],
|
||
|
|
})
|
||
|
|
class NestedLazyPanelWithContent {
|
||
|
|
parentExpanded = false;
|
||
|
|
childExpanded = false;
|
||
|
|
}
|