| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/material.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; |
| |
| /// Adds the basic requirements for a Chip. |
| Widget wrapForChip({ |
| required Widget child, |
| TextDirection textDirection = TextDirection.ltr, |
| double textScaleFactor = 1.0, |
| Brightness brightness = Brightness.light, |
| bool? useMaterial3, |
| }) { |
| return MaterialApp( |
| theme: ThemeData(brightness: brightness, useMaterial3: useMaterial3), |
| home: Directionality( |
| textDirection: textDirection, |
| child: MediaQuery( |
| data: MediaQueryData(textScaleFactor: textScaleFactor), |
| child: Material(child: child), |
| ), |
| ), |
| ); |
| } |
| |
| RenderBox getMaterialBox(WidgetTester tester, Finder type) { |
| return tester.firstRenderObject<RenderBox>( |
| find.descendant( |
| of: type, |
| matching: find.byType(CustomPaint), |
| ), |
| ); |
| } |
| |
| Material getMaterial(WidgetTester tester) { |
| return tester.widget<Material>( |
| find.descendant( |
| of: find.byType(ActionChip), |
| matching: find.byType(Material), |
| ), |
| ); |
| } |
| |
| DefaultTextStyle getLabelStyle(WidgetTester tester, String labelText) { |
| return tester.widget( |
| find.ancestor( |
| of: find.text(labelText), |
| matching: find.byType(DefaultTextStyle), |
| ).first, |
| ); |
| } |
| |
| void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) { |
| final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material)); |
| // There should be two Material widgets, first Material is from the "_wrapForChip" and |
| // last Material is from the "RawChip". |
| expect(materials.length, 2); |
| // The last Material from `RawChip` should have the clip behavior. |
| expect(materials.last.clipBehavior, clipBehavior); |
| } |
| |
| void main() { |
| testWidgetsWithLeakTracking('ActionChip defaults', (WidgetTester tester) async { |
| final ThemeData theme = ThemeData(useMaterial3: true); |
| const String label = 'action chip'; |
| |
| // Test enabled ActionChip defaults. |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: theme, |
| home: Material( |
| child: Center( |
| child: ActionChip( |
| onPressed: () {}, |
| label: const Text(label), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| // Test default chip size. |
| expect( |
| tester.getSize(find.byType(ActionChip)), |
| within<Size>(distance: 0.01, from: const Size(189.1, 48.0)), |
| ); |
| // Test default label style. |
| expect( |
| getLabelStyle(tester, label).style.color!.value, |
| theme.textTheme.labelLarge!.color!.value, |
| ); |
| |
| Material chipMaterial = getMaterial(tester); |
| expect(chipMaterial.elevation, 0); |
| expect(chipMaterial.shadowColor, Colors.transparent); |
| expect(chipMaterial.surfaceTintColor, theme.colorScheme.surfaceTint); |
| expect( |
| chipMaterial.shape, |
| RoundedRectangleBorder( |
| borderRadius: const BorderRadius.all(Radius.circular(8.0)), |
| side: BorderSide(color: theme.colorScheme.outline), |
| ), |
| ); |
| |
| ShapeDecoration decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration; |
| expect(decoration.color, null); |
| |
| // Test disabled ActionChip defaults. |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: theme, |
| home: const Material( |
| child: ActionChip( |
| label: Text(label), |
| ), |
| ), |
| ), |
| ); |
| await tester.pumpAndSettle(); |
| |
| chipMaterial = getMaterial(tester); |
| expect(chipMaterial.elevation, 0); |
| expect(chipMaterial.shadowColor, Colors.transparent); |
| expect(chipMaterial.surfaceTintColor, theme.colorScheme.surfaceTint); |
| expect( |
| chipMaterial.shape, |
| RoundedRectangleBorder( |
| borderRadius: const BorderRadius.all(Radius.circular(8.0)), |
| side: BorderSide(color: theme.colorScheme.onSurface.withOpacity(0.12)), |
| ), |
| ); |
| |
| decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration; |
| expect(decoration.color, null); |
| }); |
| |
| testWidgetsWithLeakTracking('ActionChip.elevated defaults', (WidgetTester tester) async { |
| final ThemeData theme = ThemeData(useMaterial3: true); |
| const String label = 'action chip'; |
| |
| // Test enabled ActionChip defaults. |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: theme, |
| home: Material( |
| child: Center( |
| child: ActionChip.elevated( |
| onPressed: () {}, |
| label: const Text(label), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| // Test default chip size. |
| expect( |
| tester.getSize(find.byType(ActionChip)), |
| within<Size>(distance: 0.01, from: const Size(189.1, 48.0)), |
| ); |
| // Test default label style. |
| expect( |
| getLabelStyle(tester, label).style.color!.value, |
| theme.textTheme.labelLarge!.color!.value, |
| ); |
| |
| Material chipMaterial = getMaterial(tester); |
| expect(chipMaterial.elevation, 1); |
| expect(chipMaterial.shadowColor, theme.colorScheme.shadow); |
| expect(chipMaterial.surfaceTintColor, theme.colorScheme.surfaceTint); |
| expect( |
| chipMaterial.shape, |
| const RoundedRectangleBorder( |
| borderRadius: BorderRadius.all(Radius.circular(8.0)), |
| side: BorderSide(color: Colors.transparent), |
| ), |
| ); |
| |
| ShapeDecoration decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration; |
| expect(decoration.color, null); |
| |
| // Test disabled ActionChip.elevated defaults. |
| await tester.pumpWidget( |
| MaterialApp( |
| theme: theme, |
| home: const Material( |
| child: ActionChip.elevated( |
| label: Text(label), |
| ), |
| ), |
| ), |
| ); |
| await tester.pumpAndSettle(); |
| |
| chipMaterial = getMaterial(tester); |
| expect(chipMaterial.elevation, 0); |
| expect(chipMaterial.shadowColor, theme.colorScheme.shadow); |
| expect(chipMaterial.surfaceTintColor, theme.colorScheme.surfaceTint); |
| expect( |
| chipMaterial.shape, |
| const RoundedRectangleBorder( |
| borderRadius: BorderRadius.all(Radius.circular(8.0)), |
| side: BorderSide(color: Colors.transparent), |
| ), |
| ); |
| |
| decoration = tester.widget<Ink>(find.byType(Ink)).decoration! as ShapeDecoration; |
| expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12)); |
| }); |
| |
| testWidgetsWithLeakTracking('ActionChip.color resolves material states', (WidgetTester tester) async { |
| const Color disabledColor = Color(0xff00ff00); |
| const Color backgroundColor = Color(0xff0000ff); |
| final MaterialStateProperty<Color?> color = MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return disabledColor; |
| } |
| return backgroundColor; |
| }); |
| Widget buildApp({ required bool enabled, required bool selected }) { |
| return wrapForChip( |
| useMaterial3: true, |
| child: Column( |
| children: <Widget>[ |
| ActionChip( |
| onPressed: enabled ? () { } : null, |
| color: color, |
| label: const Text('ActionChip'), |
| ), |
| ActionChip.elevated( |
| onPressed: enabled ? () { } : null, |
| color: color, |
| label: const Text('ActionChip.elevated'), |
| ), |
| ], |
| ), |
| ); |
| } |
| |
| // Test enabled state. |
| await tester.pumpWidget(buildApp(enabled: true, selected: false)); |
| |
| // Enabled ActionChip should have the provided backgroundColor. |
| expect( |
| getMaterialBox(tester, find.byType(RawChip).first), |
| paints..rrect(color: backgroundColor), |
| ); |
| // Enabled elevated ActionChip should have the provided backgroundColor. |
| expect( |
| getMaterialBox(tester, find.byType(RawChip).last), |
| paints..rrect(color: backgroundColor), |
| ); |
| |
| // Test disabled state. |
| await tester.pumpWidget(buildApp(enabled: false, selected: false)); |
| await tester.pumpAndSettle(); |
| |
| // Disabled ActionChip should have the provided disabledColor. |
| expect( |
| getMaterialBox(tester, find.byType(RawChip).first), |
| paints..rrect(color: disabledColor), |
| ); |
| // Disabled elevated ActionChip should have the provided disabledColor. |
| expect( |
| getMaterialBox(tester, find.byType(RawChip).last), |
| paints..rrect(color: disabledColor), |
| ); |
| }); |
| |
| testWidgetsWithLeakTracking('ActionChip uses provided state color properties', (WidgetTester tester) async { |
| const Color disabledColor = Color(0xff00ff00); |
| const Color backgroundColor = Color(0xff0000ff); |
| Widget buildApp({ required bool enabled, required bool selected }) { |
| return wrapForChip( |
| useMaterial3: true, |
| child: Column( |
| children: <Widget>[ |
| ActionChip( |
| onPressed: enabled ? () { } : null, |
| disabledColor: disabledColor, |
| backgroundColor: backgroundColor, |
| label: const Text('ActionChip'), |
| ), |
| ActionChip.elevated( |
| onPressed: enabled ? () { } : null, |
| disabledColor: disabledColor, |
| backgroundColor: backgroundColor, |
| label: const Text('ActionChip.elevated'), |
| ), |
| ], |
| ), |
| ); |
| } |
| |
| // Test enabled state. |
| await tester.pumpWidget(buildApp(enabled: true, selected: false)); |
| |
| // Enabled ActionChip should have the provided backgroundColor. |
| expect( |
| getMaterialBox(tester, find.byType(RawChip).first), |
| paints..rrect(color: backgroundColor), |
| ); |
| // Enabled elevated ActionChip should have the provided backgroundColor. |
| expect( |
| getMaterialBox(tester, find.byType(RawChip).last), |
| paints..rrect(color: backgroundColor), |
| ); |
| |
| // Test disabled state. |
| await tester.pumpWidget(buildApp(enabled: false, selected: false)); |
| await tester.pumpAndSettle(); |
| |
| // Disabled ActionChip should have the provided disabledColor. |
| expect( |
| getMaterialBox(tester, find.byType(RawChip).first), |
| paints..rrect(color: disabledColor), |
| ); |
| // Disabled elevated ActionChip should have the provided disabledColor. |
| expect( |
| getMaterialBox(tester, find.byType(RawChip).last), |
| paints..rrect(color: disabledColor), |
| ); |
| }); |
| |
| testWidgetsWithLeakTracking('ActionChip can be tapped', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| MaterialApp( |
| home: Material( |
| child: ActionChip( |
| onPressed: () { }, |
| label: const Text('action chip'), |
| ), |
| ), |
| ), |
| ); |
| |
| await tester.tap(find.byType(ActionChip)); |
| expect(tester.takeException(), null); |
| }); |
| |
| testWidgetsWithLeakTracking('ActionChip clipBehavior properly passes through to the Material', (WidgetTester tester) async { |
| const Text label = Text('label'); |
| await tester.pumpWidget(wrapForChip(child: ActionChip(label: label, onPressed: () { }))); |
| checkChipMaterialClipBehavior(tester, Clip.none); |
| |
| await tester.pumpWidget(wrapForChip(child: ActionChip(label: label, clipBehavior: Clip.antiAlias, onPressed: () { }))); |
| checkChipMaterialClipBehavior(tester, Clip.antiAlias); |
| }); |
| } |