// Copyright 2014 The Flutter 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/animation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('awaiting animation controllers - using direct future', (WidgetTester tester) async { final AnimationController controller1 = AnimationController( duration: const Duration(milliseconds: 100), vsync: const TestVSync(), ); final AnimationController controller2 = AnimationController( duration: const Duration(milliseconds: 600), vsync: const TestVSync(), ); final AnimationController controller3 = AnimationController( duration: const Duration(milliseconds: 300), vsync: const TestVSync(), ); final List<String> log = <String>[]; Future<void> runTest() async { log.add('a'); // t=0 await controller1.forward(); // starts at t=0 again log.add('b'); // wants to end at t=100 but missed frames until t=150 await controller2.forward(); // starts at t=150 log.add('c'); // wants to end at t=750 but missed frames until t=799 await controller3.forward(); // starts at t=799 log.add('d'); // wants to end at t=1099 but missed frames until t=1200 } log.add('start'); runTest().then((void value) { log.add('end'); }); await tester.pump(); // t=0 expect(log, <String>['start', 'a']); await tester.pump(); // t=0 again expect(log, <String>['start', 'a']); await tester.pump(const Duration(milliseconds: 50)); // t=50 expect(log, <String>['start', 'a']); await tester.pump(const Duration(milliseconds: 100)); // t=150 expect(log, <String>['start', 'a', 'b']); await tester.pump(const Duration(milliseconds: 50)); // t=200 expect(log, <String>['start', 'a', 'b']); await tester.pump(const Duration(milliseconds: 400)); // t=600 expect(log, <String>['start', 'a', 'b']); await tester.pump(const Duration(milliseconds: 199)); // t=799 expect(log, <String>['start', 'a', 'b', 'c']); await tester.pump(const Duration(milliseconds: 51)); // t=850 expect(log, <String>['start', 'a', 'b', 'c']); await tester.pump(const Duration(milliseconds: 400)); // t=1200 expect(log, <String>['start', 'a', 'b', 'c', 'd', 'end']); await tester.pump(const Duration(milliseconds: 400)); // t=1600 expect(log, <String>['start', 'a', 'b', 'c', 'd', 'end']); }); testWidgets('awaiting animation controllers - using orCancel', (WidgetTester tester) async { final AnimationController controller1 = AnimationController( duration: const Duration(milliseconds: 100), vsync: const TestVSync(), ); final AnimationController controller2 = AnimationController( duration: const Duration(milliseconds: 600), vsync: const TestVSync(), ); final AnimationController controller3 = AnimationController( duration: const Duration(milliseconds: 300), vsync: const TestVSync(), ); final List<String> log = <String>[]; Future<void> runTest() async { log.add('a'); // t=0 await controller1.forward().orCancel; // starts at t=0 again log.add('b'); // wants to end at t=100 but missed frames until t=150 await controller2.forward().orCancel; // starts at t=150 log.add('c'); // wants to end at t=750 but missed frames until t=799 await controller3.forward().orCancel; // starts at t=799 log.add('d'); // wants to end at t=1099 but missed frames until t=1200 } log.add('start'); runTest().then((void value) { log.add('end'); }); await tester.pump(); // t=0 expect(log, <String>['start', 'a']); await tester.pump(); // t=0 again expect(log, <String>['start', 'a']); await tester.pump(const Duration(milliseconds: 50)); // t=50 expect(log, <String>['start', 'a']); await tester.pump(const Duration(milliseconds: 100)); // t=150 expect(log, <String>['start', 'a', 'b']); await tester.pump(const Duration(milliseconds: 50)); // t=200 expect(log, <String>['start', 'a', 'b']); await tester.pump(const Duration(milliseconds: 400)); // t=600 expect(log, <String>['start', 'a', 'b']); await tester.pump(const Duration(milliseconds: 199)); // t=799 expect(log, <String>['start', 'a', 'b', 'c']); await tester.pump(const Duration(milliseconds: 51)); // t=850 expect(log, <String>['start', 'a', 'b', 'c']); await tester.pump(const Duration(milliseconds: 400)); // t=1200 expect(log, <String>['start', 'a', 'b', 'c', 'd', 'end']); await tester.pump(const Duration(milliseconds: 400)); // t=1600 expect(log, <String>['start', 'a', 'b', 'c', 'd', 'end']); }); testWidgets('awaiting animation controllers and failing', (WidgetTester tester) async { final AnimationController controller1 = AnimationController( duration: const Duration(milliseconds: 100), vsync: const TestVSync(), ); final List<String> log = <String>[]; Future<void> runTest() async { try { log.add('start'); await controller1.forward().orCancel; log.add('fail'); } on TickerCanceled { log.add('caught'); } } runTest().then((void value) { log.add('end'); }); await tester.pump(); // start ticker expect(log, <String>['start']); await tester.pump(const Duration(milliseconds: 50)); expect(log, <String>['start']); controller1.dispose(); expect(log, <String>['start']); await tester.idle(); expect(log, <String>['start', 'caught', 'end']); }); testWidgets('creating orCancel future later', (WidgetTester tester) async { final AnimationController controller1 = AnimationController( duration: const Duration(milliseconds: 100), vsync: const TestVSync(), ); final TickerFuture f = controller1.forward(); await tester.pump(); // start ticker await tester.pump(const Duration(milliseconds: 200)); // end ticker await f; // should be a no-op await f.orCancel; // should create a resolved future expect(true, isTrue); // should reach here }); testWidgets('creating orCancel future later', (WidgetTester tester) async { final AnimationController controller1 = AnimationController( duration: const Duration(milliseconds: 100), vsync: const TestVSync(), ); final TickerFuture f = controller1.forward(); await tester.pump(); // start ticker controller1.stop(); // cancel ticker bool ok = false; try { await f.orCancel; // should create a resolved future } on TickerCanceled { ok = true; } expect(ok, isTrue); // should reach here }); testWidgets('TickerFuture is a Future', (WidgetTester tester) async { final AnimationController controller1 = AnimationController( duration: const Duration(milliseconds: 100), vsync: const TestVSync(), ); final TickerFuture f = controller1.forward(); await tester.pump(); // start ticker await tester.pump(const Duration(milliseconds: 200)); // end ticker expect(f.asStream().single, isA<Future<void>>()); await f.catchError((dynamic e) { throw 'do not reach'; }); expect(await f.then<bool>((_) => true), isTrue); expect(f.whenComplete(() => false), isA<Future<void>>()); expect(f.timeout(const Duration(seconds: 5)), isA<Future<void>>()); }); }