circle_avatar_test.dart 12.6 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7
// This file is run as part of a reduced test set in CI on Mac and Windows
// machines.
@Tags(<String>['reduced-test-set'])
8 9
library;

10 11
import 'dart:typed_data';

12
import 'package:flutter/material.dart';
13
import 'package:flutter/rendering.dart';
14
import 'package:flutter_test/flutter_test.dart';
15
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
16
import '../image_data.dart';
17
import '../painting/mocks_for_image_cache.dart';
18

19
void main() {
20
  testWidgetsWithLeakTracking('CircleAvatar with dark background color', (WidgetTester tester) async {
21
    final Color backgroundColor = Colors.blue.shade900;
22
    await tester.pumpWidget(
Ian Hickson's avatar
Ian Hickson committed
23
      wrap(
24
        child: CircleAvatar(
25
          backgroundColor: backgroundColor,
26
          radius: 50.0,
27
          child: const Text('Z'),
28 29
        ),
      ),
30 31
    );

32
    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
33
    expect(box.size, equals(const Size(100.0, 100.0)));
34
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
35
    final BoxDecoration decoration = child.decoration as BoxDecoration;
36
    expect(decoration.color, equals(backgroundColor));
37

38
    final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
39
    expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorLight));
40 41
  });

42
  testWidgetsWithLeakTracking('CircleAvatar with light background color', (WidgetTester tester) async {
43 44 45
    final Color backgroundColor = Colors.blue.shade100;
    await tester.pumpWidget(
      wrap(
46
        child: CircleAvatar(
47 48 49 50 51 52 53 54
          backgroundColor: backgroundColor,
          radius: 50.0,
          child: const Text('Z'),
        ),
      ),
    );

    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
55
    expect(box.size, equals(const Size(100.0, 100.0)));
56
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
57
    final BoxDecoration decoration = child.decoration as BoxDecoration;
58 59 60
    expect(decoration.color, equals(backgroundColor));

    final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
61
    expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorDark));
62 63
  });

64
  testWidgetsWithLeakTracking('CircleAvatar with image background', (WidgetTester tester) async {
65 66
    await tester.pumpWidget(
      wrap(
67 68
        child: CircleAvatar(
          backgroundImage: MemoryImage(Uint8List.fromList(kTransparentImage)),
69 70 71 72 73 74 75
          radius: 50.0,
        ),
      ),
    );

    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
    expect(box.size, equals(const Size(100.0, 100.0)));
76
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
77
    final BoxDecoration decoration = child.decoration as BoxDecoration;
78
    expect(decoration.image!.fit, equals(BoxFit.cover));
79 80
  });

81
  testWidgetsWithLeakTracking('CircleAvatar with image foreground', (WidgetTester tester) async {
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    await tester.pumpWidget(
      wrap(
        child: CircleAvatar(
          foregroundImage: MemoryImage(Uint8List.fromList(kBlueRectPng)),
          radius: 50.0,
        ),
      ),
    );

    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
    expect(box.size, equals(const Size(100.0, 100.0)));
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
    final BoxDecoration decoration = child.decoration as BoxDecoration;
    expect(decoration.image!.fit, equals(BoxFit.cover));
  });

98
  testWidgetsWithLeakTracking('CircleAvatar backgroundImage is used as a fallback for foregroundImage', (WidgetTester tester) async {
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    final ErrorImageProvider errorImage = ErrorImageProvider();
    bool caughtForegroundImageError = false;
    await tester.pumpWidget(
      wrap(
        child: RepaintBoundary(
          child: CircleAvatar(
          foregroundImage: errorImage,
          backgroundImage: MemoryImage(Uint8List.fromList(kBlueRectPng)),
          radius: 50.0,
          onForegroundImageError: (_,__) => caughtForegroundImageError = true,
          ),
        ),
      ),
    );

    expect(caughtForegroundImageError, true);
    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
    expect(box.size, equals(const Size(100.0, 100.0)));
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
    final BoxDecoration decoration = child.decoration as BoxDecoration;
    expect(decoration.image!.fit, equals(BoxFit.cover));
    await expectLater(
      find.byType(CircleAvatar),
      matchesGoldenFile('circle_avatar.fallback.png'),
    );
  });

