animated_size_test.dart 8.63 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2016 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.

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
13 14 15
  void noSuchMethod(Invocation invocation) {
    invocations.add(invocation);
  }
16 17 18
}

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

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

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

      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));

56
      TestPaintingContext context = TestPaintingContext();
57 58 59 60 61 62 63 64 65
      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(
66 67
        Center(
          child: AnimatedSize(
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
            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));

83
      context = TestPaintingContext();
84 85 86 87 88 89 90 91 92 93 94
      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(
95 96
        Center(
          child: SizedBox (
97
            width: 100.0,
98
            height: 100.0,
99
            child: AnimatedSize(
100 101 102 103 104 105 106
              duration: const Duration(milliseconds: 200),
              vsync: tester,
              child: const SizedBox(
                width: 100.0,
                height: 100.0,
              ),
            ),
107 108
          ),
        ),
109 110 111 112 113 114 115 116
      );

      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(
117 118
        Center(
          child: SizedBox (
119 120
            width: 100.0,
            height: 100.0,
121
            child: AnimatedSize(
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
              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));
    });
139

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

145
      void verify({ double size, RenderAnimatedSizeState state }) {
146 147 148 149 150 151 152 153 154 155 156 157
        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(
158 159
        Center(
          child: AnimatedSize(
160
            duration: const Duration(milliseconds: 200),
161
            vsync: tester,
162
            child: AnimatedContainer(
163
              duration: const Duration(milliseconds: 100),
164
              width: 100.0,
165 166 167 168
              height: 100.0,
            ),
          ),
        ),
169 170 171 172 173 174
      );

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

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

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

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

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

      verify(size: 200.0, state: RenderAnimatedSizeState.stable);
218
      await pumpMillis(1); // register change
219 220 221 222 223 224 225 226 227 228
      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(
229 230 231 232
          child: AnimatedSize(
            duration: Duration(milliseconds: 200),
            vsync: TestVSync(),
            child: SizedBox(
233 234 235
              width: 100.0,
              height: 100.0,
            ),
236 237
          ),
        ),
238
      );
239

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

      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(
261 262
        Center(
          child: AnimatedSize(
263 264 265 266 267 268
            duration: const Duration(milliseconds: 200),
            vsync: tester,
            child: const SizedBox(
              width: 100.0,
              height: 100.0,
            ),
269 270
          ),
        ),
271
      );
272

273 274 275 276 277 278 279 280 281
      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));
      }
    });
282
  });
283
}