-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
request: pump more than one widget in sequence #141
Comments
Can you explain a little bit more of what the expected outcome would be? For example, if you ran your example with a starting opacity of 0 and an ending of 1, what opacity would you want captured in the golden image file? My initial reaction is that alchemist isn't the best use case for this, because there can be slight platform differences in animation timing. For testing animations with alchemist I recommend trying the method I outlined here. Let me know if that works or if you think this issue can be handled in another way. |
I guess I would like to capture a few golden image files at different states of the animation. I would like to use alchemist for a test where I need to pump two slightly different widgets, like the one below: import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('AnimatedOpacity', (tester) async {
Future<void> pumpWidget(double opacity) => tester.pumpWidget(
Center(
child: DecoratedBox(
decoration: const BoxDecoration(color: Colors.white),
child: SizedBox(
width: 100,
height: 100,
child: AnimatedOpacity(
opacity: opacity,
duration: const Duration(seconds: 2),
child: const Placeholder(),
),
),
),
),
);
await pumpWidget(0.3);
await expectLater(
find.byType(DecoratedBox),
matchesGoldenFile('goldens/screenshot0.png'),
);
await pumpWidget(1);
await expectLater(
find.byType(DecoratedBox),
matchesGoldenFile('goldens/screenshot1.png'),
);
await tester.pump(const Duration(seconds: 1));
await expectLater(
find.byType(DecoratedBox),
matchesGoldenFile('goldens/screenshot2.png'),
);
await tester.pump(const Duration(seconds: 1));
await expectLater(
find.byType(DecoratedBox),
matchesGoldenFile('goldens/screenshot3.png'),
);
});
} But I would like to use Alchemist instead of Flutter's own
Your example may work, but it will involve more refactoring than I would like. Also, I will need to come up with another (non-golden) test to ensure that the outer widget is passing the correct animation values to the inner widget. If there are no plans for a feature like this, I may try a different hack, where I wrap |
I was able to use a timer to create a frame-by-frame golden test of an animation. I'll leave it here in case it's of use to anyone. import 'dart:async';
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
void main() {
const animationDuration = Duration(seconds: 10);
const frames = 10;
final frameDuration = animationDuration ~/ frames;
AnimatedOpacity animatedOpacity(double opacity) => AnimatedOpacity(
duration: animationDuration,
opacity: opacity,
child: const SizedBox(
width: 100,
height: 100,
child: Placeholder(),
),
);
goldenTest(
'AnimatedOpacity',
fileName: 'animated_opacity',
pumpBeforeTest: pumpNTimes(frames + 2, frameDuration),
builder: () => GoldenTestGroup(
children: [
for (Duration d = animationDuration + const Duration(seconds: 1);
d >= Duration.zero;
d -= frameDuration)
GoldenTestScenario(
name: '${d.inSeconds}s',
child: _DelayedSwitch(
delay: d,
first: animatedOpacity(0.3),
second: animatedOpacity(1),
),
),
],
),
);
}
class _DelayedSwitch extends StatefulWidget {
const _DelayedSwitch({
required this.delay,
required this.first,
required this.second,
});
final Duration delay;
final Widget first;
final Widget second;
@override
State<StatefulWidget> createState() => _DelayedSwitchState();
}
class _DelayedSwitchState extends State<_DelayedSwitch> {
late Timer _timer;
bool _delayElapsed = false;
@override
void initState() {
super.initState();
_delayElapsed = false;
_timer = Timer(widget.delay, () => setState(() => _delayElapsed = true));
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return _delayElapsed ? widget.second : widget.first;
}
} |
Is there an existing feature request for this?
Command
pump one widget, and then another
Description
I've been trying to test a few animated widgets which produce an animation based on changes to its properties. They are very similar to Flutter's own animated widgets. Take
AnimatedOpacity
for example. At first, whenAnimatedOpacity
is built, itschild
is built with the specifiedopacity
. Then, if it is built again with a different value foropacity
, an animation is performed where the opacity level changes from the original to the new value.Testing this widget would require me to pump it with one value for
opacity
and then pump it again with a different value. I've tried usinggoldenTest.pumpWidget
with something like:But the
widget
received bypumpWidget
is an Alchemist wrapper aroundAnimatedOpacity
, and not just anAnimatedOpacity
widget.Reasoning
This is a basic type of animation used even by Flutter's own animated widgets. It would be nice to be able to test these with Alchemist.
Additional context and comments
Is there currently a way in which this could work with Alchemist as is? Or what kind of change would it make sense to implement in Alchemist to make tests such as this possible?
The text was updated successfully, but these errors were encountered: