1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:ui';
6
7import 'package:flutter/material.dart';
8import 'package:flutter/rendering.dart';
9import 'package:flutter/services.dart';
10import 'package:flutter_test/flutter_test.dart';
11
12RenderBox getMaterialBox(WidgetTester tester, Finder type) {
13 return tester.firstRenderObject<RenderBox>(
14 find.descendant(of: type, matching: find.byType(CustomPaint)),
15 );
16}
17
18Material getMaterial(WidgetTester tester) {
19 return tester.widget<Material>(
20 find.descendant(of: find.byType(ChoiceChip), matching: find.byType(Material)),
21 );
22}
23
24IconThemeData getIconData(WidgetTester tester) {
25 final IconTheme iconTheme = tester.firstWidget(
26 find.descendant(of: find.byType(RawChip), matching: find.byType(IconTheme)),
27 );
28 return iconTheme.data;
29}
30
31DefaultTextStyle getLabelStyle(WidgetTester tester, String labelText) {
32 return tester.widget(
33 find.ancestor(of: find.text(labelText), matching: find.byType(DefaultTextStyle)).first,
34 );
35}
36
37/// Adds the basic requirements for a Chip.
38Widget wrapForChip({
39 required Widget child,
40 TextDirection textDirection = TextDirection.ltr,
41 TextScaler textScaler = TextScaler.noScaling,
42 Brightness brightness = Brightness.light,
43 bool? useMaterial3,
44}) {
45 return MaterialApp(
46 theme: ThemeData(brightness: brightness, useMaterial3: useMaterial3),
47 home: Directionality(
48 textDirection: textDirection,
49 child: MediaQuery(
50 data: MediaQueryData(textScaler: textScaler),
51 child: Material(child: child),
52 ),
53 ),
54 );
55}
56
57void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
58 final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
59 // There should be two Material widgets, first Material is from the "_wrapForChip" and
60 // last Material is from the "RawChip".
61 expect(materials.length, 2);
62 // The last Material from `RawChip` should have the clip behavior.
63 expect(materials.last.clipBehavior, clipBehavior);
64}
65
66void main() {
67 testWidgets('Material2 - ChoiceChip defaults', (WidgetTester tester) async {
68 final ThemeData theme = ThemeData(useMaterial3: false);
69 const String label = 'choice chip';
70
71 // Test enabled ChoiceChip defaults.
72 await tester.pumpWidget(
73 MaterialApp(
74 theme: theme,
75 home: Material(
76 child: Center(
77 child: ChoiceChip(
78 selected: false,
79 onSelected: (bool valueChanged) {},
80 label: const Text(label),
81 ),
82 ),
83 ),
84 ),
85 );
86
87 // Test default chip size.
88 expect(tester.getSize(find.byType(ChoiceChip)), const Size(178.0, 48.0));
89 // Test default label style.
90 expect(
91 getLabelStyle(tester, label).style.color,
92 theme.textTheme.bodyLarge!.color!.withAlpha(0xde),
93 );
94
95 Material chipMaterial = getMaterial(tester);
96 expect(chipMaterial.elevation, 0);
97 expect(chipMaterial.shadowColor, Colors.black);
98 expect(chipMaterial.shape, const StadiumBorder());
99
100 ShapeDecoration decoration =
101 tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
102 expect(decoration.color, Colors.black.withAlpha(0x1f));
103
104 // Test disabled ChoiceChip defaults.
105 await tester.pumpWidget(
106 MaterialApp(
107 theme: theme,
108 home: const Material(child: ChoiceChip(selected: false, label: Text(label))),
109 ),
110 );
111 await tester.pumpAndSettle();
112
113 chipMaterial = getMaterial(tester);
114 expect(chipMaterial.elevation, 0);
115 expect(chipMaterial.shadowColor, Colors.black);
116 expect(chipMaterial.shape, const StadiumBorder());
117
118 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
119 expect(decoration.color, Colors.black38);
120
121 // Test selected enabled ChoiceChip defaults.
122 await tester.pumpWidget(
123 MaterialApp(
124 theme: theme,
125 home: Material(
126 child: ChoiceChip(
127 selected: true,
128 onSelected: (bool valueChanged) {},
129 label: const Text(label),
130 ),
131 ),
132 ),
133 );
134 await tester.pumpAndSettle();
135
136 chipMaterial = getMaterial(tester);
137 expect(chipMaterial.elevation, 0);
138 expect(chipMaterial.shadowColor, Colors.black);
139 expect(chipMaterial.shape, const StadiumBorder());
140
141 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
142 expect(decoration.color, Colors.black.withAlpha(0x3d));
143
144 // Test selected disabled ChoiceChip defaults.
145 await tester.pumpWidget(
146 MaterialApp(
147 theme: theme,
148 home: const Material(child: ChoiceChip(selected: true, label: Text(label))),
149 ),
150 );
151 await tester.pumpAndSettle();
152
153 chipMaterial = getMaterial(tester);
154 expect(chipMaterial.elevation, 0);
155 expect(chipMaterial.shadowColor, Colors.black);
156 expect(chipMaterial.shape, const StadiumBorder());
157
158 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
159 expect(decoration.color, Colors.black.withAlpha(0x3d));
160 });
161
162 testWidgets('Material3 - ChoiceChip defaults', (WidgetTester tester) async {
163 final ThemeData theme = ThemeData();
164 const String label = 'choice chip';
165
166 // Test enabled ChoiceChip defaults.
167 await tester.pumpWidget(
168 MaterialApp(
169 theme: theme,
170 home: Material(
171 child: Center(
172 child: ChoiceChip(
173 selected: false,
174 onSelected: (bool valueChanged) {},
175 label: const Text(label),
176 ),
177 ),
178 ),
179 ),
180 );
181
182 // Test default chip size.
183 expect(
184 tester.getSize(find.byType(ChoiceChip)),
185 within(distance: 0.01, from: const Size(189.1, 48.0)),
186 );
187 // Test default label style.
188 expect(
189 getLabelStyle(tester, label).style.color!.value,
190 theme.colorScheme.onSurfaceVariant.value,
191 );
192
193 Material chipMaterial = getMaterial(tester);
194 expect(chipMaterial.elevation, 0);
195 expect(chipMaterial.shadowColor, Colors.transparent);
196 expect(chipMaterial.surfaceTintColor, Colors.transparent);
197 expect(
198 chipMaterial.shape,
199 RoundedRectangleBorder(
200 borderRadius: const BorderRadius.all(Radius.circular(8.0)),
201 side: BorderSide(color: theme.colorScheme.outlineVariant),
202 ),
203 );
204
205 ShapeDecoration decoration =
206 tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
207 expect(decoration.color, null);
208
209 // Test disabled ChoiceChip defaults.
210 await tester.pumpWidget(
211 MaterialApp(
212 theme: theme,
213 home: const Material(child: ChoiceChip(selected: false, label: Text(label))),
214 ),
215 );
216 await tester.pumpAndSettle();
217
218 chipMaterial = getMaterial(tester);
219 expect(chipMaterial.elevation, 0);
220 expect(chipMaterial.shadowColor, Colors.transparent);
221 expect(chipMaterial.surfaceTintColor, Colors.transparent);
222 expect(
223 chipMaterial.shape,
224 RoundedRectangleBorder(
225 borderRadius: const BorderRadius.all(Radius.circular(8.0)),
226 side: BorderSide(color: theme.colorScheme.onSurface.withOpacity(0.12)),
227 ),
228 );
229
230 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
231 expect(decoration.color, null);
232
233 // Test selected enabled ChoiceChip defaults.
234 await tester.pumpWidget(
235 MaterialApp(
236 theme: theme,
237 home: Material(
238 child: ChoiceChip(
239 selected: true,
240 onSelected: (bool valueChanged) {},
241 label: const Text(label),
242 ),
243 ),
244 ),
245 );
246 await tester.pumpAndSettle();
247
248 chipMaterial = getMaterial(tester);
249 expect(chipMaterial.elevation, 0);
250 expect(chipMaterial.shadowColor, null);
251 expect(chipMaterial.surfaceTintColor, Colors.transparent);
252 expect(
253 chipMaterial.shape,
254 const RoundedRectangleBorder(
255 borderRadius: BorderRadius.all(Radius.circular(8.0)),
256 side: BorderSide(color: Colors.transparent),
257 ),
258 );
259
260 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
261 expect(decoration.color, theme.colorScheme.secondaryContainer);
262
263 // Test selected disabled ChoiceChip defaults.
264 await tester.pumpWidget(
265 MaterialApp(
266 theme: theme,
267 home: const Material(child: ChoiceChip(selected: true, label: Text(label))),
268 ),
269 );
270 await tester.pumpAndSettle();
271
272 chipMaterial = getMaterial(tester);
273 expect(chipMaterial.elevation, 0);
274 expect(chipMaterial.shadowColor, null);
275 expect(chipMaterial.surfaceTintColor, Colors.transparent);
276 expect(
277 chipMaterial.shape,
278 const RoundedRectangleBorder(
279 borderRadius: BorderRadius.all(Radius.circular(8.0)),
280 side: BorderSide(color: Colors.transparent),
281 ),
282 );
283
284 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
285 expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12));
286 });
287
288 testWidgets('Material3 - ChoiceChip.elevated defaults', (WidgetTester tester) async {
289 final ThemeData theme = ThemeData();
290 const String label = 'choice chip';
291
292 // Test enabled ChoiceChip.elevated defaults.
293 await tester.pumpWidget(
294 MaterialApp(
295 theme: theme,
296 home: Material(
297 child: Center(
298 child: ChoiceChip.elevated(
299 selected: false,
300 onSelected: (bool valueChanged) {},
301 label: const Text(label),
302 ),
303 ),
304 ),
305 ),
306 );
307
308 // Test default chip size.
309 expect(
310 tester.getSize(find.byType(ChoiceChip)),
311 within(distance: 0.01, from: const Size(189.1, 48.0)),
312 );
313 // Test default label style.
314 expect(
315 getLabelStyle(tester, label).style.color!.value,
316 theme.colorScheme.onSurfaceVariant.value,
317 );
318
319 Material chipMaterial = getMaterial(tester);
320 expect(chipMaterial.elevation, 1);
321 expect(chipMaterial.shadowColor, theme.colorScheme.shadow);
322 expect(chipMaterial.surfaceTintColor, Colors.transparent);
323 expect(
324 chipMaterial.shape,
325 const RoundedRectangleBorder(
326 borderRadius: BorderRadius.all(Radius.circular(8.0)),
327 side: BorderSide(color: Colors.transparent),
328 ),
329 );
330
331 ShapeDecoration decoration =
332 tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
333 expect(decoration.color, theme.colorScheme.surfaceContainerLow);
334
335 // Test disabled ChoiceChip.elevated defaults.
336 await tester.pumpWidget(
337 MaterialApp(
338 theme: theme,
339 home: const Material(child: ChoiceChip.elevated(selected: false, label: Text(label))),
340 ),
341 );
342 await tester.pumpAndSettle();
343
344 chipMaterial = getMaterial(tester);
345 expect(chipMaterial.elevation, 0);
346 expect(chipMaterial.shadowColor, theme.colorScheme.shadow);
347 expect(chipMaterial.surfaceTintColor, Colors.transparent);
348 expect(
349 chipMaterial.shape,
350 const RoundedRectangleBorder(
351 borderRadius: BorderRadius.all(Radius.circular(8.0)),
352 side: BorderSide(color: Colors.transparent),
353 ),
354 );
355
356 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
357 expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12));
358
359 // Test selected enabled ChoiceChip.elevated defaults.
360 await tester.pumpWidget(
361 MaterialApp(
362 theme: theme,
363 home: Material(
364 child: ChoiceChip.elevated(
365 selected: true,
366 onSelected: (bool valueChanged) {},
367 label: const Text(label),
368 ),
369 ),
370 ),
371 );
372 await tester.pumpAndSettle();
373
374 chipMaterial = getMaterial(tester);
375 expect(chipMaterial.elevation, 1);
376 expect(chipMaterial.shadowColor, null);
377 expect(chipMaterial.surfaceTintColor, Colors.transparent);
378 expect(
379 chipMaterial.shape,
380 const RoundedRectangleBorder(
381 borderRadius: BorderRadius.all(Radius.circular(8.0)),
382 side: BorderSide(color: Colors.transparent),
383 ),
384 );
385
386 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
387 expect(decoration.color, theme.colorScheme.secondaryContainer);
388
389 // Test selected disabled ChoiceChip.elevated defaults.
390 await tester.pumpWidget(
391 MaterialApp(
392 theme: theme,
393 home: const Material(child: ChoiceChip.elevated(selected: false, label: Text(label))),
394 ),
395 );
396 await tester.pumpAndSettle();
397
398 chipMaterial = getMaterial(tester);
399 expect(chipMaterial.elevation, 0);
400 expect(chipMaterial.shadowColor, theme.colorScheme.shadow);
401 expect(chipMaterial.surfaceTintColor, Colors.transparent);
402 expect(
403 chipMaterial.shape,
404 const RoundedRectangleBorder(
405 borderRadius: BorderRadius.all(Radius.circular(8.0)),
406 side: BorderSide(color: Colors.transparent),
407 ),
408 );
409
410 decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration;
411 expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12));
412 });
413
414 testWidgets('ChoiceChip.color resolves material states', (WidgetTester tester) async {
415 const Color disabledSelectedColor = Color(0xffffff00);
416 const Color disabledColor = Color(0xff00ff00);
417 const Color backgroundColor = Color(0xff0000ff);
418 const Color selectedColor = Color(0xffff0000);
419 final MaterialStateProperty<Color?> color = MaterialStateProperty.resolveWith((
420 Set<MaterialState> states,
421 ) {
422 if (states.contains(MaterialState.disabled) && states.contains(MaterialState.selected)) {
423 return disabledSelectedColor;
424 }
425 if (states.contains(MaterialState.disabled)) {
426 return disabledColor;
427 }
428 if (states.contains(MaterialState.selected)) {
429 return selectedColor;
430 }
431 return backgroundColor;
432 });
433 Widget buildApp({required bool enabled, required bool selected}) {
434 return wrapForChip(
435 child: Column(
436 children: <Widget>[
437 ChoiceChip(
438 onSelected: enabled ? (bool value) {} : null,
439 selected: selected,
440 color: color,
441 label: const Text('ChoiceChip'),
442 ),
443 ChoiceChip.elevated(
444 onSelected: enabled ? (bool value) {} : null,
445 selected: selected,
446 color: color,
447 label: const Text('ChoiceChip.elevated'),
448 ),
449 ],
450 ),
451 );
452 }
453
454 // Test enabled state.
455 await tester.pumpWidget(buildApp(enabled: true, selected: false));
456
457 // Enabled ChoiceChip should have the provided backgroundColor.
458 expect(
459 getMaterialBox(tester, find.byType(RawChip).first),
460 paints..rrect(color: backgroundColor),
461 );
462 // Enabled elevated ChoiceChip should have the provided backgroundColor.
463 expect(
464 getMaterialBox(tester, find.byType(RawChip).last),
465 paints..rrect(color: backgroundColor),
466 );
467
468 // Test disabled state.
469 await tester.pumpWidget(buildApp(enabled: false, selected: false));
470 await tester.pumpAndSettle();
471
472 // Disabled ChoiceChip should have the provided disabledColor.
473 expect(getMaterialBox(tester, find.byType(RawChip).first), paints..rrect(color: disabledColor));
474 // Disabled elevated ChoiceChip should have the provided disabledColor.
475 expect(getMaterialBox(tester, find.byType(RawChip).last), paints..rrect(color: disabledColor));
476
477 // Test enabled & selected state.
478 await tester.pumpWidget(buildApp(enabled: true, selected: true));
479 await tester.pumpAndSettle();
480
481 // Enabled & selected ChoiceChip should have the provided selectedColor.
482 expect(getMaterialBox(tester, find.byType(RawChip).first), paints..rrect(color: selectedColor));
483 // Enabled & selected elevated ChoiceChip should have the provided selectedColor.
484 expect(getMaterialBox(tester, find.byType(RawChip).last), paints..rrect(color: selectedColor));
485
486 // Test disabled & selected state.
487 await tester.pumpWidget(buildApp(enabled: false, selected: true));
488 await tester.pumpAndSettle();
489
490 // Disabled & selected ChoiceChip should have the provided disabledSelectedColor.
491 expect(
492 getMaterialBox(tester, find.byType(RawChip).first),
493 paints..rrect(color: disabledSelectedColor),
494 );
495 // Disabled & selected elevated ChoiceChip should have the provided disabledSelectedColor.
496 expect(
497 getMaterialBox(tester, find.byType(RawChip).last),
498 paints..rrect(color: disabledSelectedColor),
499 );
500 });
501
502 testWidgets('ChoiceChip uses provided state color properties', (WidgetTester tester) async {
503 const Color disabledColor = Color(0xff00ff00);
504 const Color backgroundColor = Color(0xff0000ff);
505 const Color selectedColor = Color(0xffff0000);
506 Widget buildApp({required bool enabled, required bool selected}) {
507 return wrapForChip(
508 child: Column(
509 children: <Widget>[
510 ChoiceChip(
511 onSelected: enabled ? (bool value) {} : null,
512 selected: selected,
513 disabledColor: disabledColor,
514 backgroundColor: backgroundColor,
515 selectedColor: selectedColor,
516 label: const Text('ChoiceChip'),
517 ),
518 ChoiceChip.elevated(
519 onSelected: enabled ? (bool value) {} : null,
520 selected: selected,
521 disabledColor: disabledColor,
522 backgroundColor: backgroundColor,
523 selectedColor: selectedColor,
524 label: const Text('ChoiceChip.elevated'),
525 ),
526 ],
527 ),
528 );
529 }
530
531 // Test enabled chips.
532 await tester.pumpWidget(buildApp(enabled: true, selected: false));
533
534 // Enabled ChoiceChip should have the provided backgroundColor.
535 expect(
536 getMaterialBox(tester, find.byType(RawChip).first),
537 paints..rrect(color: backgroundColor),
538 );
539 // Enabled elevated ChoiceChip should have the provided backgroundColor.
540 expect(
541 getMaterialBox(tester, find.byType(RawChip).last),
542 paints..rrect(color: backgroundColor),
543 );
544
545 // Test disabled chips.
546 await tester.pumpWidget(buildApp(enabled: false, selected: false));
547 await tester.pumpAndSettle();
548
549 // Disabled ChoiceChip should have the provided disabledColor.
550 expect(getMaterialBox(tester, find.byType(RawChip).first), paints..rrect(color: disabledColor));
551 // Disabled elevated ChoiceChip should have the provided disabledColor.
552 expect(getMaterialBox(tester, find.byType(RawChip).last), paints..rrect(color: disabledColor));
553
554 // Test enabled & selected chips.
555 await tester.pumpWidget(buildApp(enabled: true, selected: true));
556 await tester.pumpAndSettle();
557
558 // Enabled & selected ChoiceChip should have the provided selectedColor.
559 expect(getMaterialBox(tester, find.byType(RawChip).first), paints..rrect(color: selectedColor));
560 // Enabled & selected elevated ChoiceChip should have the provided selectedColor.
561 expect(getMaterialBox(tester, find.byType(RawChip).last), paints..rrect(color: selectedColor));
562 });
563
564 testWidgets('ChoiceChip can be tapped', (WidgetTester tester) async {
565 await tester.pumpWidget(
566 const MaterialApp(
567 home: Material(child: ChoiceChip(selected: false, label: Text('choice chip'))),
568 ),
569 );
570
571 await tester.tap(find.byType(ChoiceChip));
572 expect(tester.takeException(), null);
573 });
574
575 testWidgets('ChoiceChip clipBehavior properly passes through to the Material', (
576 WidgetTester tester,
577 ) async {
578 const Text label = Text('label');
579 await tester.pumpWidget(wrapForChip(child: const ChoiceChip(label: label, selected: false)));
580 checkChipMaterialClipBehavior(tester, Clip.none);
581
582 await tester.pumpWidget(
583 wrapForChip(
584 child: const ChoiceChip(label: label, selected: false, clipBehavior: Clip.antiAlias),
585 ),
586 );
587 checkChipMaterialClipBehavior(tester, Clip.antiAlias);
588 });
589
590 testWidgets('ChoiceChip passes iconTheme property to RawChip', (WidgetTester tester) async {
591 const IconThemeData iconTheme = IconThemeData(color: Colors.red);
592 await tester.pumpWidget(
593 wrapForChip(
594 child: const ChoiceChip(label: Text('Test'), selected: true, iconTheme: iconTheme),
595 ),
596 );
597 final RawChip rawChip = tester.widget(find.byType(RawChip));
598 expect(rawChip.iconTheme, iconTheme);
599 });
600
601 testWidgets('ChoiceChip passes showCheckmark from ChipTheme to RawChip', (
602 WidgetTester tester,
603 ) async {
604 const bool showCheckmark = false;
605 await tester.pumpWidget(
606 wrapForChip(
607 child: const ChipTheme(
608 data: ChipThemeData(showCheckmark: showCheckmark),
609 child: ChoiceChip(label: Text('Test'), selected: true),
610 ),
611 ),
612 );
613 final RawChip rawChip = tester.widget(find.byType(RawChip));
614 expect(rawChip.showCheckmark, showCheckmark);
615 });
616
617 testWidgets('ChoiceChip passes checkmark properties to RawChip', (WidgetTester tester) async {
618 const bool showCheckmark = false;
619 const Color checkmarkColor = Color(0xff0000ff);
620 await tester.pumpWidget(
621 wrapForChip(
622 child: const ChoiceChip(
623 label: Text('Test'),
624 selected: true,
625 showCheckmark: showCheckmark,
626 checkmarkColor: checkmarkColor,
627 ),
628 ),
629 );
630 final RawChip rawChip = tester.widget(find.byType(RawChip));
631 expect(rawChip.showCheckmark, showCheckmark);
632 expect(rawChip.checkmarkColor, checkmarkColor);
633 });
634
635 testWidgets('ChoiceChip uses provided iconTheme', (WidgetTester tester) async {
636 final ThemeData theme = ThemeData();
637
638 Widget buildChip({IconThemeData? iconTheme}) {
639 return MaterialApp(
640 theme: theme,
641 home: Material(
642 child: ChoiceChip(
643 iconTheme: iconTheme,
644 avatar: const Icon(Icons.add),
645 label: const Text('Test'),
646 selected: false,
647 onSelected: (bool _) {},
648 ),
649 ),
650 );
651 }
652
653 // Test default icon theme.
654 await tester.pumpWidget(buildChip());
655
656 expect(getIconData(tester).color, theme.colorScheme.primary);
657
658 // Test provided icon theme.
659 await tester.pumpWidget(buildChip(iconTheme: const IconThemeData(color: Color(0xff00ff00))));
660
661 expect(getIconData(tester).color, const Color(0xff00ff00));
662 });
663
664 testWidgets('ChoiceChip avatar layout constraints can be customized', (
665 WidgetTester tester,
666 ) async {
667 const double border = 1.0;
668 const double iconSize = 18.0;
669 const double labelPadding = 8.0;
670 const double padding = 8.0;
671 const Size labelSize = Size(100, 100);
672
673 Widget buildChip({BoxConstraints? avatarBoxConstraints}) {
674 return wrapForChip(
675 child: Center(
676 child: ChoiceChip(
677 avatarBoxConstraints: avatarBoxConstraints,
678 avatar: const Icon(Icons.favorite),
679 label: Container(
680 width: labelSize.width,
681 height: labelSize.width,
682 color: const Color(0xFFFF0000),
683 ),
684 selected: false,
685 ),
686 ),
687 );
688 }
689
690 // Test default avatar layout constraints.
691 await tester.pumpWidget(buildChip());
692
693 expect(tester.getSize(find.byType(ChoiceChip)).width, equals(234.0));
694 expect(tester.getSize(find.byType(ChoiceChip)).height, equals(118.0));
695
696 // Calculate the distance between avatar and chip edges.
697 Offset chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
698 final Offset avatarCenter = tester.getCenter(find.byIcon(Icons.favorite));
699 expect(chipTopLeft.dx, avatarCenter.dx - (labelSize.width / 2) - padding - border);
700 expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
701
702 // Calculate the distance between avatar and label.
703 Offset labelTopLeft = tester.getTopLeft(find.byType(Container));
704 expect(labelTopLeft.dx, avatarCenter.dx + (labelSize.width / 2) + labelPadding);
705
706 // Test custom avatar layout constraints.
707 await tester.pumpWidget(buildChip(avatarBoxConstraints: const BoxConstraints.tightForFinite()));
708 await tester.pump();
709
710 expect(tester.getSize(find.byType(ChoiceChip)).width, equals(152.0));
711 expect(tester.getSize(find.byType(ChoiceChip)).height, equals(118.0));
712
713 // Calculate the distance between avatar and chip edges.
714 chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
715 expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
716 expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
717
718 // Calculate the distance between avatar and label.
719 labelTopLeft = tester.getTopLeft(find.byType(Container));
720 expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
721 });
722
723 testWidgets('ChoiceChip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
724 final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
725 enableAnimation: const AnimationStyle(duration: Durations.extralong4),
726 selectAnimation: AnimationStyle.noAnimation,
727 );
728
729 await tester.pumpWidget(
730 wrapForChip(
731 child: Center(
732 child: ChoiceChip(
733 chipAnimationStyle: chipAnimationStyle,
734 selected: true,
735 label: const Text('ChoiceChip'),
736 ),
737 ),
738 ),
739 );
740
741 expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
742 });
743
744 testWidgets('Elevated ChoiceChip.chipAnimationStyle is passed to RawChip', (
745 WidgetTester tester,
746 ) async {
747 final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
748 enableAnimation: const AnimationStyle(duration: Durations.extralong4),
749 selectAnimation: AnimationStyle.noAnimation,
750 );
751
752 await tester.pumpWidget(
753 wrapForChip(
754 child: Center(
755 child: ChoiceChip.elevated(
756 chipAnimationStyle: chipAnimationStyle,
757 selected: true,
758 label: const Text('ChoiceChip'),
759 ),
760 ),
761 ),
762 );
763
764 expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
765 });
766
767 testWidgets('ChoiceChip mouse cursor behavior', (WidgetTester tester) async {
768 const SystemMouseCursor customCursor = SystemMouseCursors.grab;
769
770 await tester.pumpWidget(
771 wrapForChip(
772 child: const Center(
773 child: ChoiceChip(selected: false, mouseCursor: customCursor, label: Text('Chip')),
774 ),
775 ),
776 );
777
778 final TestGesture gesture = await tester.createGesture(
779 kind: PointerDeviceKind.mouse,
780 pointer: 1,
781 );
782 await gesture.addPointer(location: const Offset(10, 10));
783 await tester.pump();
784 expect(
785 RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
786 SystemMouseCursors.basic,
787 );
788
789 final Offset chip = tester.getCenter(find.text('Chip'));
790 await gesture.moveTo(chip);
791 await tester.pump();
792 expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), customCursor);
793 });
794
795 testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (
796 WidgetTester tester,
797 ) async {
798 tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
799 final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
800 addTearDown(focusNode.dispose);
801
802 Widget buildChip({required bool enabled}) {
803 return wrapForChip(
804 child: Center(
805 child: ChoiceChip(
806 mouseCursor: const WidgetStateMouseCursor.fromMap(<WidgetStatesConstraint, MouseCursor>{
807 WidgetState.disabled: SystemMouseCursors.forbidden,
808 WidgetState.focused: SystemMouseCursors.grab,
809 WidgetState.selected: SystemMouseCursors.click,
810 WidgetState.any: SystemMouseCursors.basic,
811 }),
812 focusNode: focusNode,
813 label: const Text('Chip'),
814 onSelected: enabled ? (bool value) {} : null,
815 selected: false,
816 ),
817 ),
818 );
819 }
820
821 // Unfocused case.
822 await tester.pumpWidget(buildChip(enabled: true));
823 final TestGesture gesture1 = await tester.createGesture(
824 kind: PointerDeviceKind.mouse,
825 pointer: 1,
826 );
827 addTearDown(gesture1.removePointer);
828 await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
829 await tester.pump();
830 await gesture1.moveTo(tester.getCenter(find.text('Chip')));
831 expect(
832 RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
833 SystemMouseCursors.basic,
834 );
835
836 // Focused case.
837 focusNode.requestFocus();
838 await tester.pump();
839 expect(
840 RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
841 SystemMouseCursors.grab,
842 );
843
844 // Disabled case.
845 await tester.pumpWidget(buildChip(enabled: false));
846 expect(
847 RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
848 SystemMouseCursors.forbidden,
849 );
850 });
851}
852

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com