Testing the widget’s appearance in Flutter

leonardorosaa

Leonardo Rosa

Posted on March 27, 2023

Testing the widget’s appearance in Flutter

A good programmer writes tests to find errors and maintain the code. Tests are part of a programmer guy daily, but many programmers ignore an important kind of test, the user interface test. Can you think how hard to ensure the widget's appearance or don’t introduce a bug for a project with thousands of widgets? That’s much hard or maybe impossible to maintain this without tests. However, The Flutter Golden Test provides an easy way to help us ensure that widgets have the correct appearance.

In this article, you'll learn about improving your user interface testing experience with the Alchemist tool and any concepts of the Golden Test.

The maintainable code is a testable code. - Unknown

What’s a Golden Test?

Remembering a little of any concepts of unit tests, the Golden Test provides a way to test the appearance of one single widget using a master image called Golden File which is considered the correct rendering of a widget.

Setting up the Alchemist package

The tool configuration is pretty simple and easy. Let’s start installing the Alchemist package into the project with the command below:

flutter pub add alchemist --dev
Enter fullscreen mode Exit fullscreen mode

Create a file to prepare some configurations before a test is executed called flutter_test_config.dart in the test/ directory after installing the Alchemist tool successfully. In this file, we’ll prepare some configurations like render widget shadows and allow the display of raw text rather than obscure them.

import 'dart:async';

import 'package:alchemist/alchemist.dart';

Future<void> testExecutable(FutureOr<void> Function() testMain) async {
  return prepareGoldenTests(testMain);
}

void prepareGoldenTests(FutureOr<void> Function() testMain) {
  return AlchemistConfig.runWithConfig(
    config: const AlchemistConfig(
      platformGoldensConfig: PlatformGoldensConfig(
        renderShadows: true,
        obscureText: false,
      ),
    ),
    run: testMain,
  );
}
Enter fullscreen mode Exit fullscreen mode

Writing a Golden Test

Let’s write one widget to test before we start to write the Golden Test. We created a widget for this section displaying an NBA game schedule.

import 'package:flutter/material.dart';

class GameItem extends StatelessWidget {
  const GameItem({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(
        vertical: 15,
        horizontal: 20,
      ),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(10),
      ),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Expanded(
            child: Row(
              children: [
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: const [
                      Text(
                        'Boston Celtics',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.w400,
                        ),
                      ),
                      SizedBox(height: 15),
                      Text(
                        'Chicago Bulls',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.w400,
                        ),
                      ),
                    ],
                  ),
                ),
                const Expanded(
                  child: Center(
                    child: Text(
                      '08:00 PM',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.w600,
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Create a testGoldens test

With a widget to test the appearance, becomes easy to write a test. Use the goldenTest() function from the alchemist package to define one test, this function allows you to define a widget to test the appearance and the file name to generate the Golden File.

goldenTest(
  'displayed the basketball game',
  fileName: 'baskteball_game_widget',
  constraints: const BoxConstraints(
      maxWidth: 300,
  ),
  builder: () => const GameItem(),
);
Enter fullscreen mode Exit fullscreen mode

Generating the Golden File

It's time to generate the Golden File after writing the test using the goldenTest() function. You can execute the command below to generate the Golden File.

flutter test --update-goldens
Enter fullscreen mode Exit fullscreen mode

You may notice that the test directory has been updated with a new directory called goldens containing the Golden Files generated by the Golden Test, for example:

test/
    goldens/
        ci/
            - baskteball_game_widget.png
        macos/
            - baskteball_game_widget.png
Enter fullscreen mode Exit fullscreen mode

The golden tests generate the macos/ subdirectory because while I'm writing this article I'm using a MacOS operation system. Whether you are using Linux or Windows your golden tests will generate the subdirectory dealing with your operating system with subtle differences between the platforms.

Golden Test in continuous integration workflow

You may notice that the goldens/ directory also has the ci/ subdirectory. The ci/ subdirectory is generated to deal with the subtle differences in rendering between MacOS, Linux, and Windows platforms.

Enabling the continuous integration using —dart-define

To enable continuous integration environment is necessary to disable the tests locally. We can use the IS_CONTINUOUS_INTEGRATION environment declaration to identify when the tests are running on the continuous integration environment and obtain this value using the bool.fromEnvironment.

Go back to the flutter_test_config.dart in the test/ directory and update the prepareGoldenTests to obtain the IS_CONTINUOUS_INTEGRATION declaration and disables the tests locally when this value is true.

void prepareGoldenTests(FutureOr<void> Function() testMain) {
  const isContinuosIntegration = bool.fromEnvironment('IS_CONTINUOUS_INTEGRATION');

  return AlchemistConfig.runWithConfig(
    config: const AlchemistConfig(
      platformGoldensConfig: PlatformGoldensConfig(
        renderShadows: true,
        obscureText: false,
        enabled: isContinuosIntegration
      ),
    ),
    run: testMain,
  );
}
Enter fullscreen mode Exit fullscreen mode

Running tests using the —dart-define

Running the tests using the —-dart-define environment declaration is pretty simple. See the command below to run the tests for a continuous integration environment.

flutter test --dart-define=IS_CONTINUOUS_INTEGRATION=true
Enter fullscreen mode Exit fullscreen mode

Conclusion

The Golden Test is important for maintaining the code and the project's health. Sometimes, the standard Golden Test tool is insufficient to cover all cases possible; therefore, using the Alchemist tool gives developers a powerful tool to develop the appearance test and a way to use it in their continuous integration environments.

💖 💪 🙅 🚩
leonardorosaa
Leonardo Rosa

Posted on March 27, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related