I am trying to create widget splash screen that shows when the app loads and the native splash screen is shown. I created the splash screen and everything seems fine so i decide to create widget test for the splash screen background image and single text on the screen. The test part for the text passes but i have issues with the image.
Widget test error text:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: _WidgetTypeFinder:<zero widgets with type "Image" (ignoring offstage widgets)>
Which: means none were found but one was expected
The full splash screen code:
class SplashScreenPage extends StatefulWidget {
const SplashScreenPage({Key? key}) : super(key: key);
@override
State<SplashScreenPage> createState() => _SplashScreenPageState();
}
class _SplashScreenPageState extends State<SplashScreenPage> {
Timer? _timer;
@override
void initState() {
_timer = Timer(const Duration(seconds: 4), () {
Navigator.of(context).pushReplacementNamed(RoutingConst.defaultRoute);
});
super.initState();
}
@override
void dispose() {
_timer!.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background.png"),
fit: BoxFit.cover,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
const Spacer(),
const Spacer(),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: Text(
"SPLASH SCREEN TEXT",
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: GoogleFonts.inter(
color: Colors.white,
fontSize: 40,
fontWeight: FontWeight.bold,
),
),
),
],
),
const Spacer(),
],
),
),
]
),
);
}
}
The widget test:
void main() {
//
// Setup
//
Widget createWidgetUnderTest() {
return const MaterialApp(
home: SplashScreenPage(),
);
}
//
// Testing
//
testWidgets(
"Check if splash screen text shows up",
(WidgetTester tester) async {
await tester.pumpWidget(createWidgetUnderTest());
expect(find.text("SPLASH SCREEN TEXT"), findsOneWidget);
},
);
testWidgets(
"Check if splash screen background shows up",
(WidgetTester tester) async {
await tester.pumpWidget(createWidgetUnderTest());
expect(find.byType(Image), findsOneWidget);
},
);
}
The test for the text passes, but the one for the image fails and i can't figure out why. I tried the find.image(AssetImage("asset-path")) but that didn't work aswell. Tried to put key on the container holding the box decoration in and then try to find the container in the test and it finds it so maybie i am doing something wrong in finding image inside box decoration but i don't know how to find it if that's the case.
The SplashScreenPage
does not contain an actual Image widget, so the finders below used in the test will fail to find an Image
widget.
find.byType(Image)
finds a Widget
of type Image
.find.image()
finds a Widget
of type Image
or FadeInImage
.Setting an image to a Container
's decoration
does not create an Image
widget, so the finders are inappropriate for this test.
Use find.byWidgetPredicate to find the actual Widget
containing the image, in this case: Container
and add checks to specify the properties of the Container
you're looking for.
Here's the code:
testWidgets(
"Check if splash screen background shows up",
(WidgetTester tester) async {
await tester.pumpWidget(createWidgetUnderTest());
final assetImageFinder = find.byWidgetPredicate(
(Widget widget) {
if (widget is Container) {
final decoration = widget.decoration;
if (decoration is BoxDecoration) {
final image = decoration.image;
if (image is DecorationImage) {
final imageProvider = image.image;
if (imageProvider is AssetImage) {
return imageProvider.assetName ==
"assets/images/background.png";
}
}
}
}
return false;
},
);
expect(assetImageFinder, findsOneWidget);
},
);