sass-references/angular-material/material/chips/chip-input.spec.ts

294 lines
9.6 KiB
TypeScript

import {Directionality} from '@angular/cdk/bidi';
import {COMMA, ENTER, TAB} from '@angular/cdk/keycodes';
import {PlatformModule} from '@angular/cdk/platform';
import {
createKeyboardEvent,
dispatchKeyboardEvent,
dispatchEvent,
} from '@angular/cdk/testing/private';
import {Component, DebugElement, ViewChild} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync, flush, waitForAsync} from '@angular/core/testing';
import {MatFormFieldModule} from '@angular/material/form-field';
import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {Subject} from 'rxjs';
import {
MAT_CHIPS_DEFAULT_OPTIONS,
MatChipGrid,
MatChipInput,
MatChipInputEvent,
MatChipsDefaultOptions,
MatChipsModule,
} from './index';
describe('MatChipInput', () => {
let fixture: ComponentFixture<any>;
let testChipInput: TestChipInput;
let inputDebugElement: DebugElement;
let inputNativeElement: HTMLElement;
let chipInputDirective: MatChipInput;
let dir = 'ltr';
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [PlatformModule, MatChipsModule, MatFormFieldModule, NoopAnimationsModule],
providers: [
{
provide: Directionality,
useFactory: () => {
return {
value: dir.toLowerCase(),
change: new Subject(),
};
},
},
],
declarations: [TestChipInput],
});
}));
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(TestChipInput);
testChipInput = fixture.debugElement.componentInstance;
fixture.detectChanges();
inputDebugElement = fixture.debugElement.query(By.directive(MatChipInput))!;
chipInputDirective = inputDebugElement.injector.get<MatChipInput>(MatChipInput);
inputNativeElement = inputDebugElement.nativeElement;
}));
describe('basic behavior', () => {
it('emits the (chipEnd) on enter keyup', () => {
spyOn(testChipInput, 'add');
dispatchKeyboardEvent(inputNativeElement, 'keydown', ENTER);
expect(testChipInput.add).toHaveBeenCalled();
});
it('should have a default id', () => {
expect(inputNativeElement.getAttribute('id')).toBeTruthy();
});
it('should allow binding to the `placeholder` input', () => {
expect(inputNativeElement.hasAttribute('placeholder')).toBe(false);
testChipInput.placeholder = 'bound placeholder';
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
expect(inputNativeElement.getAttribute('placeholder')).toBe('bound placeholder');
});
it('should become disabled if the list is disabled', () => {
expect(inputNativeElement.hasAttribute('disabled')).toBe(false);
expect(chipInputDirective.disabled).toBe(false);
fixture.componentInstance.chipGridInstance.disabled = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
expect(inputNativeElement.getAttribute('disabled')).toBe('true');
expect(chipInputDirective.disabled).toBe(true);
});
it('should be aria-required if the list is required', () => {
expect(inputNativeElement.hasAttribute('aria-required')).toBe(false);
fixture.componentInstance.required = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
expect(inputNativeElement.getAttribute('aria-required')).toBe('true');
});
it('should be required if the list is required', () => {
expect(inputNativeElement.hasAttribute('required')).toBe(false);
fixture.componentInstance.required = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
expect(inputNativeElement.getAttribute('required')).toBe('true');
});
it('should allow focus to escape when tabbing forwards', fakeAsync(() => {
const gridElement: HTMLElement = fixture.nativeElement.querySelector('mat-chip-grid');
expect(gridElement.getAttribute('tabindex')).toBe('0');
dispatchKeyboardEvent(gridElement, 'keydown', TAB);
fixture.detectChanges();
expect(gridElement.getAttribute('tabindex'))
.withContext('Expected tabIndex to be set to -1 temporarily.')
.toBe('-1');
flush();
fixture.detectChanges();
expect(gridElement.getAttribute('tabindex'))
.withContext('Expected tabIndex to be reset back to 0')
.toBe('0');
}));
it('should set input styling classes', () => {
expect(inputNativeElement.classList).toContain('mat-mdc-input-element');
expect(inputNativeElement.classList).toContain('mat-mdc-form-field-input-control');
expect(inputNativeElement.classList).toContain('mat-mdc-chip-input');
expect(inputNativeElement.classList).toContain('mdc-text-field__input');
});
});
describe('[addOnBlur]', () => {
it('allows (chipEnd) when true', () => {
spyOn(testChipInput, 'add');
testChipInput.addOnBlur = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
chipInputDirective._blur();
expect(testChipInput.add).toHaveBeenCalled();
});
it('disallows (chipEnd) when false', () => {
spyOn(testChipInput, 'add');
testChipInput.addOnBlur = false;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
chipInputDirective._blur();
expect(testChipInput.add).not.toHaveBeenCalled();
});
});
describe('[separatorKeyCodes]', () => {
it('does not emit (chipEnd) when a non-separator key is pressed', () => {
spyOn(testChipInput, 'add');
chipInputDirective.separatorKeyCodes = [COMMA];
fixture.detectChanges();
dispatchKeyboardEvent(inputNativeElement, 'keydown', ENTER);
expect(testChipInput.add).not.toHaveBeenCalled();
});
it('emits (chipEnd) when a custom separator keys is pressed', () => {
spyOn(testChipInput, 'add');
chipInputDirective.separatorKeyCodes = [COMMA];
fixture.detectChanges();
dispatchKeyboardEvent(inputNativeElement, 'keydown', COMMA);
expect(testChipInput.add).toHaveBeenCalled();
});
it('emits accepts the custom separator keys in a Set', () => {
spyOn(testChipInput, 'add');
chipInputDirective.separatorKeyCodes = new Set([COMMA]);
fixture.detectChanges();
dispatchKeyboardEvent(inputNativeElement, 'keydown', COMMA);
expect(testChipInput.add).toHaveBeenCalled();
});
it('emits (chipEnd) when the separator keys are configured globally', () => {
fixture.destroy();
TestBed.resetTestingModule().configureTestingModule({
imports: [MatChipsModule, MatFormFieldModule, PlatformModule, NoopAnimationsModule],
declarations: [TestChipInput],
providers: [
{
provide: MAT_CHIPS_DEFAULT_OPTIONS,
useValue: {separatorKeyCodes: [COMMA]} as MatChipsDefaultOptions,
},
],
});
fixture = TestBed.createComponent(TestChipInput);
testChipInput = fixture.debugElement.componentInstance;
fixture.detectChanges();
inputDebugElement = fixture.debugElement.query(By.directive(MatChipInput))!;
chipInputDirective = inputDebugElement.injector.get<MatChipInput>(MatChipInput);
inputNativeElement = inputDebugElement.nativeElement;
spyOn(testChipInput, 'add');
fixture.detectChanges();
dispatchKeyboardEvent(inputNativeElement, 'keydown', COMMA);
expect(testChipInput.add).toHaveBeenCalled();
});
it('should not emit the chipEnd event if a separator is pressed with a modifier key', () => {
spyOn(testChipInput, 'add');
chipInputDirective.separatorKeyCodes = [ENTER];
fixture.detectChanges();
dispatchKeyboardEvent(inputNativeElement, 'keydown', ENTER, undefined, {shift: true});
expect(testChipInput.add).not.toHaveBeenCalled();
});
it('should set aria-describedby correctly when a non-empty list of ids is passed to setDescribedByIds', fakeAsync(() => {
const ids = ['a', 'b', 'c'];
testChipInput.chipGridInstance.setDescribedByIds(ids);
flush();
fixture.detectChanges();
expect(inputNativeElement.getAttribute('aria-describedby')).toEqual('a b c');
}));
it('should set aria-describedby correctly when an empty list of ids is passed to setDescribedByIds', fakeAsync(() => {
const ids: string[] = [];
testChipInput.chipGridInstance.setDescribedByIds(ids);
flush();
fixture.detectChanges();
expect(inputNativeElement.getAttribute('aria-describedby')).toBeNull();
}));
it('should not emit chipEnd if the key is repeated', () => {
spyOn(testChipInput, 'add');
chipInputDirective.separatorKeyCodes = [COMMA];
fixture.detectChanges();
const event = createKeyboardEvent('keydown', COMMA);
Object.defineProperty(event, 'repeat', {get: () => true});
dispatchEvent(inputNativeElement, event);
fixture.detectChanges();
expect(testChipInput.add).not.toHaveBeenCalled();
});
});
});
@Component({
template: `
<mat-form-field>
<mat-chip-grid #chipGrid [required]="required">
<mat-chip-row>Hello</mat-chip-row>
<input [matChipInputFor]="chipGrid"
[matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)"
[placeholder]="placeholder" />
</mat-chip-grid>
</mat-form-field>
`,
standalone: false,
})
class TestChipInput {
@ViewChild(MatChipGrid) chipGridInstance: MatChipGrid;
addOnBlur: boolean = false;
placeholder = '';
required = false;
add(_: MatChipInputEvent) {}
}