126
  testWidgetsWithLeakTracking('CircleAvatar with foreground color', (WidgetTester tester) async {
127 128
    final Color foregroundColor = Colors.red.shade100;
    await tester.pumpWidget(
Ian Hickson's avatar
Ian Hickson committed
129
      wrap(
130
        child: CircleAvatar(
131
          foregroundColor: foregroundColor,
132
          child: const Text('Z'),
133 134 135 136
        ),
      ),
    );

137
    final ThemeData fallback = ThemeData.fallback();
138 139

    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
140
    expect(box.size, equals(const Size(40.0, 40.0)));
141
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
142
    final BoxDecoration decoration = child.decoration as BoxDecoration;
143
    expect(decoration.color, equals(fallback.primaryColorDark));
144 145

    final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
146
    expect(paragraph.text.style!.color, equals(foregroundColor));
147 148
  });

149
  testWidgetsWithLeakTracking('CircleAvatar default colors', (WidgetTester tester) async {
150
    final ThemeData theme = ThemeData(useMaterial3: true);
151 152
    await tester.pumpWidget(
      wrap(
153
        child: Theme(
154 155
          data: theme,
          child: const CircleAvatar(
156
            child: Text('Z'),
157 158 159 160 161 162
          ),
        ),
      ),
    );

    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
163
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
164
    final BoxDecoration decoration = child.decoration as BoxDecoration;
165
    expect(decoration.color, equals(theme.colorScheme.primaryContainer));
166 167

    final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
168
    expect(paragraph.text.style!.color, equals(theme.colorScheme.onPrimaryContainer));
169
  });
170

171
  testWidgetsWithLeakTracking('CircleAvatar text does not expand with textScaleFactor', (WidgetTester tester) async {
172 173 174
    final Color foregroundColor = Colors.red.shade100;
    await tester.pumpWidget(
      wrap(
175
        child: CircleAvatar(
176 177 178 179 180 181
          foregroundColor: foregroundColor,
          child: const Text('Z'),
        ),
      ),
    );

182
    expect(tester.getSize(find.text('Z')), equals(const Size(16.0, 16.0)));
183 184 185

    await tester.pumpWidget(
      wrap(
186
        child: MediaQuery(
187 188
          data: const MediaQueryData(
            textScaleFactor: 2.0,
189
            size: Size(111.0, 111.0),
190
            devicePixelRatio: 1.1,
191 192
            padding: EdgeInsets.all(11.0),
          ),
193 194
          child: CircleAvatar(
            child: Builder(
195
              builder: (BuildContext context) {
196
                final MediaQueryData data = MediaQuery.of(context);
197 198 199 200 201 202 203 204 205

                // These should not change.
                expect(data.size, equals(const Size(111.0, 111.0)));
                expect(data.devicePixelRatio, equals(1.1));
                expect(data.padding, equals(const EdgeInsets.all(11.0)));

                // This should be overridden to 1.0.
                expect(data.textScaleFactor, equals(1.0));
                return const Text('Z');
206
              },
207
            ),
208 209 210 211
          ),
        ),
      ),
    );
212
    expect(tester.getSize(find.text('Z')), equals(const Size(16.0, 16.0)));
213
  });
214

215
  testWidgetsWithLeakTracking('CircleAvatar respects minRadius', (WidgetTester tester) async {
216 217 218
    final Color backgroundColor = Colors.blue.shade900;
    await tester.pumpWidget(
      wrap(
219 220
        child: UnconstrainedBox(
          child: CircleAvatar(
221 222 223 224 225 226 227 228 229
            backgroundColor: backgroundColor,
            minRadius: 50.0,
            child: const Text('Z'),
          ),
        ),
      ),
    );

    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
230
    expect(box.size, equals(const Size(100.0, 100.0)));
231
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
232
    final BoxDecoration decoration = child.decoration as BoxDecoration;
233 234 235
    expect(decoration.color, equals(backgroundColor));

    final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
236
    expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorLight));
