Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Is there a way to test between 2 cubit that communicate on parent cubit? #3807

Closed
masfranzhuo opened this issue May 5, 2023 · 3 comments
Assignees
Labels
needs repro info The issue is missing a reproduction sample and/or steps question Further information is requested

Comments

@masfranzhuo
Copy link

Description

So, I have 2 cubits: CategoryCubit and ProductCubit. Then I added one cubit on top of that. It working fine, but just can't fond a way to test it.

Here the code:

class CategoryCubit extends Cubit<CategoryState> {
  CategoryCubit() : super(const CategoryState.initial());

  void selectCategory({required CategoryEntity category}) async {
    if (state is Loaded) {
      emit(CategoryState.loaded(selectedCategory: category));
    }
  }
}
class ProductCubit extends Cubit<ProductState> {
  ProductCubit({required FetchProducts fetchProducts})
      : _fetchProducts = fetchProducts,
        super(const ProductState.initial());

  final FetchProducts _fetchProducts;

  Future<void> fetchProducts({
    String? categoryId,
    int limit = 10,
    int page = 1,
    String? searchText,
  }) async {
    emit(const Loading());

    final result = await _fetchProducts(
      categoryId: categoryId,
      limit: limit,
      page: page,
      searchText: searchText,
    );
    result.fold(
      (error) => emit(Error(error: error)),
      (products) => emit(Loaded(products: products.data)),
    );
  }
}
class CategoryProductIntegrationCubit extends Cubit<CategoryProductIntegrationState> {
  final product.ProductCubit productCubit;
  final category.CategoryCubit categoryCubit;

  late StreamSubscription categoryStreamSubscription;

  CategoryProductIntegrationCubit({
    required this.productCubit,
    required this.categoryCubit,
  }) : super(const _Initial()) {
    categoryStreamSubscription = categoryCubit.stream.listen((state) {
      if (state is category.Loaded) {
        if (state.selectedCategory != null) {
          productCubit.fetchProducts(categoryId: state.selectedCategory!.id);
        }
      }
    });
  }
}
@masfranzhuo masfranzhuo changed the title test: Is there a way to test between 2 cubit that communicate on intergration cubit? test: Is there a way to test between 2 cubit that communicate on parent cubit? May 5, 2023
@felangel
Copy link
Owner

felangel commented May 5, 2023

Hi @masfranzhuo 👋
Thanks for opening an issue!

You can test the CategoryProductIntegrationCubit by injecting a MockCubit for productCubit and categoryCubit respectively. Then you can stub the categoryCubit stream using whenListen from package:bloc_test and verify that productCubit.fetchProducts is called with the correct id.

Hope that helps!

@felangel felangel added question Further information is requested waiting for response Waiting for follow up labels May 5, 2023
@felangel felangel self-assigned this May 5, 2023
@masfranzhuo
Copy link
Author

masfranzhuo commented May 5, 2023

Hi @masfranzhuo 👋 Thanks for opening an issue!

You can test the CategoryProductIntegrationCubit by injecting a MockCubit for productCubit and categoryCubit respectively. Then you can stub the categoryCubit stream using whenListen from package:bloc_test and verify that productCubit.fetchProducts is called with the correct id.

Hope that helps!

Hello @felangel , I have tried the approach and found error when running the test, is something I do wrong?

void main() {
  late CategoryProductIntegrationCubit cubit;
  late MockProductCubit mockProductCubit;
  late MockCategoryCubit mockCategoryCubit;

  setUp(() {
    mockProductCubit = MockProductCubit();
    mockCategoryCubit = MockCategoryCubit();

    cubit = CategoryProductIntegrationCubit(
      productCubit: mockProductCubit,
      categoryCubit: mockCategoryCubit,
    );
  });

  test('emits _Initial state initially', () {
    expect(cubit.state, const CategoryProductIntegrationState.initial());
  });

  test('should verify fetch product, when category changes', () {
    whenListen(
      mockCategoryCubit,
      Stream.fromIterable(
        [
          const CategoryState.loaded(categories: []),
          const CategoryState.loaded(
            selectedCategory: CategoryEntity(id: 'anyId', name: 'anyName'),
            categories: [],
          ),
        ],
      ),
    );

    cubit.categoryCubit.selectCategory(
      category: const CategoryEntity(id: 'anyId', name: 'anyName'),
    );

    verify(() => mockProductCubit.fetchProducts(categoryId: 'anyId'));
  });
}

the error in console:

No matching calls (actually, no calls at all).
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
package:test_api                                                                                                              fail

@felangel
Copy link
Owner

felangel commented Aug 5, 2023

Hi @masfranzhuo 👋
Sounds like you're running into something similar to felangel/mocktail#204. If you're still having trouble could you please share a link to a minimal reproduction sample and I'm happy to take a closer look, thanks! 🙏

@felangel felangel added the needs repro info The issue is missing a reproduction sample and/or steps label Aug 5, 2023
@felangel felangel removed the waiting for response Waiting for follow up label Sep 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs repro info The issue is missing a reproduction sample and/or steps question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants