animated_size_test.dart 9.69 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
// @dart = 2.8

7 8 9 10 11 12 13 14
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

class TestPaintingContext implements PaintingContext {
  final List<Invocation> invocations = <Invocation>[];

  @override
15 16 17
  void noSuchMethod(Invocation invocation) {
    invocations.add(invocation);
  }
18 19 20
}

void main() {
21 22 23
  group('AnimatedSize', () {
    testWidgets('animates forwards then backwards with stable-sized children', (WidgetTester tester) async {
      await tester.pumpWidget(
24 25
        Center(
          child: AnimatedSize(
26 27 28 29 30 31
            duration: const Duration(milliseconds: 200),
            vsync: tester,
            child: const SizedBox(
              width: 100.0,
              height: 100.0,
            ),
32 33
          ),
        ),
34 35 36 37 38 39 40
      );

      RenderBox box = tester.renderObject(find.byType(AnimatedSize));
      expect(box.size.width, equals(100.0));
      expect(box.size.height, equals(100.0));

      await tester.pumpWidget(
41 42
        Center(
          child: AnimatedSize(
43 44 45 46 47 48
            duration: const Duration(milliseconds: 200),
            vsync: tester,
            child: const SizedBox(
              width: 200.0,
              height: 200.0,
            ),
49 50
          ),
        ),
51 52 53 54 55 56 57
      );

      await tester.pump(const Duration(milliseconds: 100));
      box = tester.renderObject(find.byType(AnimatedSize));
      expect(box.size.width, equals(150.0));
      expect(box.size.height, equals(150.0));

58
      TestPaintingContext context = TestPaintingContext();
59 60 61 62 63 64 65 66 67
      box.paint(context, Offset.zero);
      expect(context.invocations.first.memberName, equals(#pushClipRect));

      await tester.pump(const Duration(milliseconds: 100));
      box = tester.renderObject(find.byType(AnimatedSize));
      expect(box.size.width, equals(200.0));
      expect(box.size.height, equals(200.0));

      await tester.pumpWidget(
68 69
        Center(
          child: AnimatedSize(
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
            duration: const Duration(milliseconds: 200),
            vsync: tester,
            child: const SizedBox(
              width: 100.0,
              height: 100.0,
            ),
          ),
        ),
      );

      await tester.pump(const Duration(milliseconds: 100));
      box = tester.renderObject(find.byType(AnimatedSize));
      expect(box.size.width, equals(150.0));
      expect(box.size.height, equals(150.0));

85
      context = TestPaintingContext();
86 87 88 89 90 91 92 93 94 95 96
      box.paint(context, Offset.zero);
      expect(context.invocations.first.memberName, equals(#paintChild));

      await tester.pump(const Duration(milliseconds: 100));
      box = tester.renderObject(find.byType(AnimatedSize));
      expect(box.size.width, equals(100.0));
      expect(box.size.height, equals(100.0));
    });

    testWidgets('clamps animated size to constraints', (WidgetTester tester) async {
      await tester.pumpWidget(
97 98
        Center(
          child: SizedBox (
99
            width: 100.0,
100
            height: 100.0,
101
            child: AnimatedSize(
102 103 104 105 106 107 108
              duration: const Duration(milliseconds: 200),
              vsync: tester,
              child: const SizedBox(
                width: 100.0,
                height: 100.0,
              ),
            ),
109 110
          ),
        ),
111 112 113 114 115 116 117 118
      );

      RenderBox box = tester.renderObject(find.byType(AnimatedSize));
      expect(box.size.width, equals(100.0));
      expect(box.size.height, equals(100.0));

      // Attempt to animate beyond the outer SizedBox.
      await tester.pumpWidget(
119 120
        Center(
          child: SizedBox (
121 122
            width: 100.0,
            height: 100.0,
123
            child: AnimatedSize(
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
              duration: const Duration(milliseconds: 200),
              vsync: tester,
              child: const SizedBox(
                width: 200.0,
                height: 200.0,
              ),
            ),
          ),
        ),
      );

      // Verify that animated size is the same as the outer SizedBox.
      await tester.pump(const Duration(milliseconds: 100));
      box = tester.renderObject(find.byType(AnimatedSize));
      expect(box.size.width, equals(100.0));
      expect(box.size.height, equals(100.0));
    });
141

142
    testWidgets('tracks unstable child, then resumes animation when child stabilizes', (WidgetTester tester) async {
143
      Future<void> pumpMillis(int millis) async {
144
        await tester.pump(Duration(milliseconds: millis));
145 146
      }

147
      void verify({ double size, RenderAnimatedSizeState state }) {
148 149 150 151 152 153 154 155 156 157 158 159
        assert(size != null || state != null);
        final RenderAnimatedSize box = tester.renderObject(find.byType(AnimatedSize));
        if (size != null) {
          expect(box.size.width, size);
          expect(box.size.height, size);
        }
        if (state != null) {
          expect(box.state, state);
        }
      }

      await tester.pumpWidget(
160 161
        Center(
          child: AnimatedSize(
162
            duration: const Duration(milliseconds: 200),
163
            vsync: tester,
164
            child: AnimatedContainer(
165
              duration: const Duration(milliseconds: 100),
166
              width: 100.0,
167 168 169 170
              height: 100.0,
            ),
          ),
        ),
171 172 173 174 175 176
      );

      verify(size: 100.0, state: RenderAnimatedSizeState.stable);

      // Animate child size from 100 to 200 slowly (100ms).
      await tester.pumpWidget(
177 178
        Center(
          child: AnimatedSize(
179
            duration: const Duration(milliseconds: 200),
180
            vsync: tester,
181
            child: AnimatedContainer(
182
              duration: const Duration(milliseconds: 100),
183
              width: 200.0,
184 185 186 187
              height: 200.0,
            ),
          ),
        ),
188
      );
189

190 191 192
      // Make sure animation proceeds at child's pace, with AnimatedSize
      // tightly tracking the child's size.
      verify(state: RenderAnimatedSizeState.stable);
193
      await pumpMillis(1); // register change
194 195 196 197 198
      verify(state: RenderAnimatedSizeState.changed);
      await pumpMillis(49);
      verify(size: 150.0, state: RenderAnimatedSizeState.unstable);
      await pumpMillis(50);
      verify(size: 200.0, state: RenderAnimatedSizeState.unstable);
199

200 201 202 203 204 205
      // Stabilize size
      await pumpMillis(50);
      verify(size: 200.0, state: RenderAnimatedSizeState.stable);

      // Quickly (in 1ms) change size back to 100
      await tester.pumpWidget(
206 207
        Center(
          child: AnimatedSize(
208 209
            duration: const Duration(milliseconds: 200),
            vsync: tester,
210
            child: AnimatedContainer(
211 212 213 214
              duration: const Duration(milliseconds: 1),
              width: 100.0,
              height: 100.0,
            ),
215 216
          ),
        ),
217 218 219
      );

      verify(size: 200.0, state: RenderAnimatedSizeState.stable);
220
      await pumpMillis(1); // register change
221 222 223 224 225 226 227 228 229 230
      verify(state: RenderAnimatedSizeState.changed);
      await pumpMillis(100);
      verify(size: 150.0, state: RenderAnimatedSizeState.stable);
      await pumpMillis(100);
      verify(size: 100.0, state: RenderAnimatedSizeState.stable);
    });

    testWidgets('resyncs its animation controller', (WidgetTester tester) async {
      await tester.pumpWidget(
        const Center(
231 232 233 234
          child: AnimatedSize(
            duration: Duration(milliseconds: 200),
            vsync: TestVSync(),
            child: SizedBox(
235 236 237
              width: 100.0,
              height: 100.0,
            ),
238 239
          ),
        ),
240
      );
241

242
      await tester.pumpWidget(
243 244
        Center(
          child: AnimatedSize(
245 246 247 248 249 250
            duration: const Duration(milliseconds: 200),
            vsync: tester,
            child: const SizedBox(
              width: 200.0,
              height: 100.0,
            ),
251 252
          ),
        ),
253 254 255 256 257 258 259 260 261 262
      );

      await tester.pump(const Duration(milliseconds: 100));

      final RenderBox box = tester.renderObject(find.byType(AnimatedSize));
      expect(box.size.width, equals(150.0));
    });

    testWidgets('does not run animation unnecessarily', (WidgetTester tester) async {
      await tester.pumpWidget(
263 264
        Center(
          child: AnimatedSize(
265 266 267 268 269 270
            duration: const Duration(milliseconds: 200),
            vsync: tester,
            child: const SizedBox(
              width: 100.0,
              height: 100.0,
            ),
271 272
          ),
        ),
273
      );
274

275 276 277 278 279 280 281 282 283
      for (int i = 0; i < 20; i++) {
        final RenderAnimatedSize box = tester.renderObject(find.byType(AnimatedSize));
        expect(box.size.width, 100.0);
        expect(box.size.height, 100.0);
        expect(box.state, RenderAnimatedSizeState.stable);
        expect(box.isAnimating, false);
        await tester.pump(const Duration(milliseconds: 10));
      }
    });
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

    testWidgets('can set and update clipBehavior', (WidgetTester tester) async {
      await tester.pumpWidget(
        Center(
          child: AnimatedSize(
            duration: const Duration(milliseconds: 200),
            vsync: tester,
            child: const SizedBox(
              width: 100.0,
              height: 100.0,
            ),
          ),
        ),
      );

      // By default, clipBehavior should be Clip.hardEdge
      final RenderAnimatedSize renderObject = tester.renderObject(find.byType(AnimatedSize));
      expect(renderObject.clipBehavior, equals(Clip.hardEdge));

      for(final Clip clip in Clip.values) {
        await tester.pumpWidget(
          Center(
            child: AnimatedSize(
              duration: const Duration(milliseconds: 200),
              vsync: tester,
              clipBehavior: clip,
              child: const SizedBox(
                width: 100.0,
                height: 100.0,
              ),
            ),
          ),
        );
        expect(renderObject.clipBehavior, clip);
      }
    });
320
  });
321
}