// 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. // This file is run as part of a reduced test set in CI on Mac and Windows // machines. @Tags(<String>['reduced-test-set']) library; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; MaterialApp _appWithDialog(WidgetTester tester, Widget dialog, { ThemeData? theme }) { return MaterialApp( theme: theme, home: Material( child: Builder( builder: (BuildContext context) { return Center( child: ElevatedButton( child: const Text('X'), onPressed: () { showDialog<void>( context: context, builder: (BuildContext context) { return RepaintBoundary(key: _painterKey, child: dialog); }, ); }, ), ); }, ), ), ); } final Key _painterKey = UniqueKey(); Material _getMaterialFromDialog(WidgetTester tester) { return tester.widget<Material>(find.descendant(of: find.byType(AlertDialog), matching: find.byType(Material))); } RenderParagraph _getTextRenderObject(WidgetTester tester, String text) { return tester.element<StatelessElement>(find.text(text)).renderObject! as RenderParagraph; } void main() { test('DialogTheme lerp special cases', () { expect(DialogTheme.lerp(null, null, 0), const DialogTheme()); const DialogTheme theme = DialogTheme(); expect(identical(DialogTheme.lerp(theme, theme, 0.5), theme), true); }); testWidgets('Dialog Theme implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DialogTheme( backgroundColor: Color(0xff123456), elevation: 8.0, shadowColor: Color(0xff000001), surfaceTintColor: Color(0xff000002), alignment: Alignment.bottomLeft, iconColor: Color(0xff654321), titleTextStyle: TextStyle(color: Color(0xffffffff)), contentTextStyle: TextStyle(color: Color(0xff000000)), actionsPadding: EdgeInsets.all(8.0), ).debugFillProperties(builder); final List<String> description = builder.properties .where((DiagnosticsNode n) => !n.isFiltered(DiagnosticLevel.info)) .map((DiagnosticsNode n) => n.toString()).toList(); expect(description, <String>[ 'backgroundColor: Color(0xff123456)', 'elevation: 8.0', 'shadowColor: Color(0xff000001)', 'surfaceTintColor: Color(0xff000002)', 'alignment: Alignment.bottomLeft', 'iconColor: Color(0xff654321)', 'titleTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))', 'contentTextStyle: TextStyle(inherit: true, color: Color(0xff000000))', 'actionsPadding: EdgeInsets.all(8.0)', ]); }); testWidgets('Dialog background color', (WidgetTester tester) async { const Color customColor = Colors.pink; const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: <Widget>[ ], ); final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(backgroundColor: customColor)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final Material materialWidget = _getMaterialFromDialog(tester); expect(materialWidget.color, customColor); }); testWidgets('Custom dialog elevation', (WidgetTester tester) async { const double customElevation = 12.0; const Color shadowColor = Color(0xFF000001); const Color surfaceTintColor = Color(0xFF000002); const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: <Widget>[ ], ); final ThemeData theme = ThemeData( dialogTheme: const DialogTheme( elevation: customElevation, shadowColor: shadowColor, surfaceTintColor: surfaceTintColor, ), ); await tester.pumpWidget( _appWithDialog(tester, dialog, theme: theme), ); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final Material materialWidget = _getMaterialFromDialog(tester); expect(materialWidget.elevation, customElevation); expect(materialWidget.shadowColor, shadowColor); expect(materialWidget.surfaceTintColor, surfaceTintColor); }); testWidgets('Custom dialog shape', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: <Widget>[ ], ); final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(shape: customBorder)); await tester.pumpWidget( _appWithDialog(tester, dialog, theme: theme), ); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final Material materialWidget = _getMaterialFromDialog(tester); expect(materialWidget.shape, customBorder); }); testWidgets('Custom dialog alignment', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: <Widget>[ ], ); final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(alignment: Alignment.bottomLeft)); await tester.pumpWidget( _appWithDialog(tester, dialog, theme: theme), ); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final Offset bottomLeft = tester.getBottomLeft( find.descendant(of: find.byType(Dialog), matching: find.byType(Material)), ); expect(bottomLeft.dx, 40.0); expect(bottomLeft.dy, 576.0); }); testWidgets('Dialog alignment takes priority over theme', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: <Widget>[ ], alignment: Alignment.topRight, ); final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(alignment: Alignment.bottomLeft)); await tester.pumpWidget( _appWithDialog(tester, dialog, theme: theme), ); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final Offset bottomLeft = tester.getBottomLeft( find.descendant(of: find.byType(Dialog), matching: find.byType(Material)), ); expect(bottomLeft.dx, 480.0); expect(bottomLeft.dy, 104.0); }); testWidgets('Custom dialog shape matches golden', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: <Widget>[ ], ); final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(shape: customBorder)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); await expectLater( find.byKey(_painterKey), matchesGoldenFile('dialog_theme.dialog_with_custom_border.png'), ); }); testWidgets('Custom Icon Color - Constructor Param - highest preference', (WidgetTester tester) async { const Color iconColor = Colors.pink, dialogThemeColor = Colors.green, iconThemeColor = Colors.yellow; final ThemeData theme = ThemeData( iconTheme: const IconThemeData(color: iconThemeColor), dialogTheme: const DialogTheme(iconColor: dialogThemeColor), ); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), iconColor: iconColor, actions: <Widget>[ ], ); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); expect(text.text.style!.color, iconColor); }); testWidgets('Custom Icon Color - Dialog Theme - preference over Theme', (WidgetTester tester) async { const Color dialogThemeColor = Colors.green, iconThemeColor = Colors.yellow; final ThemeData theme = ThemeData( iconTheme: const IconThemeData(color: iconThemeColor), dialogTheme: const DialogTheme(iconColor: dialogThemeColor), ); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: <Widget>[ ], ); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); expect(text.text.style!.color, dialogThemeColor); }); testWidgets('Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { const Color iconThemeColor = Colors.yellow; final ThemeData theme = ThemeData(iconTheme: const IconThemeData(color: iconThemeColor)); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: <Widget>[ ], ); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); expect(text.text.style!.color, iconThemeColor); }); testWidgets('Custom Icon Color - Theme - lowest preference for M3', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: <Widget>[ ], ); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); expect(text.text.style!.color, theme.colorScheme.secondary); }); testWidgets('Custom Title Text Style - Constructor Param', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( title: Text(titleText), titleTextStyle: titleTextStyle, actions: <Widget>[ ], ); await tester.pumpWidget(_appWithDialog(tester, dialog)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph title = _getTextRenderObject(tester, titleText); expect(title.text.style, titleTextStyle); }); testWidgets('Custom Title Text Style - Dialog Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( title: Text(titleText), actions: <Widget>[ ], ); final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(titleTextStyle: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph title = _getTextRenderObject(tester, titleText); expect(title.text.style, titleTextStyle); }); testWidgets('Custom Title Text Style - Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( title: Text(titleText), actions: <Widget>[ ], ); final ThemeData theme = ThemeData(textTheme: const TextTheme(titleLarge: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph title = _getTextRenderObject(tester, titleText); expect(title.text.style!.color, titleTextStyle.color); }); testWidgets('Simple Dialog - Custom Title Text Style - Constructor Param', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const SimpleDialog dialog = SimpleDialog( title: Text(titleText), titleTextStyle: titleTextStyle, ); await tester.pumpWidget(_appWithDialog(tester, dialog)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph title = _getTextRenderObject(tester, titleText); expect(title.text.style, titleTextStyle); }); testWidgets('Simple Dialog - Custom Title Text Style - Dialog Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const SimpleDialog dialog = SimpleDialog( title: Text(titleText), ); final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(titleTextStyle: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph title = _getTextRenderObject(tester, titleText); expect(title.text.style, titleTextStyle); }); testWidgets('Simple Dialog - Custom Title Text Style - Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const SimpleDialog dialog = SimpleDialog( title: Text(titleText), ); final ThemeData theme = ThemeData(textTheme: const TextTheme(titleLarge: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph title = _getTextRenderObject(tester, titleText); expect(title.text.style!.color, titleTextStyle.color); }); testWidgets('Custom Content Text Style - Constructor Param', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( content: Text(contentText), contentTextStyle: contentTextStyle, actions: <Widget>[ ], ); await tester.pumpWidget(_appWithDialog(tester, dialog)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph content = _getTextRenderObject(tester, contentText); expect(content.text.style, contentTextStyle); }); testWidgets('Custom Content Text Style - Dialog Theme', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( content: Text(contentText), actions: <Widget>[ ], ); final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(contentTextStyle: contentTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph content = _getTextRenderObject(tester, contentText); expect(content.text.style, contentTextStyle); }); testWidgets('Custom Content Text Style - Theme', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( content: Text(contentText), actions: <Widget>[ ], ); final ThemeData theme = ThemeData(textTheme: const TextTheme(titleMedium: contentTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(); final RenderParagraph content = _getTextRenderObject(tester, contentText); expect(content.text.style!.color, contentTextStyle.color); }); }