box_decoration_test.dart 10.6 KB
Newer Older
Hixie's avatar
Hixie committed
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7 8 9
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui show Image;

import 'package:flutter/foundation.dart';
10
import 'package:flutter/material.dart';
11
import 'package:flutter/painting.dart';
12
import 'package:flutter/widgets.dart';
13
import 'package:flutter_test/flutter_test.dart';
14

15
import '../painting/image_data.dart';
16 17
import '../rendering/mock_canvas.dart';

18 19 20
class TestImageProvider extends ImageProvider<TestImageProvider> {
  TestImageProvider(this.future);

21
  final Future<void> future;
22 23 24 25 26

  static ui.Image image;

  @override
  Future<TestImageProvider> obtainKey(ImageConfiguration configuration) {
27
    return SynchronousFuture<TestImageProvider>(this);
28 29 30 31
  }

  @override
  ImageStreamCompleter load(TestImageProvider key) {
32
    return OneFrameImageStreamCompleter(
33
      future.then<ImageInfo>((void value) => ImageInfo(image: image))
34 35 36 37
    );
  }
}

38
Future<void> main() async {
39
  AutomatedTestWidgetsFlutterBinding();
40
  TestImageProvider.image = await decodeImageFromList(Uint8List.fromList(kTransparentImage));
41 42

  testWidgets('DecoratedBox handles loading images', (WidgetTester tester) async {
43
    final GlobalKey key = GlobalKey();
44
    final Completer<void> completer = Completer<void>();
45
    await tester.pumpWidget(
46
      KeyedSubtree(
47
        key: key,
48 49 50 51
        child: DecoratedBox(
          decoration: BoxDecoration(
            image: DecorationImage(
              image: TestImageProvider(completer.future),
52 53 54 55 56 57 58 59 60 61 62 63 64 65
            ),
          ),
        ),
      ),
    );
    expect(tester.binding.hasScheduledFrame, isFalse);
    completer.complete();
    await tester.idle();
    expect(tester.binding.hasScheduledFrame, isTrue);
    await tester.pump();
    expect(tester.binding.hasScheduledFrame, isFalse);
  });

  testWidgets('Moving a DecoratedBox', (WidgetTester tester) async {
66
    final Completer<void> completer = Completer<void>();
67 68 69 70 71 72 73
    final Widget subtree = KeyedSubtree(
      key: GlobalKey(),
      child: RepaintBoundary(
        child: DecoratedBox(
          decoration: BoxDecoration(
            image: DecorationImage(
              image: TestImageProvider(completer.future),
74 75 76 77 78 79 80 81
            ),
          ),
        ),
      ),
    );
    await tester.pumpWidget(subtree);
    await tester.idle();
    expect(tester.binding.hasScheduledFrame, isFalse);
82
    await tester.pumpWidget(Container(child: subtree));
83 84 85 86 87 88 89 90 91 92 93
    await tester.idle();
    expect(tester.binding.hasScheduledFrame, isFalse);
    completer.complete(); // schedules microtask, does not run it
    expect(tester.binding.hasScheduledFrame, isFalse);
    await tester.idle(); // runs microtask
    expect(tester.binding.hasScheduledFrame, isTrue);
    await tester.pump();
    await tester.idle();
    expect(tester.binding.hasScheduledFrame, isFalse);
  });

94 95
  testWidgets('Circles can have uniform borders', (WidgetTester tester) async {
    await tester.pumpWidget(
96
      Container(
97
        padding: const EdgeInsets.all(50.0),
98
        decoration: BoxDecoration(
99
          shape: BoxShape.circle,
100
          border: Border.all(width: 10.0, color: const Color(0x80FF00FF)),
101 102
          color: Colors.teal[600],
        ),
103 104
      )
    );
105
  });
106

107
  testWidgets('Bordered Container insets its child', (WidgetTester tester) async {
108
    const Key key = Key('outerContainer');
109
    await tester.pumpWidget(
110 111
      Center(
        child: Container(
112
          key: key,
113 114
          decoration: BoxDecoration(border: Border.all(width: 10.0)),
          child: Container(
115
            width: 25.0,
116 117 118
            height: 25.0,
          ),
        ),
119 120 121
      )
    );
    expect(tester.getSize(find.byKey(key)), equals(const Size(45.0, 45.0)));
122
  });
123 124 125 126

  testWidgets('BoxDecoration paints its border correctly', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/7672

127
    const Key key = Key('Container with BoxDecoration');
128
    Widget buildFrame(Border border) {
129 130
      return Center(
        child: Container(
131 132 133
          key: key,
          width: 100.0,
          height: 50.0,
134
          decoration: BoxDecoration(border: border),
135 136 137 138
        ),
      );
    }

139
    const Color black = Color(0xFF000000);
140

141
    await tester.pumpWidget(buildFrame(Border.all()));
142
    expect(find.byKey(key), paints
143
      ..rect(color: black, style: PaintingStyle.stroke, strokeWidth: 1.0));
144

145
    await tester.pumpWidget(buildFrame(Border.all(width: 0.0)));
146
    expect(find.byKey(key), paints
147
      ..rect(color: black, style: PaintingStyle.stroke, strokeWidth: 0.0));
148

149 150
    const Color green = Color(0xFF00FF00);
    const BorderSide greenSide = BorderSide(color: green, width: 10.0);
151

152
    await tester.pumpWidget(buildFrame(const Border(top: greenSide)));
153 154
    expect(find.byKey(key), paints..path(color: green, style: PaintingStyle.fill));

155
    await tester.pumpWidget(buildFrame(const Border(left: greenSide)));
156 157
    expect(find.byKey(key), paints..path(color: green, style: PaintingStyle.fill));

158
    await tester.pumpWidget(buildFrame(const Border(right: greenSide)));
159 160
    expect(find.byKey(key), paints..path(color: green, style: PaintingStyle.fill));

161
    await tester.pumpWidget(buildFrame(const Border(bottom: greenSide)));
162
    expect(find.byKey(key), paints..path(color: green, style: PaintingStyle.fill));
163

164 165
    const Color blue = Color(0xFF0000FF);
    const BorderSide blueSide = BorderSide(color: blue, width: 0.0);
166

167
    await tester.pumpWidget(buildFrame(const Border(top: blueSide, right: greenSide, bottom: greenSide)));
168 169 170 171
    expect(find.byKey(key), paints
      ..path() // There's not much point checking the arguments to these calls because paintBorder
      ..path() // reuses the same Paint object each time, configured differently, and so they will
      ..path()); // all appear to have the same settings here (that of the last call).
172 173
  });