237 238
  });

239
  testWidgetsWithLeakTracking('CircleAvatar respects maxRadius', (WidgetTester tester) async {
240 241 242
    final Color backgroundColor = Colors.blue.shade900;
    await tester.pumpWidget(
      wrap(
243
        child: CircleAvatar(
244 245 246 247 248 249 250 251
          backgroundColor: backgroundColor,
          maxRadius: 50.0,
          child: const Text('Z'),
        ),
      ),
    );

    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
252
    expect(box.size, equals(const Size(100.0, 100.0)));
253
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
254
    final BoxDecoration decoration = child.decoration as BoxDecoration;
255 256 257
    expect(decoration.color, equals(backgroundColor));

    final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
258
    expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorLight));
259 260
  });

261
  testWidgetsWithLeakTracking('CircleAvatar respects setting both minRadius and maxRadius', (WidgetTester tester) async {
262 263 264
    final Color backgroundColor = Colors.blue.shade900;
    await tester.pumpWidget(
      wrap(
265
        child: CircleAvatar(
266 267 268 269 270 271 272 273 274
          backgroundColor: backgroundColor,
          maxRadius: 50.0,
          minRadius: 50.0,
          child: const Text('Z'),
        ),
      ),
    );

    final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
275
    expect(box.size, equals(const Size(100.0, 100.0)));
276
    final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
277
    final BoxDecoration decoration = child.decoration as BoxDecoration;
278 279 280
    expect(decoration.color, equals(backgroundColor));

    final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
281
    expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorLight));
282
  });
283 284

  group('Material 2', () {
285 286 287
    // These tests are only relevant for Material 2. Once Material 2
    // support is deprecated and the APIs are removed, these tests
    // can be deleted.
288

289
    testWidgetsWithLeakTracking('CircleAvatar default colors with light theme', (WidgetTester tester) async {
290
      final ThemeData theme = ThemeData(useMaterial3: false, primaryColor: Colors.grey.shade100);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
      await tester.pumpWidget(
        wrap(
          child: Theme(
            data: theme,
            child: const CircleAvatar(
              child: Text('Z'),
            ),
          ),
        ),
      );

      final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
      final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
      final BoxDecoration decoration = child.decoration as BoxDecoration;
      expect(decoration.color, equals(theme.primaryColorLight));

      final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
      expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color));
    });

311
    testWidgetsWithLeakTracking('CircleAvatar default colors with dark theme', (WidgetTester tester) async {
312
      final ThemeData theme = ThemeData(useMaterial3: false, primaryColor: Colors.grey.shade800);
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
      await tester.pumpWidget(
        wrap(
          child: Theme(
            data: theme,
            child: const CircleAvatar(
              child: Text('Z'),
            ),
          ),
        ),
      );

      final RenderConstrainedBox box = tester.renderObject(find.byType(CircleAvatar));
      final RenderDecoratedBox child = box.child! as RenderDecoratedBox;
      final BoxDecoration decoration = child.decoration as BoxDecoration;
      expect(decoration.color, equals(theme.primaryColorDark));

      final RenderParagraph paragraph = tester.renderObject(find.text('Z'));
      expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color));
    });
  });
333
}
Ian Hickson's avatar
Ian Hickson committed
334

335
Widget wrap({ required Widget child }) {
336
  return Directionality(
Ian Hickson's avatar
Ian Hickson committed
337
    textDirection: TextDirection.ltr,
338
    child: MediaQuery(
339
      data: const MediaQueryData(),
340 341 342
      child: MaterialApp(
        theme: ThemeData(useMaterial3: false),
        home: Center(child: child)),
343
    ),
Ian Hickson's avatar
Ian Hickson committed
344 345
  );
}