repoServiceBlocEventGroupTestUtil<Bloc extends RepoServiceBloc<GroupEvent>, GroupEvent extends Enum, DataType, ExecutorParams> function

Future<void> repoServiceBlocEventGroupTestUtil<Bloc extends RepoServiceBloc<GroupEvent>, GroupEvent extends Enum, DataType, ExecutorParams>(
  1. Bloc repoServiceBlocFn(), {
  2. ExecutorParams? eventParams,
  3. String? eventKey,
  4. required GroupEvent groupEvent,
  5. required RepoServiceStubDefinition stub,
  6. void setUp(
    1. Bloc bloc
    )?,
  7. void verifier(
    1. List<RepoServiceBlocState<GroupEvent>> states,
    2. Either<Failure, DataType?>? executorResult
    )?,
  8. TypeMatcher<BaseRequest>? requestMatcher,
})

Example

void main() {
  late ExampleRepoServiceBloc repoServiceBloc;
  setUp(() {
    GetIt.instance.registerSingleton<IHttpClient>(HttpClientMock());
    repoServiceBloc = ExampleRepoServiceBloc();
  });
  test("$ExampleRepoServiceBloc test ${ExampleEvent.one}", () async {
    final String responseFixture = fixture("modules/utils/repo_service_bloc_example_response.json");
    await repoServiceBlocEventGroupTestUtil<ExampleRepoServiceBloc, ExampleEvent, List<ExampleModel>>(
      () => repoServiceBloc,
      groupEvent: ExampleEvent.one,
      stub: RepoServiceStubDefinition.httpStub(
        responseStubValue: responseFixture,
      ),
      verifier: (states) {
        expect(
          states,
          contains(
            const TypeMatcher<RepoServiceBlocState<ExampleEvent>>().having(
              (state) => state.data[ExampleEvent.one],
              "ExampleEvent.one",
              const TypeMatcher<LoadedData<List<ExampleModel>>>().having(
                (p0) => p0.data,
                "data",
                isA<Right<Failure, List<ExampleModel>>>(),
              ),
            ),
          ),
        );
      },
    );
  });
}
enum ExampleEvent {
  one,
  second,
}
final mockUri = Uri.parse("https:///google.com");
List<ExampleModel> responseParser(String response) {
  final data = jsonDecode(response);
  List items = data["data"];
  return items.map((e) {
    return ExampleModel.fromMap(e);
  }).toList();
}
class ExampleRepoServiceBloc extends RepoServiceBloc<ExampleEvent> {
  ExampleRepoServiceBloc()
      : super(
          logger: null,
          configurations: Map<ExampleEvent, RepoServiceConfiguration>.of({
            ExampleEvent.one: BasicHttpRequestRepoServiceConfiguration<List<ExampleModel>>(
              method: "POST",
              uri: (_) => mockUri,
              responseParser: responseParser,
              initialState: LoadedData<List<ExampleModel>>(),
            ),
          }),
        );
}

Implementation

///   setUp(() {
///     GetIt.instance.registerSingleton<IHttpClient>(HttpClientMock());

///     repoServiceBloc = ExampleRepoServiceBloc();
///   });

///   test("$ExampleRepoServiceBloc test ${ExampleEvent.one}", () async {
///     final String responseFixture = fixture("modules/utils/repo_service_bloc_example_response.json");

///     await repoServiceBlocEventGroupTestUtil<ExampleRepoServiceBloc, ExampleEvent, List<ExampleModel>>(
///       () => repoServiceBloc,
///       groupEvent: ExampleEvent.one,
///       stub: RepoServiceStubDefinition.httpStub(
///         responseStubValue: responseFixture,
///       ),
///       verifier: (states) {
///         expect(
///           states,
///           contains(
///             const TypeMatcher<RepoServiceBlocState<ExampleEvent>>().having(
///               (state) => state.data[ExampleEvent.one],
///               "ExampleEvent.one",
///               const TypeMatcher<LoadedData<List<ExampleModel>>>().having(
///                 (p0) => p0.data,
///                 "data",
///                 isA<Right<Failure, List<ExampleModel>>>(),
///               ),
///             ),
///           ),
///         );
///       },
///     );
///   });
/// }

