简体   繁体   中英

Best Approach To Testing App Appearance In Flutter While App Is In Dark/Light Theme (especially for Dark Theme)

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 .

  • What can be done to remedy this situation and how feasible is it to run Widget Tests (focused on app appearance)?
  • Should the universal default for testing app appearance in flutter be an Integration Test ?

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!]

HEre is my short solution, based on @Alvindera97 answer:

  Future<void> testDarkMode(
    WidgetTester tester, {
    required keyElementToCheckDarkmodeIn,
    required keyDarkmodeSwitcher,
  }) async {
    expect(
      Theme.of(tester.element(_finder.key(keyElementToCheckDarkmodeIn))).brightness,
      equals(Brightness.light),
    );

    await tester.tap(_finder.key(keyDarkmodeSwitcher));
    await tester.pump();
    await tester.pumpAndSettle(_testUtils.delay(DELAY));

    expect(
      Theme.of(tester.element(_finder.key(keyElementToCheckDarkmodeIn))).brightness,
      equals(Brightness.dark),
    );
  }

  Finder key(String keyText) {
    return find.byKey(Key(keyText));
  }


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM