1
1
import { FocusKeyManager } from '@angular/cdk/a11y' ;
2
2
import { Directionality , Direction } from '@angular/cdk/bidi' ;
3
3
import { BACKSPACE , DELETE , ENTER , LEFT_ARROW , RIGHT_ARROW , SPACE , TAB } from '@angular/cdk/keycodes' ;
4
- import { createKeyboardEvent , dispatchFakeEvent , dispatchKeyboardEvent } from '@angular/cdk/testing' ;
4
+ import {
5
+ createKeyboardEvent ,
6
+ dispatchFakeEvent ,
7
+ dispatchKeyboardEvent ,
8
+ MockNgZone ,
9
+ } from '@angular/cdk/testing' ;
5
10
import {
6
11
Component ,
7
12
DebugElement ,
@@ -10,16 +15,18 @@ import {
10
15
ViewChildren ,
11
16
Type ,
12
17
Provider ,
18
+ NgZone ,
13
19
} from '@angular/core' ;
14
20
import { ComponentFixture , fakeAsync , TestBed , tick } from '@angular/core/testing' ;
15
21
import { FormControl , FormsModule , NgForm , ReactiveFormsModule , Validators } from '@angular/forms' ;
16
22
import { MatFormFieldModule } from '@angular/material/form-field' ;
17
23
import { By } from '@angular/platform-browser' ;
18
- import { NoopAnimationsModule } from '@angular/platform-browser/animations' ;
24
+ import { NoopAnimationsModule , BrowserAnimationsModule } from '@angular/platform-browser/animations' ;
19
25
import { MatInputModule } from '../input/index' ;
20
26
import { MatChip } from './chip' ;
21
27
import { MatChipInputEvent } from './chip-input' ;
22
28
import { MatChipList , MatChipsModule } from './index' ;
29
+ import { trigger , transition , style , animate } from '@angular/animations' ;
23
30
24
31
25
32
describe ( 'MatChipList' , ( ) => {
@@ -30,6 +37,7 @@ describe('MatChipList', () => {
30
37
let testComponent : StandardChipList ;
31
38
let chips : QueryList < any > ;
32
39
let manager : FocusKeyManager < MatChip > ;
40
+ let zone : MockNgZone ;
33
41
34
42
describe ( 'StandardChipList' , ( ) => {
35
43
describe ( 'basic behaviors' , ( ) => {
@@ -189,6 +197,7 @@ describe('MatChipList', () => {
189
197
// Focus and blur the middle item
190
198
midItem . focus ( ) ;
191
199
midItem . _blur ( ) ;
200
+ zone . simulateZoneExit ( ) ;
192
201
193
202
// Destroy the middle item
194
203
testComponent . remove = 2 ;
@@ -197,6 +206,32 @@ describe('MatChipList', () => {
197
206
// Should not have focus
198
207
expect ( chipListInstance . _keyManager . activeItemIndex ) . toEqual ( - 1 ) ;
199
208
} ) ;
209
+
210
+ it ( 'should move focus to the last chip when the focused chip was deleted inside a' +
211
+ 'component with animations' , fakeAsync ( ( ) => {
212
+ fixture . destroy ( ) ;
213
+ TestBed . resetTestingModule ( ) ;
214
+ fixture = createComponent ( StandardChipListWithAnimations , [ ] , BrowserAnimationsModule ) ;
215
+ fixture . detectChanges ( ) ;
216
+
217
+ chipListDebugElement = fixture . debugElement . query ( By . directive ( MatChipList ) ) ;
218
+ chipListNativeElement = chipListDebugElement . nativeElement ;
219
+ chipListInstance = chipListDebugElement . componentInstance ;
220
+ testComponent = fixture . debugElement . componentInstance ;
221
+ chips = chipListInstance . chips ;
222
+
223
+ chips . last . focus ( ) ;
224
+ fixture . detectChanges ( ) ;
225
+
226
+ expect ( chipListInstance . _keyManager . activeItemIndex ) . toBe ( chips . length - 1 ) ;
227
+
228
+ dispatchKeyboardEvent ( chips . last . _elementRef . nativeElement , 'keydown' , BACKSPACE ) ;
229
+ fixture . detectChanges ( ) ;
230
+ tick ( 500 ) ;
231
+
232
+ expect ( chipListInstance . _keyManager . activeItemIndex ) . toBe ( chips . length - 1 ) ;
233
+ } ) ) ;
234
+
200
235
} ) ;
201
236
} ) ;
202
237
@@ -1053,18 +1088,23 @@ describe('MatChipList', () => {
1053
1088
} ) ;
1054
1089
} ) ;
1055
1090
1056
- function createComponent < T > ( component : Type < T > , providers : Provider [ ] = [ ] ) : ComponentFixture < T > {
1091
+ function createComponent < T > ( component : Type < T > , providers : Provider [ ] = [ ] , animationsModule :
1092
+ Type < NoopAnimationsModule > | Type < BrowserAnimationsModule > = NoopAnimationsModule ) :
1093
+ ComponentFixture < T > {
1057
1094
TestBed . configureTestingModule ( {
1058
1095
imports : [
1059
1096
FormsModule ,
1060
1097
ReactiveFormsModule ,
1061
1098
MatChipsModule ,
1062
1099
MatFormFieldModule ,
1063
1100
MatInputModule ,
1064
- NoopAnimationsModule ,
1101
+ animationsModule ,
1065
1102
] ,
1066
1103
declarations : [ component ] ,
1067
- providers
1104
+ providers : [
1105
+ { provide : NgZone , useFactory : ( ) => zone = new MockNgZone ( ) } ,
1106
+ ...providers
1107
+ ]
1068
1108
} ) . compileComponents ( ) ;
1069
1109
1070
1110
return TestBed . createComponent < T > ( component ) ;
@@ -1328,3 +1368,33 @@ class ChipListWithFormErrorMessages {
1328
1368
@ViewChild ( 'form' ) form : NgForm ;
1329
1369
formControl = new FormControl ( '' , Validators . required ) ;
1330
1370
}
1371
+
1372
+
1373
+ @Component ( {
1374
+ template : `
1375
+ <mat-chip-list>
1376
+ <mat-chip *ngFor="let i of numbers" (removed)="remove(i)">{{i}}</mat-chip>
1377
+ </mat-chip-list>` ,
1378
+ animations : [
1379
+ // For the case we're testing this animation doesn't
1380
+ // have to be used anywhere, it just has to be defined.
1381
+ trigger ( 'dummyAnimation' , [
1382
+ transition ( ':leave' , [
1383
+ style ( { opacity : 0 } ) ,
1384
+ animate ( '500ms' , style ( { opacity : 1 } ) )
1385
+ ] )
1386
+ ] )
1387
+ ]
1388
+ } )
1389
+ class StandardChipListWithAnimations {
1390
+ numbers = [ 0 , 1 , 2 , 3 , 4 ] ;
1391
+
1392
+ remove ( item : number ) : void {
1393
+ const index = this . numbers . indexOf ( item ) ;
1394
+
1395
+ if ( index > - 1 ) {
1396
+ this . numbers . splice ( index , 1 ) ;
1397
+ }
1398
+ }
1399
+ }
1400
+
0 commit comments