import 'package:flutter_test/flutter_test.dart'; import 'package:bookshelf_flutter/bloc/library/library_bloc.dart'; import 'package:bookshelf_flutter/bloc/library/library_event.dart'; import 'package:bookshelf_flutter/bloc/library/library_state.dart'; import 'package:bookshelf_flutter/models/models.dart'; void main() { group('LibraryBloc', () { late LibraryBloc libraryBloc; setUp(() { libraryBloc = LibraryBloc(); }); tearDown(() { libraryBloc.close(); }); test('initial state is LibraryState.initial()', () { expect(libraryBloc.state, isA()); expect(libraryBloc.state.isLoading, true); }); group('LoadBooks', () { test('emits [LibraryState] with books when LoadBooks is added', () async { final expected = [ isA() .having((state) => state.isLoading, 'isLoading', false) .having((state) => state.books.isNotEmpty, 'books.isNotEmpty', true), ]; expectLater(libraryBloc.stream, emitsInOrder(expected)); libraryBloc.add(const LoadBooks()); }); }); group('SearchBooks', () { test('filters books by title', () async { libraryBloc.add(const LoadBooks()); await Future.delayed(Duration.zero); libraryBloc.add(const SearchBooks('Гэтсби')); await Future.delayed(Duration.zero); expect(libraryBloc.state.filteredBooks.length, 1); expect(libraryBloc.state.filteredBooks.first.title, contains('Гэтсби')); }); test('filters books by author', () async { libraryBloc.add(const LoadBooks()); await Future.delayed(Duration.zero); libraryBloc.add(const SearchBooks('Оруэлл')); await Future.delayed(Duration.zero); expect(libraryBloc.state.filteredBooks.length, 1); expect(libraryBloc.state.filteredBooks.first.author, contains('Оруэлл')); }); test('filters books by genre', () async { libraryBloc.add(const LoadBooks()); await Future.delayed(Duration.zero); libraryBloc.add(const SearchBooks('Fantasy')); await Future.delayed(Duration.zero); expect(libraryBloc.state.filteredBooks.isNotEmpty, true); }); test('returns empty list when no matches found', () async { libraryBloc.add(const LoadBooks()); await Future.delayed(Duration.zero); libraryBloc.add(const SearchBooks('NonExistent')); await Future.delayed(Duration.zero); expect(libraryBloc.state.filteredBooks.length, 0); }); }); group('BookSelected', () { test('updates selectedBook in state', () async { libraryBloc.add(const LoadBooks()); await Future.delayed(Duration.zero); final book = libraryBloc.state.books.first; libraryBloc.add(BookSelected(book)); await Future.delayed(Duration.zero); expect(libraryBloc.state.selectedBook?.id, book.id); }); }); group('FilterByStatus', () { test('filters books by status', () async { libraryBloc.add(const LoadBooks()); await Future.delayed(Duration.zero); libraryBloc.add(const FilterByStatus(BookStatus.reading)); await Future.delayed(Duration.zero); expect(libraryBloc.state.filteredBooks.every((book) => book.status == BookStatus.reading), true); expect(libraryBloc.state.statusFilter, BookStatus.reading); }); }); group('ClearFilters', () { test('clears search query and shows all books', () async { libraryBloc.add(const LoadBooks()); await Future.delayed(Duration.zero); libraryBloc.add(const SearchBooks('test')); await Future.delayed(Duration.zero); libraryBloc.add(const ClearFilters()); await Future.delayed(Duration.zero); expect(libraryBloc.state.searchQuery, ''); expect(libraryBloc.state.filteredBooks.length, libraryBloc.state.books.length); }); }); }); }