bottom_sheet_theme_test.dart 15.2 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7
// 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/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
8
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
9

10 11 12 13 14 15
void main() {
  test('BottomSheetThemeData copyWith, ==, hashCode basics', () {
    expect(const BottomSheetThemeData(), const BottomSheetThemeData().copyWith());
    expect(const BottomSheetThemeData().hashCode, const BottomSheetThemeData().copyWith().hashCode);
  });

16 17 18 19 20 21 22 23 24 25 26 27
  test('BottomSheetThemeData lerp special cases', () {
    expect(BottomSheetThemeData.lerp(null, null, 0), null);
    const BottomSheetThemeData data = BottomSheetThemeData();
    expect(identical(BottomSheetThemeData.lerp(data, data, 0.5), data), true);
  });

  test('BottomSheetThemeData lerp special cases', () {
    expect(BottomSheetThemeData.lerp(null, null, 0), null);
    const BottomSheetThemeData data = BottomSheetThemeData();
    expect(identical(BottomSheetThemeData.lerp(data, data, 0.5), data), true);
  });

28 29 30
  test('BottomSheetThemeData null fields by default', () {
    const BottomSheetThemeData bottomSheetTheme = BottomSheetThemeData();
    expect(bottomSheetTheme.backgroundColor, null);
31
    expect(bottomSheetTheme.shadowColor, null);
32 33
    expect(bottomSheetTheme.elevation, null);
    expect(bottomSheetTheme.shape, null);
34
    expect(bottomSheetTheme.clipBehavior, null);
35
    expect(bottomSheetTheme.constraints, null);
36 37
    expect(bottomSheetTheme.dragHandleColor, null);
    expect(bottomSheetTheme.dragHandleSize, null);
38 39
  });

40
  testWidgetsWithLeakTracking('Default BottomSheetThemeData debugFillProperties', (WidgetTester tester) async {
41 42 43 44 45 46 47 48 49 50 51
    final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
    const BottomSheetThemeData().debugFillProperties(builder);

    final List<String> description = builder.properties
        .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
        .map((DiagnosticsNode node) => node.toString())
        .toList();

    expect(description, <String>[]);
  });

52
  testWidgetsWithLeakTracking('BottomSheetThemeData implements debugFillProperties', (WidgetTester tester) async {
53
    final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
54 55
    const BottomSheetThemeData(
      backgroundColor: Color(0xFFFFFFFF),
56
      elevation: 2.0,
57
      shadowColor: Color(0xFF00FFFF),
58
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))),
59
      clipBehavior: Clip.antiAlias,
60
      constraints: BoxConstraints(minWidth: 200, maxWidth: 640),
61 62
      dragHandleColor: Color(0xFFFFFFFF),
      dragHandleSize: Size(20, 20)
63 64 65 66 67 68 69 70 71 72
    ).debugFillProperties(builder);

    final List<String> description = builder.properties
        .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
        .map((DiagnosticsNode node) => node.toString())
        .toList();

    expect(description, <String>[
      'backgroundColor: Color(0xffffffff)',
      'elevation: 2.0',
73
      'shadowColor: Color(0xff00ffff)',
74
      'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))',
75 76
      'dragHandleColor: Color(0xffffffff)',
      'dragHandleSize: Size(20.0, 20.0)',
77
      'clipBehavior: Clip.antiAlias',
78
      'constraints: BoxConstraints(200.0<=w<=640.0, 0.0<=h<=Infinity)',
79 80 81
    ]);
  });

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
  testWidgetsWithLeakTracking('Material3 - Passing no BottomSheetThemeData returns defaults', (WidgetTester tester) async {
    await tester.pumpWidget(MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: Scaffold(
        body: BottomSheet(
          onClosing: () {},
          builder: (BuildContext context) {
            return Container();
          },
        ),
      ),
    ));

    final Material material = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
      ),
    );

    final ThemeData theme = Theme.of(tester.element(find.byType(Scaffold)));
    expect(material.color, theme.colorScheme.surface);
    expect(material.elevation, 1.0);
    expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(28.0))));
    expect(material.clipBehavior, Clip.none);
  });

  testWidgetsWithLeakTracking('Material2 - Passing no BottomSheetThemeData returns defaults', (WidgetTester tester) async {
110
    await tester.pumpWidget(MaterialApp(
111
      theme: ThemeData(useMaterial3: false),
112 113 114 115 116 117 118 119 120 121 122 123 124 125
      home: Scaffold(
        body: BottomSheet(
          onClosing: () {},
          builder: (BuildContext context) {
            return Container();
          },
        ),
      ),
    ));

    final Material material = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
126
      ),
127 128 129 130
    );
    expect(material.color, null);
    expect(material.elevation, 0.0);
    expect(material.shape, null);
131
    expect(material.clipBehavior, Clip.none);
132 133
  });

