blob: afad96ecfe1d539054024f22a5f961ae0233567e [file] [log] [blame]
// 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/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Animates forward when built', (WidgetTester tester) async {
final List<int> values = <int>[];
int endCount = 0;
await tester.pumpWidget(
TweenAnimationBuilder<int>(
duration: const Duration(seconds: 1),
tween: IntTween(begin: 10, end: 110),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
onEnd: () {
endCount++;
},
),
);
expect(endCount, 0);
expect(values, <int>[10]);
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[10, 60]);
await tester.pump(const Duration(milliseconds: 501));
expect(endCount, 1);
expect(values, <int>[10, 60, 110]);
await tester.pump(const Duration(milliseconds: 500));
expect(endCount, 1);
expect(values, <int>[10, 60, 110]);
});
testWidgets('No initial animation when begin=null', (WidgetTester tester) async {
final List<int> values = <int>[];
int endCount = 0;
await tester.pumpWidget(
TweenAnimationBuilder<int>(
duration: const Duration(seconds: 1),
tween: IntTween(end: 100),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
onEnd: () {
endCount++;
},
),
);
expect(endCount, 0);
expect(values, <int>[100]);
await tester.pump(const Duration(seconds: 2));
expect(endCount, 0);
expect(values, <int>[100]);
});
testWidgets('No initial animation when begin=end', (WidgetTester tester) async {
final List<int> values = <int>[];
int endCount = 0;
await tester.pumpWidget(
TweenAnimationBuilder<int>(
duration: const Duration(seconds: 1),
tween: IntTween(begin: 100, end: 100),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
onEnd: () {
endCount++;
},
),
);
expect(endCount, 0);
expect(values, <int>[100]);
await tester.pump(const Duration(seconds: 2));
expect(endCount, 0);
expect(values, <int>[100]);
});
testWidgets('Replace tween animates new tween', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required IntTween tween}) {
return TweenAnimationBuilder<int>(
duration: const Duration(seconds: 1),
tween: tween,
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
await tester.pumpWidget(buildWidget(tween: IntTween(begin: 0, end: 100)));
expect(values, <int>[0]);
await tester.pump(const Duration(seconds: 2)); // finish first animation.
expect(values, <int>[0, 100]);
await tester.pumpWidget(buildWidget(tween: IntTween(begin: 100, end: 200)));
expect(values, <int>[0, 100, 100]);
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 100, 100, 150]);
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 100, 100, 150, 200]);
});
testWidgets('Curve is respected', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required IntTween tween, required Curve curve}) {
return TweenAnimationBuilder<int>(
duration: const Duration(seconds: 1),
tween: tween,
curve: curve,
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
await tester.pumpWidget(buildWidget(tween: IntTween(begin: 0, end: 100), curve: Curves.easeInExpo));
expect(values, <int>[0]);
await tester.pump(const Duration(milliseconds: 500));
expect(values.last, lessThan(50));
expect(values.last, greaterThan(0));
await tester.pump(const Duration(seconds: 2)); // finish animation.
values.clear();
// Update curve (and tween to re-trigger animation).
await tester.pumpWidget(buildWidget(tween: IntTween(begin: 100, end: 200), curve: Curves.linear));
expect(values, <int>[100]);
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[100, 150]);
});
testWidgets('Duration is respected', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required IntTween tween, required Duration duration}) {
return TweenAnimationBuilder<int>(
tween: tween,
duration: duration,
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
await tester.pumpWidget(buildWidget(tween: IntTween(begin: 0, end: 100), duration: const Duration(seconds: 1)));
expect(values, <int>[0]);
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 50]);
await tester.pump(const Duration(seconds: 2)); // finish animation.
values.clear();
// Update duration (and tween to re-trigger animation).
await tester.pumpWidget(buildWidget(tween: IntTween(begin: 100, end: 200), duration: const Duration(seconds: 2)));
expect(values, <int>[100]);
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[100, 125]);
});
testWidgets('Child is integrated into tree', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: TweenAnimationBuilder<int>(
tween: IntTween(begin: 0, end: 100),
duration: const Duration(seconds: 1),
builder: (BuildContext context, int i, Widget? child) {
return child!;
},
child: const Text('Hello World'),
),
),
);
expect(find.text('Hello World'), findsOneWidget);
});
group('Change tween gapless while', () {
testWidgets('running forward', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required IntTween tween}) {
return TweenAnimationBuilder<int>(
tween: tween,
duration: const Duration(seconds: 1),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
await tester.pumpWidget(buildWidget(
tween: IntTween(begin: 0, end: 100),
));
expect(values, <int>[0]);
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 50]);
// Change tween
await tester.pumpWidget(buildWidget(
tween: IntTween(begin: 200, end: 300),
));
expect(values, <int>[0, 50, 50]); // gapless: animation continues where it left off.
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 50, 50, 175]); // 175 = halfway between 50 and new target 300.
// Run animation to end
await tester.pump(const Duration(seconds: 2));
expect(values, <int>[0, 50, 50, 175, 300]);
values.clear();
});
testWidgets('running forward and then reverse with same tween instance', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required IntTween tween}) {
return TweenAnimationBuilder<int>(
tween: tween,
duration: const Duration(seconds: 1),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
final IntTween tween1 = IntTween(begin: 0, end: 100);
final IntTween tween2 = IntTween(begin: 200, end: 300);
await tester.pumpWidget(buildWidget(
tween: tween1,
));
await tester.pump(const Duration(milliseconds: 500));
await tester.pumpWidget(buildWidget(
tween: tween2,
));
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(seconds: 2));
expect(values, <int>[0, 50, 50, 175, 300]);
values.clear();
});
});
testWidgets('Changing tween while gapless tween change is in progress', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required IntTween tween}) {
return TweenAnimationBuilder<int>(
tween: tween,
duration: const Duration(seconds: 1),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
final IntTween tween1 = IntTween(begin: 0, end: 100);
final IntTween tween2 = IntTween(begin: 200, end: 300);
final IntTween tween3 = IntTween(begin: 400, end: 501);
await tester.pumpWidget(buildWidget(
tween: tween1,
));
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 50]);
values.clear();
// Change tween
await tester.pumpWidget(buildWidget(
tween: tween2,
));
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[50, 175]);
values.clear();
await tester.pumpWidget(buildWidget(
tween: tween3,
));
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[175, 338, 501]);
});
testWidgets('Changing curve while no animation is running does not trigger animation', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required Curve curve}) {
return TweenAnimationBuilder<int>(
tween: IntTween(begin: 0, end: 100),
curve: curve,
duration: const Duration(seconds: 1),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
await tester.pumpWidget(buildWidget(
curve: Curves.linear,
));
await tester.pump(const Duration(seconds: 2));
expect(values, <int>[0, 100]);
values.clear();
await tester.pumpWidget(buildWidget(
curve: Curves.easeInExpo,
));
expect(values, <int>[100]);
await tester.pump(const Duration(seconds: 2));
expect(values, <int>[100]);
});
testWidgets('Setting same tween and direction does not trigger animation', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required IntTween tween}) {
return TweenAnimationBuilder<int>(
tween: tween,
duration: const Duration(seconds: 1),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
await tester.pumpWidget(buildWidget(
tween: IntTween(begin: 0, end: 100),
));
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 50, 100]);
values.clear();
await tester.pumpWidget(buildWidget(
tween: IntTween(begin: 0, end: 100),
));
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
expect(values, everyElement(100));
});
testWidgets('Setting same tween and direction while gapless animation is in progress works', (WidgetTester tester) async {
final List<int> values = <int>[];
Widget buildWidget({required IntTween tween}) {
return TweenAnimationBuilder<int>(
tween: tween,
duration: const Duration(seconds: 1),
builder: (BuildContext context, int i, Widget? child) {
values.add(i);
return const Placeholder();
},
);
}
await tester.pumpWidget(buildWidget(
tween: IntTween(begin: 0, end: 100),
));
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 50]);
await tester.pumpWidget(buildWidget(
tween: IntTween(begin: 200, end: 300),
));
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 50, 50, 175]);
await tester.pumpWidget(buildWidget(
tween: IntTween(begin: 200, end: 300),
));
expect(values, <int>[0, 50, 50, 175, 175]);
await tester.pump(const Duration(milliseconds: 500));
expect(values, <int>[0, 50, 50, 175, 175, 300]);
values.clear();
await tester.pump(const Duration(seconds: 2));
expect(values, everyElement(300));
});
testWidgets('Works with nullable tweens', (WidgetTester tester) async {
final List<Size?> values = <Size?>[];
await tester.pumpWidget(
TweenAnimationBuilder<Size?>(
duration: const Duration(seconds: 1),
tween: SizeTween(end: const Size(10,10)),
builder: (BuildContext context, Size? s, Widget? child) {
values.add(s);
return const Placeholder();
},
),
);
expect(values, <Size>[const Size(10,10)]);
await tester.pump(const Duration(seconds: 2));
expect(values, <Size>[const Size(10,10)]);
});
}