Skip to content

Commit dba8a0c

Browse files
crisbetojelbourn
authored andcommitted
refactor(chip-list): improve unit test speed (#10564)
Speeds up the chip list tests by not recompiling all of the different test components for every test. Also switches all of the `async` tests to run inside `fakeAsync` instead.
1 parent fddb40d commit dba8a0c

File tree

1 file changed

+68
-78
lines changed

1 file changed

+68
-78
lines changed

src/lib/chips/chip-list.spec.ts

Lines changed: 68 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import {FocusKeyManager} from '@angular/cdk/a11y';
2-
import {Directionality} from '@angular/cdk/bidi';
2+
import {Directionality, Direction} from '@angular/cdk/bidi';
33
import {BACKSPACE, DELETE, ENTER, LEFT_ARROW, RIGHT_ARROW, SPACE, TAB} from '@angular/cdk/keycodes';
44
import {createKeyboardEvent, dispatchFakeEvent, dispatchKeyboardEvent} from '@angular/cdk/testing';
5-
import {Component, DebugElement, QueryList, ViewChild, ViewChildren} from '@angular/core';
6-
import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
5+
import {
6+
Component,
7+
DebugElement,
8+
QueryList,
9+
ViewChild,
10+
ViewChildren,
11+
Type,
12+
Provider,
13+
} from '@angular/core';
14+
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
715
import {FormControl, FormsModule, NgForm, ReactiveFormsModule, Validators} from '@angular/forms';
816
import {MatFormFieldModule} from '@angular/material/form-field';
917
import {By} from '@angular/platform-browser';
@@ -22,43 +30,12 @@ describe('MatChipList', () => {
2230
let testComponent: StandardChipList;
2331
let chips: QueryList<any>;
2432
let manager: FocusKeyManager<MatChip>;
25-
let dir = 'ltr';
26-
27-
beforeEach(async(() => {
28-
TestBed.configureTestingModule({
29-
imports: [
30-
FormsModule,
31-
ReactiveFormsModule,
32-
MatChipsModule,
33-
MatFormFieldModule,
34-
MatInputModule,
35-
NoopAnimationsModule
36-
],
37-
declarations: [
38-
ChipListWithFormErrorMessages,
39-
StandardChipList,
40-
FormFieldChipList,
41-
BasicChipList,
42-
InputChipList,
43-
MultiSelectionChipList,
44-
FalsyValueChipList,
45-
SelectedChipList
46-
],
47-
providers: [{
48-
provide: Directionality, useFactory: () => {
49-
return {value: dir.toLowerCase()};
50-
}
51-
}]
52-
});
53-
54-
TestBed.compileComponents();
55-
}));
5633

5734
describe('StandardChipList', () => {
5835
describe('basic behaviors', () => {
59-
beforeEach(async(() => {
36+
beforeEach(() => {
6037
setupStandardList();
61-
}));
38+
});
6239

6340
it('should add the `mat-chip-list` class', () => {
6441
expect(chipListNativeElement.classList).toContain('mat-chip-list');
@@ -76,12 +53,12 @@ describe('MatChipList', () => {
7653
});
7754

7855
describe('with selected chips', () => {
79-
beforeEach(async(() => {
80-
fixture = TestBed.createComponent(SelectedChipList);
56+
beforeEach(() => {
57+
fixture = createComponent(SelectedChipList);
8158
fixture.detectChanges();
8259
chipListDebugElement = fixture.debugElement.query(By.directive(MatChipList));
8360
chipListNativeElement = chipListDebugElement.nativeElement;
84-
}));
61+
});
8562

8663
it('should not override chips selected', () => {
8764
const instanceChips = fixture.componentInstance.chips.toArray();
@@ -104,10 +81,10 @@ describe('MatChipList', () => {
10481
});
10582

10683
describe('focus behaviors', () => {
107-
beforeEach(async(() => {
84+
beforeEach(() => {
10885
setupStandardList();
10986
manager = chipListInstance._keyManager;
110-
}));
87+
});
11188

11289
it('should focus the first chip on focus', () => {
11390
chipListInstance.focus();
@@ -190,11 +167,10 @@ describe('MatChipList', () => {
190167

191168
describe('keyboard behavior', () => {
192169
describe('LTR (default)', () => {
193-
beforeEach(async(() => {
194-
dir = 'ltr';
170+
beforeEach(() => {
195171
setupStandardList();
196172
manager = chipListInstance._keyManager;
197-
}));
173+
});
198174

199175
it('should focus previous item when press LEFT ARROW', () => {
200176
let nativeChips = chipListNativeElement.querySelectorAll('mat-chip');
@@ -253,11 +229,10 @@ describe('MatChipList', () => {
253229
});
254230

255231
describe('RTL', () => {
256-
beforeEach(async(() => {
257-
dir = 'rtl';
258-
setupStandardList();
232+
beforeEach(() => {
233+
setupStandardList('rtl');
259234
manager = chipListInstance._keyManager;
260-
}));
235+
});
261236

262237
it('should focus previous item when press RIGHT ARROW', () => {
263238
let nativeChips = chipListNativeElement.querySelectorAll('mat-chip');
@@ -411,7 +386,7 @@ describe('MatChipList', () => {
411386
let nativeChips: HTMLElement[];
412387

413388
beforeEach(() => {
414-
fixture = TestBed.createComponent(BasicChipList);
389+
fixture = createComponent(BasicChipList);
415390
fixture.detectChanges();
416391

417392
formField = fixture.debugElement.query(By.css('.mat-form-field')).nativeElement;
@@ -430,7 +405,7 @@ describe('MatChipList', () => {
430405
.toBe(true, 'placeholder should be floating');
431406
});
432407

433-
it('should remove selection if chip has been removed', async(() => {
408+
it('should remove selection if chip has been removed', fakeAsync(() => {
434409
const instanceChips = fixture.componentInstance.chips;
435410
const chipList = fixture.componentInstance.chipList;
436411
const firstChip = nativeChips[0];
@@ -442,11 +417,10 @@ describe('MatChipList', () => {
442417

443418
fixture.componentInstance.foods = [];
444419
fixture.detectChanges();
420+
tick();
445421

446-
fixture.whenStable().then(() => {
447-
expect(chipList.selected)
448-
.toBe(undefined, 'Expected selection to be removed when option no longer exists.');
449-
});
422+
expect(chipList.selected)
423+
.toBe(undefined, 'Expected selection to be removed when option no longer exists.');
450424
}));
451425

452426

@@ -486,7 +460,7 @@ describe('MatChipList', () => {
486460

487461
describe('single selection', () => {
488462
beforeEach(() => {
489-
fixture = TestBed.createComponent(BasicChipList);
463+
fixture = createComponent(BasicChipList);
490464
fixture.detectChanges();
491465

492466
nativeChips = fixture.debugElement.queryAll(By.css('mat-chip'))
@@ -623,8 +597,9 @@ describe('MatChipList', () => {
623597

624598
it('should be able to programmatically select a falsy option', () => {
625599
fixture.destroy();
600+
TestBed.resetTestingModule();
626601

627-
const falsyFixture = TestBed.createComponent(FalsyValueChipList);
602+
const falsyFixture = createComponent(FalsyValueChipList);
628603
falsyFixture.detectChanges();
629604

630605
falsyFixture.componentInstance.control.setValue([0]);
@@ -649,7 +624,7 @@ describe('MatChipList', () => {
649624

650625
describe('multiple selection', () => {
651626
beforeEach(() => {
652-
fixture = TestBed.createComponent(MultiSelectionChipList);
627+
fixture = createComponent(MultiSelectionChipList);
653628
fixture.detectChanges();
654629

655630
nativeChips = fixture.debugElement.queryAll(By.css('mat-chip'))
@@ -732,7 +707,7 @@ describe('MatChipList', () => {
732707
let nativeChips: HTMLElement[];
733708

734709
beforeEach(() => {
735-
fixture = TestBed.createComponent(InputChipList);
710+
fixture = createComponent(InputChipList);
736711
fixture.detectChanges();
737712

738713
nativeChips = fixture.debugElement.queryAll(By.css('mat-chip'))
@@ -807,18 +782,17 @@ describe('MatChipList', () => {
807782
.toBeFalsy(`Expected chip with the old value not to be selected.`);
808783
});
809784

810-
it('should set the control to touched when the chip list is touched', async(() => {
785+
it('should set the control to touched when the chip list is touched', fakeAsync(() => {
811786
expect(fixture.componentInstance.control.touched)
812787
.toBe(false, 'Expected the control to start off as untouched.');
813788

814789
const nativeChipList = fixture.debugElement.query(By.css('.mat-chip-list')).nativeElement;
815790

816791
dispatchFakeEvent(nativeChipList, 'blur');
792+
tick();
817793

818-
fixture.whenStable().then(() => {
819-
expect(fixture.componentInstance.control.touched)
820-
.toBe(true, 'Expected the control to be touched.');
821-
});
794+
expect(fixture.componentInstance.control.touched)
795+
.toBe(true, 'Expected the control to be touched.');
822796
}));
823797

824798
it('should not set touched when a disabled chip list is touched', () => {
@@ -870,8 +844,6 @@ describe('MatChipList', () => {
870844

871845
describe('keyboard behavior', () => {
872846
beforeEach(() => {
873-
fixture = TestBed.createComponent(InputChipList);
874-
fixture.detectChanges();
875847
chipListDebugElement = fixture.debugElement.query(By.directive(MatChipList));
876848
chipListInstance = chipListDebugElement.componentInstance;
877849
chips = chipListInstance.chips;
@@ -924,7 +896,7 @@ describe('MatChipList', () => {
924896
let chipListEl: HTMLElement;
925897

926898
beforeEach(() => {
927-
fixture = TestBed.createComponent(ChipListWithFormErrorMessages);
899+
fixture = createComponent(ChipListWithFormErrorMessages);
928900
fixture.detectChanges();
929901
errorTestComponent = fixture.componentInstance;
930902
containerEl = fixture.debugElement.query(By.css('mat-form-field')).nativeElement;
@@ -939,23 +911,22 @@ describe('MatChipList', () => {
939911
.toBe('false', 'Expected aria-invalid to be set to "false".');
940912
});
941913

942-
it('should display an error message when the chip list is touched and invalid', async(() => {
914+
it('should display an error message when the list is touched and invalid', fakeAsync(() => {
943915
expect(errorTestComponent.formControl.invalid)
944916
.toBe(true, 'Expected form control to be invalid');
945917
expect(containerEl.querySelectorAll('mat-error').length)
946918
.toBe(0, 'Expected no error message');
947919

948920
errorTestComponent.formControl.markAsTouched();
949921
fixture.detectChanges();
922+
tick();
950923

951-
fixture.whenStable().then(() => {
952-
expect(containerEl.classList)
953-
.toContain('mat-form-field-invalid', 'Expected container to have the invalid CSS class.');
954-
expect(containerEl.querySelectorAll('mat-error').length)
955-
.toBe(1, 'Expected one error message to have been rendered.');
956-
expect(chipListEl.getAttribute('aria-invalid'))
957-
.toBe('true', 'Expected aria-invalid to be set to "true".');
958-
});
924+
expect(containerEl.classList)
925+
.toContain('mat-form-field-invalid', 'Expected container to have the invalid CSS class.');
926+
expect(containerEl.querySelectorAll('mat-error').length)
927+
.toBe(1, 'Expected one error message to have been rendered.');
928+
expect(chipListEl.getAttribute('aria-invalid'))
929+
.toBe('true', 'Expected aria-invalid to be set to "true".');
959930
}));
960931

961932
it('should display an error message when the parent form is submitted', fakeAsync(() => {
@@ -1033,8 +1004,27 @@ describe('MatChipList', () => {
10331004
});
10341005
});
10351006

1036-
function setupStandardList() {
1037-
fixture = TestBed.createComponent(StandardChipList);
1007+
function createComponent<T>(component: Type<T>, providers: Provider[] = []): ComponentFixture<T> {
1008+
TestBed.configureTestingModule({
1009+
imports: [
1010+
FormsModule,
1011+
ReactiveFormsModule,
1012+
MatChipsModule,
1013+
MatFormFieldModule,
1014+
MatInputModule,
1015+
NoopAnimationsModule,
1016+
],
1017+
declarations: [component],
1018+
providers
1019+
}).compileComponents();
1020+
1021+
return TestBed.createComponent<T>(component);
1022+
}
1023+
1024+
function setupStandardList(direction: Direction = 'ltr') {
1025+
fixture = createComponent(StandardChipList, [{
1026+
provide: Directionality, useFactory: () => ({value: direction.toLowerCase()})
1027+
}]);
10381028
fixture.detectChanges();
10391029

10401030
chipListDebugElement = fixture.debugElement.query(By.directive(MatChipList));
@@ -1045,7 +1035,7 @@ describe('MatChipList', () => {
10451035
}
10461036

10471037
function setupInputList() {
1048-
fixture = TestBed.createComponent(FormFieldChipList);
1038+
fixture = createComponent(FormFieldChipList);
10491039
fixture.detectChanges();
10501040

10511041
chipListDebugElement = fixture.debugElement.query(By.directive(MatChipList));

0 commit comments

Comments
 (0)