134
  testWidgetsWithLeakTracking('BottomSheet uses values from BottomSheetThemeData', (WidgetTester tester) async {
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    final BottomSheetThemeData bottomSheetTheme = _bottomSheetTheme();

    await tester.pumpWidget(MaterialApp(
      theme: ThemeData(bottomSheetTheme: bottomSheetTheme),
      home: Scaffold(
        body: BottomSheet(
          onClosing: () {},
          builder: (BuildContext context) {
            return Container();
          },
        ),
      ),
    ));

    final Material material = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
153
      ),
154 155 156 157
    );
    expect(material.color, bottomSheetTheme.backgroundColor);
    expect(material.elevation, bottomSheetTheme.elevation);
    expect(material.shape, bottomSheetTheme.shape);
158
    expect(material.clipBehavior, bottomSheetTheme.clipBehavior);
159 160
  });

161
  testWidgetsWithLeakTracking('BottomSheet widget properties take priority over theme', (WidgetTester tester) async {
162
    const Color backgroundColor = Colors.purple;
163
    const Color shadowColor = Colors.blue;
164 165 166 167
    const double elevation = 7.0;
    const ShapeBorder shape = RoundedRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(9.0)),
    );
168
    const Clip clipBehavior = Clip.hardEdge;
169 170 171 172 173 174

    await tester.pumpWidget(MaterialApp(
      theme: ThemeData(bottomSheetTheme: _bottomSheetTheme()),
      home: Scaffold(
        body: BottomSheet(
          backgroundColor: backgroundColor,
175
          shadowColor: shadowColor,
176 177
          elevation: elevation,
          shape: shape,
178
          clipBehavior: Clip.hardEdge,
179 180 181 182 183 184 185 186 187 188 189 190
          onClosing: () {},
          builder: (BuildContext context) {
            return Container();
          },
        ),
      ),
    ));

    final Material material = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
191
      ),
192 193
    );
    expect(material.color, backgroundColor);
194
    expect(material.shadowColor, shadowColor);
195 196
    expect(material.elevation, elevation);
    expect(material.shape, shape);
197
    expect(material.clipBehavior, clipBehavior);
198
  });
199

200
  testWidgetsWithLeakTracking('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async {
201 202
    const double modalElevation = 5.0;
    const double persistentElevation = 7.0;
203
    const Color modalBackgroundColor = Colors.yellow;
204
    const Color modalBarrierColor = Colors.blue;
205
    const Color persistentBackgroundColor = Colors.red;
206 207 208
    const BottomSheetThemeData bottomSheetTheme = BottomSheetThemeData(
      elevation: persistentElevation,
      modalElevation: modalElevation,
209 210
      backgroundColor: persistentBackgroundColor,
      modalBackgroundColor: modalBackgroundColor,
211
      modalBarrierColor:modalBarrierColor,
212 213 214 215 216 217 218 219 220 221 222 223 224
    );

    await tester.pumpWidget(bottomSheetWithElevations(bottomSheetTheme));
    await tester.tap(find.text('Show Modal'));
    await tester.pumpAndSettle();

    final Material material = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
      ),
    );
    expect(material.elevation, modalElevation);
225
    expect(material.color, modalBackgroundColor);
226 227 228

    final ModalBarrier modalBarrier = tester.widget(find.byType(ModalBarrier).last);
    expect(modalBarrier.color, modalBarrierColor);
229 230
  });

231
  testWidgetsWithLeakTracking('General bottom sheet parameters take priority over modal bottom sheet-specific parameters for persistent bottom sheets', (WidgetTester tester) async {
232 233
    const double modalElevation = 5.0;
    const double persistentElevation = 7.0;
234 235
    const Color modalBackgroundColor = Colors.yellow;
    const Color persistentBackgroundColor = Colors.red;
236 237 238
    const BottomSheetThemeData bottomSheetTheme = BottomSheetThemeData(
      elevation: persistentElevation,
      modalElevation: modalElevation,
239 240
      backgroundColor: persistentBackgroundColor,
      modalBackgroundColor: modalBackgroundColor,
241 242 243 244 245 246 247 248 249 250 251 252 253
    );

    await tester.pumpWidget(bottomSheetWithElevations(bottomSheetTheme));
    await tester.tap(find.text('Show Persistent'));
    await tester.pumpAndSettle();

    final Material material = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
      ),
    );
    expect(material.elevation, persistentElevation);
254
    expect(material.color, persistentBackgroundColor);
255 256
  });

