Prime-Holding / rx_bloc

A set of Flutter packages that help implement the BloC (Business Logic Component) design pattern using the power of reactive streams
https://pub.dev/packages/rx_bloc
62 stars 21 forks source link

Exclude dependencies from the smart widgets in the golden test #700

Closed StanevPrime closed 1 day ago

StanevPrime commented 3 months ago

As a developer I want when the widget tree is built during the golden tests execution the dependencies of smart widgets such as BloCs, Services etc to be not added to the widget tree so that I can add them as mock objects

ACs

Reference implementation:

class AppTodoListBulkEditPopupMenuButtonWithDependencies {
    @override
    Widget build(BuildContext context) {
        final current =  TodoManagementPage();

        if(isInTestMode) {
            return current;
        }

        return MultiProvider(
            providers: [
              ..._services,
              ..._blocs,
           ],
           child: current,
        );
  }
}

Option 1: flutter_test_config.dart

import 'package:procredit/base/app/config/app_constants.dart';
...

Future<void> testExecutable(FutureOr<void> Function() testMain) async =>
    GoldenToolkit.runWithConfiguration(
      () async {
        WidgetsApp.debugAllowBannerOverride = false;
        isInTestMode = true;
        await loadAppFonts();
        return testMain();
      },
      config: GoldenToolkitConfiguration(
        enableRealShadows: true,
      ),
    );

Option 2

is_in_test_mode_io_available.dart

bool isInTestMode = io.Platform.environment.containsKey('FLUTTER_TEST');

is_in_test_mode_io_not_available.dart

bool isInTestMode = false;

app_constants.dart

import 'is_in_test_mode.dart' if (dart.io) 'is_in_test_mode_io_available.dart' if (dart.library.html) 'is_in_test_mode_io_not_available.dart';

Documentation: https://dart.dev/guides/libraries/create-packages#conditionally-importing-and-exporting-library-files

Option 3

Define a variable in the test run command and have it as a global constant with default value in the app,

app_constants.dart

import 'dart:io' as io;

// Global flag for test mode
bool isInTestMode = bool.fromEnvironment('testing_mode', defaultValue: false);

Run All Tests configuration arguments

--dart-define=testing_mode=true

Refferance: https://stackoverflow.com/a/63723815

Option 4

Platform.environment.containsKey('FLUTTER_TEST'); is a boolean that returns true when it's executed by a test and false otherwise. To work on Web, iOS and Android, it should be imported from universal_io/io.dart .It is tested on mobile and web and it works with universal_io: ^2.2.2

DDavidPrime commented 3 months ago

This could also help with the test checking: https://stackoverflow.com/questions/59028609/how-to-find-if-we-are-running-unit-test-in-dart-flutter

nikolay-vasilev-prime commented 3 months ago

Platform.environment.containsKey('FLUTTER_TEST'); is a boolean that returns true when it's executed by a test and false otherwise. To work on Web, iOS and Android, it should be imported from universal_io/io.dart . I tested it on mobile and web and it works with universal_io: ^2.2.2, which is the latest version for now. From this comment it looks like it wasn't working on previous versions.

So the Option 2 with global variable is a good option.

I discovered that if multiple pages/widgets implement the same type of widget with *WithDependencies, they share same instance of the widget and they don't if initialize it with the class without the dependencies.

StanevPrime commented 3 months ago

Adding an extra dependency (universal_io) is not a good option from my perspective, since it increases the maintenance cost of the rx_bloc_cli.

StanevPrime commented 3 months ago

It was decided to proceed with the option 2 based on the following benefits:

@DDavidPrime, @nikolay-vasilev-prime