/// enum ExampleEvent {
///   one,
///   second,
/// }

/// final mockUri = Uri.parse("https:///google.com");

/// List<ExampleModel> responseParser(String response) {
///   final data = jsonDecode(response);

///   List items = data["data"];

///   return items.map((e) {
///     return ExampleModel.fromMap(e);
///   }).toList();
/// }

/// class ExampleRepoServiceBloc extends RepoServiceBloc<ExampleEvent> {
///   ExampleRepoServiceBloc()
///       : super(
///           logger: null,
///           configurations: Map<ExampleEvent, RepoServiceConfiguration>.of({
///             ExampleEvent.one: BasicHttpRequestRepoServiceConfiguration<List<ExampleModel>>(
///               method: "POST",
///               uri: (_) => mockUri,
///               responseParser: responseParser,
///               initialState: LoadedData<List<ExampleModel>>(),
///             ),
///           }),
///         );
/// }
/// ```
/// {@endtemplate}
Future<void> repoServiceBlocEventGroupTestUtil<Bloc extends RepoServiceBloc<GroupEvent>, GroupEvent extends Enum,
    DataType, ExecutorParams>(
  Bloc Function() repoServiceBlocFn, {
  ExecutorParams? eventParams,
  String? eventKey,
  required GroupEvent groupEvent,
  required RepoServiceStubDefinition stub,
  void Function(Bloc bloc)? setUp,
  void Function(List<RepoServiceBlocState<GroupEvent>> states, Either<Failure, DataType?>? executorResult)? verifier,
  TypeMatcher<BaseRequest>? requestMatcher,
  // // /// [act] This lets you define a custom executor trigger, this is useful when you try to dispatch your event
  // // /// with custom parameters
  // // required void Function(Bloc bloc) act,
}) async {
  Bloc repoServiceBloc = repoServiceBlocFn();

  // validate if exists EventGroupConfig
  RepoServiceConfiguration? configuration = repoServiceBloc.configurations[groupEvent];

  List<RepoServiceBlocState<GroupEvent>> states = [];

  StreamSubscription _subscription = repoServiceBloc.stream.listen((state) {
    states.add(state);
  });

  if (configuration == null) {
    throw ConfigurationNotDefinedForGroup(groupEvent);
  }

  Either<Failure, DataType?>? executorResult;

  BaseRequest? eventRequest;

  await configuration.map(
    basicHttpRequest: (basicHttpRequestConfig) async {
      if (stub is! _HttpStub) {
        throw InvalidStubbingDefinition(_HttpStub, groupEvent);
      }
      if (repoServiceBloc.blocRepoServiceImpl.client is! HttpClientMock) {
        throw InvalidHttpClientMock();
      }

      await repoServiceTestHttpUtil<RepoServiceBase, DataType>(
        () => repoServiceBloc.blocRepoServiceImpl,
        setUp: (clientMock) {
          setUp?.call(repoServiceBloc);
        },
        act: (_) async {
          repoServiceBloc.execute(
            groupEvent,
            params: eventParams,
            key: eventKey,
          );
          return repoServiceBloc.events().firstWhere((event) {
            return event.map(
              actorExecutor: (actorExecutor) {
                return false;
              },
              actorResult: (actorResult) {
                return actorResult.executor.group == groupEvent;
              },
            );
          }).then((value) {
            return value.mapOrNull(
              actorResult: (value) {
                return value.result;
              },
              actorExecutor: null,
            ) as Either<Failure, DataType>;
          });
        },
        verify: (client, response) async {
          verify(
            client.send(
              argThat(
                requestMatcher ??
                    const TypeMatcher<Request>().having(
                      (r) {
                        return r.toString();
                      },
                      "url",
                      contains(
                        basicHttpRequestConfig.uri(eventParams).toString(),
                      ),
                    ).having(
                      (r) {
                        return r.method;
                      },
                      "method",
                      basicHttpRequestConfig.method,
                    ),
              ),
            ),
          );
          expect(response, isA<Either<Failure, DataType>>());
          executorResult = response;
        },
        responseStubValue: stub.responseStubValue,
        statusCodeStubValue: stub.statusCodeStubValue,
        headersStubValue: stub.headersStubValue,
      );
    },
    httpFromBaseRequest: (httpFromBaseRequestConfig) async {
      if (stub is! _HttpStub) {
        throw InvalidStubbingDefinition(_HttpStub, groupEvent);
      }
      if (repoServiceBloc.blocRepoServiceImpl.client is! HttpClientMock) {
        throw InvalidHttpClientMock();
      }

      await repoServiceTestHttpUtil<RepoServiceBase, DataType>(
        () => repoServiceBloc.blocRepoServiceImpl,
        setUp: (clientMock) {
          setUp?.call(repoServiceBloc);
        },
        act: (_) {
          repoServiceBloc.execute(
            groupEvent,
            params: eventParams,
            key: eventKey,
          );
          return repoServiceBloc.events().firstWhere((event) {
            return event.map(
              actorExecutor: (actorExecutor) {
                return false;
              },
              actorResult: (actorResult) {
                return actorResult.executor.group == groupEvent;
              },
            );
          }).then((value) {
            return value.mapOrNull(
              actorResult: (value) {
                return value.result;
              },
              actorExecutor: null,
            ) as Either<Failure, DataType>;
          });
        },
        verify: (client, response) async {
          eventRequest = await httpFromBaseRequestConfig.request(eventParams);
          verify(
            client.send(
              argThat(
                requestMatcher ??
                    const TypeMatcher<BaseRequest>()
                        .having(
                          (p0) => p0.method,
                          "Request Method",
                          eventRequest!.method,
                        )
                        .having(
                          (p0) => p0.url.toString(),
                          "Request Uri",
                          eventRequest!.url.toString(),
                        ),
              ),
            ),
          ).called(1);
          expect(response, isA<Either<Failure, DataType>>());
          executorResult = response;
        },
        responseStubValue: stub.responseStubValue,
        statusCodeStubValue: stub.statusCodeStubValue,
        headersStubValue: stub.headersStubValue,
      );
    },
    generic: (genericConfig) async {
      if (stub is! _GenericStub) {
        throw InvalidStubbingDefinition(_GenericStub, groupEvent);
      }
      if (repoServiceBloc.blocRepoServiceImpl.client is! HttpClientMock) {
        throw InvalidHttpClientMock();
      }

      await repoServiceTestGenericUtil<RepoServiceBase, DataType>(
        () => repoServiceBloc.blocRepoServiceImpl,
        setUp: () {
          stub.setUp(eventParams);
        },
        act: (_) {
          repoServiceBloc.execute(
            groupEvent,
            params: eventParams,
            key: eventKey,
          );
          return repoServiceBloc.events().firstWhere((event) {
            return event.map(
              actorExecutor: (actorExecutor) {
                return false;
              },
              actorResult: (actorResult) {
                return actorResult.executor.group == groupEvent;
              },
            );
          }).then((value) {
            return value.mapOrNull(
              actorResult: (value) {
                return value.result;
              },
              actorExecutor: null,
            ) as Either<Failure, DataType>;
          });
        },
        verify: (result) {
          expect(result, isA<Either<Failure, DataType>>());
          executorResult = result;
        },
      );
    },
  );

  await Future.delayed(const Duration(milliseconds: 10));
  verifier?.call(states, executorResult);

  _subscription.cancel();
}