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' , ( ) => {
@@ -154,6 +162,7 @@ describe('MatChipList', () => {
154
162
// Focus and blur the middle item
155
163
midItem . focus ( ) ;
156
164
midItem . _blur ( ) ;
165
+ zone . simulateZoneExit ( ) ;
157
166
158
167
// Destroy the middle item
159
168
testComponent . remove = 2 ;
@@ -162,6 +171,32 @@ describe('MatChipList', () => {
162
171
// Should not have focus
163
172
expect ( chipListInstance . _keyManager . activeItemIndex ) . toEqual ( - 1 ) ;
164
173
} ) ;
174
+
175
+ it ( 'should move focus to the last chip when the focused chip was deleted inside a' +
176
+ 'component with animations' , fakeAsync ( ( ) => {
177
+ fixture . destroy ( ) ;
178
+ TestBed . resetTestingModule ( ) ;
179
+ fixture = createComponent ( StandardChipListWithAnimations , [ ] , BrowserAnimationsModule ) ;
180
+ fixture . detectChanges ( ) ;
181
+
182
+ chipListDebugElement = fixture . debugElement . query ( By . directive ( MatChipList ) ) ;
183
+ chipListNativeElement = chipListDebugElement . nativeElement ;
184
+ chipListInstance = chipListDebugElement . componentInstance ;
185
+ testComponent = fixture . debugElement . componentInstance ;
186
+ chips = chipListInstance . chips ;
187
+
188
+ chips . last . focus ( ) ;
189
+ fixture . detectChanges ( ) ;
190
+
191
+ expect ( chipListInstance . _keyManager . activeItemIndex ) . toBe ( chips . length - 1 ) ;
192
+
193
+ dispatchKeyboardEvent ( chips . last . _elementRef . nativeElement , 'keydown' , BACKSPACE ) ;
194
+ fixture . detectChanges ( ) ;
195
+ tick ( 500 ) ;
196
+
197
+ expect ( chipListInstance . _keyManager . activeItemIndex ) . toBe ( chips . length - 1 ) ;
198
+ } ) ) ;
199
+
165
200
} ) ;
166
201
} ) ;
167
202
@@ -1018,18 +1053,23 @@ describe('MatChipList', () => {
1018
1053
} ) ;
1019
1054
} ) ;
1020
1055
1021
- function createComponent < T > ( component : Type < T > , providers : Provider [ ] = [ ] ) : ComponentFixture < T > {
1056
+ function createComponent < T > ( component : Type < T > , providers : Provider [ ] = [ ] , animationsModule :
1057
+ Type < NoopAnimationsModule > | Type < BrowserAnimationsModule > = NoopAnimationsModule ) :
1058
+ ComponentFixture < T > {
1022
1059
TestBed . configureTestingModule ( {
1023
1060
imports : [
1024
1061
FormsModule ,
1025
1062
ReactiveFormsModule ,
1026
1063
MatChipsModule ,
1027
1064
MatFormFieldModule ,
1028
1065
MatInputModule ,
1029
- NoopAnimationsModule ,
1066
+ animationsModule ,
1030
1067
] ,
1031
1068
declarations : [ component ] ,
1032
- providers
1069
+ providers : [
1070
+ { provide : NgZone , useFactory : ( ) => zone = new MockNgZone ( ) } ,
1071
+ ...providers
1072
+ ]
1033
1073
} ) . compileComponents ( ) ;
1034
1074
1035
1075
return TestBed . createComponent < T > ( component ) ;
@@ -1293,3 +1333,33 @@ class ChipListWithFormErrorMessages {
1293
1333
@ViewChild ( 'form' ) form : NgForm ;
1294
1334
formControl = new FormControl ( '' , Validators . required ) ;
1295
1335
}
1336
+
1337
+
1338
+ @Component ( {
1339
+ template : `
1340
+ <mat-chip-list>
1341
+ <mat-chip *ngFor="let i of numbers" (removed)="remove(i)">{{i}}</mat-chip>
1342
+ </mat-chip-list>` ,
1343
+ animations : [
1344
+ // For the case we're testing this animation doesn't
1345
+ // have to be used anywhere, it just has to be defined.
1346
+ trigger ( 'dummyAnimation' , [
1347
+ transition ( ':leave' , [
1348
+ style ( { opacity : 0 } ) ,
1349
+ animate ( '500ms' , style ( { opacity : 1 } ) )
1350
+ ] )
1351
+ ] )
1352
+ ]
1353
+ } )
1354
+ class StandardChipListWithAnimations {
1355
+ numbers = [ 0 , 1 , 2 , 3 , 4 ] ;
1356
+
1357
+ remove ( item : number ) : void {
1358
+ const index = this . numbers . indexOf ( item ) ;
1359
+
1360
+ if ( index > - 1 ) {
1361
+ this . numbers . splice ( index , 1 ) ;
1362
+ }
1363
+ }
1364
+ }
1365
+
0 commit comments