After going through the Flutter docs on testing, I have come to a point in my app where I would like to test both light and dark theme appearance on the app. Integration tests could be an option, however they are "expensive" to run and I would like to leave the consideration of integration tests as a last resort on the matter of testing for dark/light theme app appearance.
This is what I tried with (Widget Tests) testWidgets
:
void main() {
testWidgets("Test that the app renders properly in 'Dark Theme'.",
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData.dark(),
home: RegistrationHomePage(),
),
);
expect(
SchedulerBinding.instance.window.platformBrightness,
Brightness.dark,
reason: "The test suite should now be testing with app theme set to dark theme.",
);
})
}
However, this test failed. It failed because the Widget Test is still executing this test in light theme instead of dark theme.
Update: Realistically, I am testing the color that a text widget would be displayed in [both in light theme and dark theme].
main.dart
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.system,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
home: RegistrationHomePage(),
);
}
}
registration_screen.dart
class RegistrationHomePage extends StatefulWidget {
// Constructor
RegistrationHomePage({Key key}) : super(key: key);
@override
_RegistrationHomePageState createState() => _RegistrationHomePageState();
}
class _RegistrationHomePageState extends State<RegistrationHomePage> {
void setState(fn) {
super.setState(fn);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(
"Welcome to the app",
style: TextStyle(
color: MediaQuery.of(context).platformBrightness == Brightness.dark
? Colors.green.shade900
: Colors.green,
fontWeight: FontWeight.w600,
fontSize: 35.0,
),
textAlign: TextAlign.center,
),
),
);
}
}
test.dart
void main() {
testWidgets("Test that the app renders properly in 'Dark Theme'.",
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData.dark(),
home: RegistrationHomePage(),
),
);
final Finder loginTextFinder = find.text("Welcome to the app.");
final Text loginText = tester.firstWidget(loginTextFinder);
expect(
WelcomeText.style.color,
Colors.green.shade900,
reason:
'While the system dark is dark theme, the text color should be dark green',
);
});
}
The test fails. The test fails because the tests have been carried out with the app set to light theme instead of dark theme. There must be something I'm doing wrong here. For now it seems like I cannot set the test app to dark theme which I have tried to do in test.dart
with
void main() {
testWidgets("Test that the app renders properly in 'Dark Theme'.",
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData.dark(),
home: RegistrationHomePage(),
),
);
});
}
This is the route I would take if I am running a widget test for an app in dark theme:
void main() {
testWidgets("Test that the app renders properly in dark theme",
(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
theme: ThemeData(brightness: Brightness.dark),
home: RegistrationHomePage(),
));
// Capture a BuildContext object
final BuildContext context = tester.element(find.byType(MaterialApp));
// Get finders and relevant objects that would be available at first load of MaterialApp()
final Finder welcomeTextFinder = find.text("Welcome to the app");
final Text welcomeText = tester.firstWidget(welcomeTextFinder);
// functions
bool testIsInLightTheme() {
/// return true if the test is in light theme, else false
if (Theme.of(context).brightness == Brightness.light) {
return true;
}
return false;
}
// Here is just a test to confirm that the MaterialApp is now in dark theme
expect(
Theme.of(tester.element(find.byWidget(welcomeText))).brightness,
equals(Brightness.dark),
reason:
"Since MaterialApp() was set to dark theme when it was built at tester.pumpWidget(), the MaterialApp should be in dark theme",
);
// Now let's test the color of the text
expect(
welcomeText.style.color,
testIsInLightTheme() ? Colors.green : Colors.green.shade900,
reason:
"When MaterialApp is in light theme, text is black. When Material App is in dark theme, text is white",
);
});
}
Some notable mentions: Capturing a BuildContext object in test: https://stackoverflow.com/a/67704136/7181909
Standard instruction (basically some flutter source code that dealt with theme testing) on how theme testing should be approached [By the Flutter team that contributed to theme related testing!]