257
  testWidgetsWithLeakTracking("Material3 - Modal bottom sheet-specific parameters don't apply to persistent bottom sheets", (WidgetTester tester) async {
258
    const double modalElevation = 5.0;
259
    const Color modalBackgroundColor = Colors.yellow;
260 261
    const BottomSheetThemeData bottomSheetTheme = BottomSheetThemeData(
      modalElevation: modalElevation,
262
      modalBackgroundColor: modalBackgroundColor,
263 264 265 266 267 268
    );

    await tester.pumpWidget(bottomSheetWithElevations(bottomSheetTheme));
    await tester.tap(find.text('Show Persistent'));
    await tester.pumpAndSettle();

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    final Material material = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
      ),
    );
    expect(material.elevation, 1.0);
    final ThemeData theme = Theme.of(tester.element(find.byType(Scaffold)));
    expect(material.color, theme.colorScheme.surface);
  });

  testWidgetsWithLeakTracking("Material2 - Modal bottom sheet-specific parameters don't apply to persistent bottom sheets", (WidgetTester tester) async {
    const double modalElevation = 5.0;
    const Color modalBackgroundColor = Colors.yellow;
    const BottomSheetThemeData bottomSheetTheme = BottomSheetThemeData(
      modalElevation: modalElevation,
      modalBackgroundColor: modalBackgroundColor,
    );

    await tester.pumpWidget(bottomSheetWithElevations(bottomSheetTheme, useMaterial3: false));
    await tester.tap(find.text('Show Persistent'));
    await tester.pumpAndSettle();

292 293 294 295 296 297 298
    final Material material = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
      ),
    );
    expect(material.elevation, 0);
299
    expect(material.color, null);
300
  });
301

302
  testWidgetsWithLeakTracking('Modal bottom sheets respond to theme changes', (WidgetTester tester) async {
303 304 305 306
    const double lightElevation = 5.0;
    const double darkElevation = 3.0;
    const Color lightBackgroundColor = Colors.green;
    const Color darkBackgroundColor = Colors.grey;
307 308
    const Color lightShadowColor = Colors.blue;
    const Color darkShadowColor = Colors.purple;
309 310

    await tester.pumpWidget(MaterialApp(
311
      theme: ThemeData.light().copyWith(
312 313 314
        bottomSheetTheme: const BottomSheetThemeData(
          elevation: lightElevation,
          backgroundColor: lightBackgroundColor,
315
          shadowColor: lightShadowColor,
316 317
        ),
      ),
318
      darkTheme: ThemeData.dark().copyWith(
319 320 321
        bottomSheetTheme: const BottomSheetThemeData(
          elevation: darkElevation,
          backgroundColor: darkBackgroundColor,
322
          shadowColor: darkShadowColor,
323 324 325 326 327 328 329 330 331 332 333 334 335
        ),
      ),
      home: Scaffold(
        body: Builder(
          builder: (BuildContext context) {
            return Column(
              children: <Widget>[
                RawMaterialButton(
                  child: const Text('Show Modal'),
                  onPressed: () {
                    showModalBottomSheet<void>(
                      context: context,
                      builder: (BuildContext context) {
336
                        return const Text('This is a modal bottom sheet.');
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
                      },
                    );
                  },
                ),
              ],
            );
          },
        ),
      ),
    ));
    await tester.tap(find.text('Show Modal'));
    await tester.pumpAndSettle();

    final Material lightMaterial = tester.widget<Material>(
      find.descendant(
        of: find.byType(BottomSheet),
        matching: find.byType(Material),
      ),
    );
    expect(lightMaterial.elevation, lightElevation);
    expect(lightMaterial.color, lightBackgroundColor);
358
    expect(lightMaterial.shadowColor, lightShadowColor);
359 360

    // Simulate the user changing to dark theme
361
    tester.binding.platformDispatcher.platformBrightnessTestValue = Brightness.dark;
362 363 364 365 366 367 368 369 370 371
    await tester.pumpAndSettle();

    final Material darkMaterial = tester.widget<Material>(
    find.descendant(
      of: find.byType(BottomSheet),
        matching: find.byType(Material),
      ),
    );
    expect(darkMaterial.elevation, darkElevation);
    expect(darkMaterial.color, darkBackgroundColor);
372
    expect(darkMaterial.shadowColor, darkShadowColor);
373
  });
374 375
}

376
Widget bottomSheetWithElevations(BottomSheetThemeData bottomSheetTheme, {bool useMaterial3 = true}) {
377
  return MaterialApp(
378
    theme: ThemeData(bottomSheetTheme: bottomSheetTheme, useMaterial3: useMaterial3),
379 380 381 382 383 384 385 386 387 388 389
    home: Scaffold(
      body: Builder(
        builder: (BuildContext context) {
          return Column(
              children: <Widget>[
                RawMaterialButton(
                  child: const Text('Show Modal'),
                  onPressed: () {
                    showModalBottomSheet<void>(
                      context: context,
                      builder: (BuildContext _) {
390 391
                        return const Text(
                          'This is a modal bottom sheet.',
392 393 394 395 396 397 398 399
                        );
                      },
                    );
                  },
                ),
                RawMaterialButton(
                  child: const Text('Show Persistent'),
                  onPressed: () {
400
                    showBottomSheet(
401 402
                      context: context,
                      builder: (BuildContext _) {
403 404
                        return const Text(
                          'This is a persistent bottom sheet.',
405 406 407 408 409 410 411 412 413 414 415
                        );
                      },
                    );
                  },
                ),
              ],
          );
        },
      ),
    ),
  );
416 417 418
}

BottomSheetThemeData _bottomSheetTheme() {
419
  return const BottomSheetThemeData(
420 421
    backgroundColor: Colors.orange,
    elevation: 12.0,
422
    shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12))),
423
    clipBehavior: Clip.antiAlias,
424 425
  );
}