bloc_one_shot_test 0.1.0 copy "bloc_one_shot_test: ^0.1.0" to clipboard
bloc_one_shot_test: ^0.1.0 copied to clipboard

Test utilities for bloc_one_shot. Provides blocEffectTest() helper that mirrors blocTest() API with added effect verification.

bloc_one_shot_test #

pub package License: MIT

Test utilities for bloc_one_shot. Provides a blocEffectTest helper that mirrors the blocTest API with added effect verification.

Installation #

dev_dependencies:
  bloc_one_shot_test: ^0.1.0

Usage #

blocEffectTest #

A test helper for Blocs and Cubits that use SideEffectMixin. It verifies both state emissions and side effect emissions in a single test.

import 'package:bloc_one_shot_test/bloc_one_shot_test.dart';

blocEffectTest<LoginCubit, LoginState, LoginEffect>(
  'emits [Loading, Success] and NavigateToHome on login',
  build: () => LoginCubit(authRepo: mockAuthRepo),
  act: (cubit) => cubit.login('user@example.com', 'password'),
  expect: () => [
    isA<LoginLoading>(),
    isA<LoginSuccess>(),
  ],
  expectEffects: () => [
    isA<NavigateToHome>(),
  ],
);

Parameters #

Parameter Type Required Description
description String Yes Test description
build B Function() Yes Factory that creates the Bloc/Cubit under test
act FutureOr<void> Function(B)? No Interaction with the Bloc/Cubit (add events, call methods)
wait Duration? No Additional wait time for async operations
skipStates int No Number of initial state emissions to skip (default: 0)
skipEffects int No Number of initial effect emissions to skip (default: 0)
expect dynamic Function()? No Expected states — same as blocTest
expectEffects dynamic Function()? No Expected side effects
verify FutureOr<void> Function(B)? No Additional verification after the test
setUp FutureOr<void> Function()? No Setup callback before the test
tearDown FutureOr<void> Function()? No Teardown callback after the test

Examples #

Verify only effects (no state change)

blocEffectTest<AuthCubit, AuthState, AuthEffect>(
  'emits ShowErrorSnackbar when login fails',
  build: () => AuthCubit(authRepo: failingMockRepo),
  act: (cubit) => cubit.login('bad@email.com', 'wrong'),
  expect: () => [isA<AuthLoading>(), isA<AuthInitial>()],
  expectEffects: () => [isA<ShowErrorSnackbar>()],
);

Verify no effects were emitted

blocEffectTest<CounterCubit, int, CounterEffect>(
  'does not emit effects on normal increment',
  build: () => CounterCubit(),
  act: (cubit) => cubit.increment(),
  expect: () => [1],
  expectEffects: () => <CounterEffect>[],
);

Skip initial emissions

blocEffectTest<CounterBloc, int, CounterEffect>(
  'only checks the last state after 3 increments',
  build: () => CounterBloc(),
  act: (bloc) {
    bloc.add(Increment());
    bloc.add(Increment());
    bloc.add(Increment());
  },
  wait: const Duration(milliseconds: 50),
  skipStates: 2,
  expect: () => [3],
);

With setUp, tearDown, and verify

blocEffectTest<AuthCubit, AuthState, AuthEffect>(
  'navigates to home on successful login',
  setUp: () {
    // Prepare mocks, test fixtures, etc.
    when(() => mockRepo.login(any(), any())).thenAnswer((_) async {});
  },
  build: () => AuthCubit(authRepo: mockRepo),
  act: (cubit) => cubit.login('test@test.com', 'password'),
  expectEffects: () => [isA<NavigateToHome>()],
  verify: (cubit) {
    verify(() => mockRepo.login('test@test.com', 'password')).called(1);
  },
  tearDown: () {
    // Clean up resources
  },
);

Works with both Bloc and Cubit

// Bloc
blocEffectTest<LoginBloc, LoginState, LoginEffect>(
  'Bloc: emits NavigateToHome',
  build: () => LoginBloc(),
  act: (bloc) => bloc.add(LoginRequested(email: 'a', password: 'b')),
  expectEffects: () => [isA<NavigateToHome>()],
);

// Cubit
blocEffectTest<LoginCubit, LoginState, LoginEffect>(
  'Cubit: emits NavigateToHome',
  build: () => LoginCubit(),
  act: (cubit) => cubit.login('a', 'b'),
  expectEffects: () => [isA<NavigateToHome>()],
);

Async operations with wait

For Blocs with async event handlers, use wait to allow time for operations to complete:

blocEffectTest<AuthBloc, AuthState, AuthEffect>(
  'handles async login with network delay',
  build: () => AuthBloc(authRepo: slowMockRepo),
  act: (bloc) => bloc.add(LoginRequested(email: 'a', password: 'b')),
  wait: const Duration(milliseconds: 300),
  expect: () => [isA<AuthLoading>(), isA<AuthSuccess>()],
  expectEffects: () => [isA<NavigateToHome>()],
);

How It Works #

blocEffectTest creates a test that:

  1. Calls setUp (if provided)
  2. Builds the Bloc/Cubit via build()
  3. Subscribes to both bloc.stream (states) and bloc.effects (side effects)
  4. Calls act to interact with the Bloc/Cubit
  5. Waits for the specified wait duration (or two microtask cycles by default)
  6. Asserts collected states against expect
  7. Asserts collected effects against expectEffects
  8. Calls verify for additional assertions
  9. Closes the Bloc/Cubit
  10. Calls tearDown (if provided)

Comparison with blocTest #

Feature blocTest blocEffectTest
Verify states expect expect
Verify effects N/A expectEffects
Skip states skip skipStates
Skip effects N/A skipEffects
setUp / tearDown Yes Yes
verify Yes Yes
wait Yes Yes

License #

MIT — see LICENSE for details.

1
likes
150
points
111
downloads

Publisher

verified publisheraltumstack.com

Weekly Downloads

Test utilities for bloc_one_shot. Provides blocEffectTest() helper that mirrors blocTest() API with added effect verification.

Homepage
Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

bloc, bloc_one_shot, diff_match_patch, meta, test

More

Packages that depend on bloc_one_shot_test