animated_size_test.dart 8.65 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
}