174 175 176
  testWidgets('BoxDecoration paints its border correctly', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/12165
    await tester.pumpWidget(
177
      Column(
178
        children: <Widget>[
179
          Container(
180 181 182 183 184
            // There's not currently a way to verify that this paints the same size as the others,
            // so the pattern below just asserts that there's four paths but doesn't check the geometry.
            width: 100.0,
            height: 100.0,
            decoration: const BoxDecoration(
185 186
              border: Border(
                top: BorderSide(
187
                  width: 10.0,
188
                  color: Color(0xFFEEEEEE),
189
                ),
190
                left: BorderSide(
191
                  width: 10.0,
192
                  color: Color(0xFFFFFFFF),
193
                ),
194
                right: BorderSide(
195
                  width: 10.0,
196
                  color: Color(0xFFFFFFFF),
197
                ),
198
                bottom: BorderSide(
199
                  width: 10.0,
200
                  color: Color(0xFFFFFFFF),
201 202 203 204
                ),
              ),
            ),
          ),
205
          Container(
206 207
            width: 100.0,
            height: 100.0,
208 209
            decoration: BoxDecoration(
              border: Border.all(
210 211 212 213 214
                width: 10.0,
                color: const Color(0xFFFFFFFF),
              ),
            ),
          ),
215
          Container(
216 217
            width: 100.0,
            height: 100.0,
218 219
            decoration: BoxDecoration(
              border: Border.all(
220 221 222 223
                width: 10.0,
                color: const Color(0xFFFFFFFF),
              ),
              borderRadius: const BorderRadius.only(
224
                topRight: Radius.circular(10.0),
225 226 227
              ),
            ),
          ),
228
          Container(
229 230
            width: 100.0,
            height: 100.0,
231 232
            decoration: BoxDecoration(
              border: Border.all(
233 234 235 236 237 238 239 240 241 242 243 244 245 246
                width: 10.0,
                color: const Color(0xFFFFFFFF),
              ),
              shape: BoxShape.circle,
            ),
          ),
        ],
      ),
    );
    expect(find.byType(Column), paints
      ..path()
      ..path()
      ..path()
      ..path()
Dan Field's avatar
Dan Field committed
247
      ..rect(rect: const Rect.fromLTRB(355.0, 105.0, 445.0, 195.0))
248
      ..drrect(
249
        outer: RRect.fromLTRBAndCorners(
250 251 252 253 254 255
          350.0, 200.0, 450.0, 300.0,
          topLeft: Radius.zero,
          topRight: const Radius.circular(10.0),
          bottomRight: Radius.zero,
          bottomLeft: Radius.zero,
        ),
256
        inner: RRect.fromLTRBAndCorners(
257 258 259 260 261 262 263
          360.0, 210.0, 440.0, 290.0,
          topLeft: const Radius.circular(-10.0),
          topRight: Radius.zero,
          bottomRight: const Radius.circular(-10.0),
          bottomLeft: const Radius.circular(-10.0),
        ),
      )
264
      ..circle(x: 400.0, y: 350.0, radius: 45.0),
265 266
    );
  });
