sass-references/angular-material/material/core/option/option.spec.ts

264 lines
8.9 KiB
TypeScript
Raw Permalink Normal View History

2024-12-06 10:42:08 +08:00
import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
import {Component, DebugElement, signal} from '@angular/core';
import {By} from '@angular/platform-browser';
import {
dispatchFakeEvent,
dispatchKeyboardEvent,
createKeyboardEvent,
dispatchEvent,
} from '@angular/cdk/testing/private';
import {SPACE, ENTER} from '@angular/cdk/keycodes';
import {MatOption, MatOptionModule, MAT_OPTION_PARENT_COMPONENT} from './index';
describe('MatOption component', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [MatOptionModule, BasicOption],
});
}));
it('should complete the `stateChanges` stream on destroy', () => {
const fixture = TestBed.createComponent(BasicOption);
fixture.detectChanges();
const optionInstance: MatOption = fixture.debugElement.query(
By.directive(MatOption),
)!.componentInstance;
const completeSpy = jasmine.createSpy('complete spy');
const subscription = optionInstance._stateChanges.subscribe({complete: completeSpy});
fixture.destroy();
expect(completeSpy).toHaveBeenCalled();
subscription.unsubscribe();
});
it('should not emit to `onSelectionChange` if selecting an already-selected option', () => {
const fixture = TestBed.createComponent(BasicOption);
fixture.detectChanges();
const optionInstance: MatOption = fixture.debugElement.query(
By.directive(MatOption),
)!.componentInstance;
optionInstance.select();
expect(optionInstance.selected).toBe(true);
const spy = jasmine.createSpy('selection change spy');
const subscription = optionInstance.onSelectionChange.subscribe(spy);
optionInstance.select();
fixture.detectChanges();
expect(optionInstance.selected).toBe(true);
expect(spy).not.toHaveBeenCalled();
subscription.unsubscribe();
});
it('should not emit to `onSelectionChange` if deselecting an unselected option', () => {
const fixture = TestBed.createComponent(BasicOption);
fixture.detectChanges();
const optionInstance: MatOption = fixture.debugElement.query(
By.directive(MatOption),
)!.componentInstance;
optionInstance.deselect();
expect(optionInstance.selected).toBe(false);
const spy = jasmine.createSpy('selection change spy');
const subscription = optionInstance.onSelectionChange.subscribe(spy);
optionInstance.deselect();
fixture.detectChanges();
expect(optionInstance.selected).toBe(false);
expect(spy).not.toHaveBeenCalled();
subscription.unsubscribe();
});
it('should be able to set a custom id', () => {
const fixture = TestBed.createComponent(BasicOption);
fixture.componentInstance.id.set('custom-option');
fixture.detectChanges();
const optionInstance = fixture.debugElement.query(By.directive(MatOption))!.componentInstance;
expect(optionInstance.id).toBe('custom-option');
});
it('should select the option when pressing space', () => {
const fixture = TestBed.createComponent(BasicOption);
fixture.detectChanges();
const optionDebugElement = fixture.debugElement.query(By.directive(MatOption))!;
const optionNativeElement: HTMLElement = optionDebugElement.nativeElement;
const optionInstance: MatOption = optionDebugElement.componentInstance;
const spy = jasmine.createSpy('selection change spy');
const subscription = optionInstance.onSelectionChange.subscribe(spy);
const event = dispatchKeyboardEvent(optionNativeElement, 'keydown', SPACE);
fixture.detectChanges();
expect(spy).toHaveBeenCalled();
expect(event.defaultPrevented).toBe(true);
subscription.unsubscribe();
});
it('should select the option when pressing enter', () => {
const fixture = TestBed.createComponent(BasicOption);
fixture.detectChanges();
const optionDebugElement = fixture.debugElement.query(By.directive(MatOption))!;
const optionNativeElement: HTMLElement = optionDebugElement.nativeElement;
const optionInstance: MatOption = optionDebugElement.componentInstance;
const spy = jasmine.createSpy('selection change spy');
const subscription = optionInstance.onSelectionChange.subscribe(spy);
const event = dispatchKeyboardEvent(optionNativeElement, 'keydown', ENTER);
fixture.detectChanges();
expect(spy).toHaveBeenCalled();
expect(event.defaultPrevented).toBe(true);
subscription.unsubscribe();
});
it('should not do anything when pressing the selection keys with a modifier', () => {
const fixture = TestBed.createComponent(BasicOption);
fixture.detectChanges();
const optionDebugElement = fixture.debugElement.query(By.directive(MatOption))!;
const optionNativeElement: HTMLElement = optionDebugElement.nativeElement;
const optionInstance: MatOption = optionDebugElement.componentInstance;
const spy = jasmine.createSpy('selection change spy');
const subscription = optionInstance.onSelectionChange.subscribe(spy);
[ENTER, SPACE].forEach(key => {
const event = createKeyboardEvent('keydown', key);
Object.defineProperty(event, 'shiftKey', {get: () => true});
dispatchEvent(optionNativeElement, event);
fixture.detectChanges();
expect(event.defaultPrevented).toBe(false);
});
expect(spy).not.toHaveBeenCalled();
subscription.unsubscribe();
});
describe('ripples', () => {
let fixture: ComponentFixture<BasicOption>;
let optionDebugElement: DebugElement;
let optionNativeElement: HTMLElement;
let optionInstance: MatOption;
beforeEach(() => {
fixture = TestBed.createComponent(BasicOption);
fixture.detectChanges();
optionDebugElement = fixture.debugElement.query(By.directive(MatOption))!;
optionNativeElement = optionDebugElement.nativeElement;
optionInstance = optionDebugElement.componentInstance;
});
it('should show ripples by default', () => {
expect(optionInstance.disableRipple)
.withContext('Expected ripples to be enabled by default')
.toBeFalsy();
expect(optionNativeElement.querySelectorAll('.mat-ripple-element').length)
.withContext('Expected no ripples to show up initially')
.toBe(0);
dispatchFakeEvent(optionNativeElement, 'mousedown');
dispatchFakeEvent(optionNativeElement, 'mouseup');
expect(optionNativeElement.querySelectorAll('.mat-ripple-element').length)
.withContext('Expected one ripple to show up after a fake click.')
.toBe(1);
});
it('should not show ripples if the option is disabled', () => {
expect(optionNativeElement.querySelectorAll('.mat-ripple-element').length)
.withContext('Expected no ripples to show up initially')
.toBe(0);
fixture.componentInstance.disabled.set(true);
fixture.detectChanges();
dispatchFakeEvent(optionNativeElement, 'mousedown');
dispatchFakeEvent(optionNativeElement, 'mouseup');
expect(optionNativeElement.querySelectorAll('.mat-ripple-element').length)
.withContext('Expected no ripples to show up after click on a disabled option.')
.toBe(0);
});
});
it('should have a focus indicator', () => {
const fixture = TestBed.createComponent(BasicOption);
const optionNativeElement = fixture.debugElement.query(By.directive(MatOption))!.nativeElement;
expect(optionNativeElement.parentElement.querySelector('.mat-focus-indicator'))
.withContext(
'expected to find a focus indicator on ' +
"either the mat-option element or one of it's children",
)
.not.toBeNull();
});
describe('inside inert group', () => {
let fixture: ComponentFixture<InsideGroup>;
beforeEach(waitForAsync(() => {
TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [MatOptionModule, InsideGroup],
providers: [
{
provide: MAT_OPTION_PARENT_COMPONENT,
useValue: {inertGroups: true},
},
],
});
fixture = TestBed.createComponent(InsideGroup);
fixture.detectChanges();
}));
it('should remove all accessibility-related attributes from the group', () => {
const group: HTMLElement = fixture.nativeElement.querySelector('mat-optgroup');
expect(group.hasAttribute('role')).toBe(false);
expect(group.hasAttribute('aria-disabled')).toBe(false);
expect(group.hasAttribute('aria-labelledby')).toBe(false);
});
it('should mirror the group label inside the option', () => {
const option: HTMLElement = fixture.nativeElement.querySelector('mat-option');
expect(option.textContent?.trim()).toBe('Option(Group)');
});
});
});
@Component({
template: `<mat-option [id]="id()" [disabled]="disabled()"></mat-option>`,
standalone: true,
imports: [MatOptionModule],
})
class BasicOption {
disabled = signal(false);
id = signal('');
}
@Component({
template: `
<mat-optgroup label="Group">
<mat-option>Option</mat-option>
</mat-optgroup>
`,
standalone: true,
imports: [MatOptionModule],
})
class InsideGroup {}