267 268 269 270 271

  testWidgets('Can hit test on BoxDecoration', (WidgetTester tester) async {

    List<int> itemsTapped;

272
    const Key key = Key('Container with BoxDecoration');
273 274
    Widget buildFrame(Border border) {
      itemsTapped = <int>[];
275 276
      return Center(
        child: GestureDetector(
277
          behavior: HitTestBehavior.deferToChild,
278
          child: Container(
279 280 281
            key: key,
            width: 100.0,
            height: 50.0,
282
            decoration: BoxDecoration(border: border),
283 284 285 286
          ),
          onTap: () {
            itemsTapped.add(1);
          },
287
        ),
288 289 290
      );
    }

291
    await tester.pumpWidget(buildFrame(Border.all()));
292 293 294 295 296 297 298 299 300 301
    expect(itemsTapped, isEmpty);

    await tester.tap(find.byKey(key));
    expect(itemsTapped, <int>[1]);

    await tester.tapAt(const Offset(350.0, 275.0));
    expect(itemsTapped, <int>[1,1]);

    await tester.tapAt(const Offset(449.0, 324.0));
    expect(itemsTapped, <int>[1,1,1]);
302

303 304 305 306 307 308
  });

  testWidgets('Can hit test on BoxDecoration circle', (WidgetTester tester) async {

    List<int> itemsTapped;

309
    const Key key = Key('Container with BoxDecoration');
310 311
    Widget buildFrame(Border border) {
      itemsTapped = <int>[];
312 313
      return Center(
        child: GestureDetector(
314
            behavior: HitTestBehavior.deferToChild,
315
            child: Container(
316 317 318
            key: key,
            width: 100.0,
            height: 50.0,
319
            decoration: BoxDecoration(border: border, shape: BoxShape.circle),
320 321 322 323
          ),
          onTap: () {
            itemsTapped.add(1);
          },
324
        ),
325 326 327
      );
    }

328
    await tester.pumpWidget(buildFrame(Border.all()));
329 330 331 332 333 334 335 336 337 338 339 340 341
    expect(itemsTapped, isEmpty);

    await tester.tapAt(const Offset(0.0, 0.0));
    expect(itemsTapped, isEmpty);

    await tester.tapAt(const Offset(350.0, 275.0));
    expect(itemsTapped, isEmpty);

    await tester.tapAt(const Offset(400.0, 300.0));
    expect(itemsTapped, <int>[1]);

    await tester.tap(find.byKey(key));
    expect(itemsTapped, <int>[1,1]);
342

343 344
  });

345
}