refactor: create separate BLoCs for each screen with comprehensive tests

- Created 8 separate BLoCs (Home, Library, BookDetails, AddBook, Scanner, Categories, Wishlist, Settings)
- Each BLoC has its own event, state, and bloc files
- Added 70 comprehensive tests covering all BLoC functionality
- All tests passing (70/70)
- Fixed linting issues and updated deprecated APIs
- Improved code organization and maintainability
This commit is contained in:
Yuriy Panov
2026-02-04 14:40:00 +06:00
parent 3004f712f3
commit 310463e89a
177 changed files with 9718 additions and 0 deletions

View File

@@ -0,0 +1,178 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:bookshelf_flutter/bloc/add_book/add_book_bloc.dart';
import 'package:bookshelf_flutter/bloc/add_book/add_book_event.dart';
import 'package:bookshelf_flutter/bloc/add_book/add_book_state.dart';
import 'package:bookshelf_flutter/models/models.dart';
void main() {
group('AddBookBloc', () {
late AddBookBloc addBookBloc;
setUp(() {
addBookBloc = AddBookBloc();
});
tearDown(() {
addBookBloc.close();
});
test('initial state is AddBookState.initial()', () {
expect(addBookBloc.state, isA<AddBookState>());
expect(addBookBloc.state.isLoading, false);
});
group('InitializeForm', () {
test('initializes form with prefilled data', () async {
final prefilledData = {
'title': 'Test Book',
'author': 'Test Author',
'genre': 'Test Genre',
'annotation': 'Test annotation',
'coverUrl': 'https://example.com/cover.jpg',
'pages': 200,
'language': 'English',
'publishedYear': 2020,
'rating': 4.5,
'status': BookStatus.reading,
'progress': 50,
'isFavorite': true,
};
addBookBloc.add(InitializeForm(prefilledData));
await Future.delayed(Duration.zero);
expect(addBookBloc.state.title, 'Test Book');
expect(addBookBloc.state.author, 'Test Author');
expect(addBookBloc.state.genre, 'Test Genre');
expect(addBookBloc.state.isFavorite, true);
expect(addBookBloc.state.pages, 200);
});
test('initializes form with empty data when prefilledData is null', () async {
addBookBloc.add(const InitializeForm(null));
await Future.delayed(Duration.zero);
expect(addBookBloc.state.title, '');
expect(addBookBloc.state.author, '');
expect(addBookBloc.state.isFavorite, false);
});
});
group('UpdateFormField', () {
test('updates title field', () async {
addBookBloc.add(const UpdateFormField('title', 'New Title'));
await Future.delayed(Duration.zero);
expect(addBookBloc.state.title, 'New Title');
});
test('updates author field', () async {
addBookBloc.add(const UpdateFormField('author', 'New Author'));
await Future.delayed(Duration.zero);
expect(addBookBloc.state.author, 'New Author');
});
test('updates genre field', () async {
addBookBloc.add(const UpdateFormField('genre', 'New Genre'));
await Future.delayed(Duration.zero);
expect(addBookBloc.state.genre, 'New Genre');
});
test('updates pages field', () async {
addBookBloc.add(const UpdateFormField('pages', 300));
await Future.delayed(Duration.zero);
expect(addBookBloc.state.pages, 300);
});
test('updates rating field', () async {
addBookBloc.add(const UpdateFormField('rating', 4.8));
await Future.delayed(Duration.zero);
expect(addBookBloc.state.rating, 4.8);
});
test('updates status field', () async {
addBookBloc.add(const UpdateFormField('status', BookStatus.done));
await Future.delayed(Duration.zero);
expect(addBookBloc.state.status, BookStatus.done);
});
});
group('ToggleFavorite', () {
test('toggles isFavorite from false to true', () async {
expect(addBookBloc.state.isFavorite, false);
addBookBloc.add(const ToggleFavorite());
await Future.delayed(Duration.zero);
expect(addBookBloc.state.isFavorite, true);
});
test('toggles isFavorite from true to false', () async {
addBookBloc.add(const ToggleFavorite());
await Future.delayed(Duration.zero);
expect(addBookBloc.state.isFavorite, true);
addBookBloc.add(const ToggleFavorite());
await Future.delayed(Duration.zero);
expect(addBookBloc.state.isFavorite, false);
});
});
group('ClearForm', () {
test('clears all form fields', () async {
addBookBloc.add(const UpdateFormField('title', 'Test'));
addBookBloc.add(const UpdateFormField('author', 'Test'));
addBookBloc.add(const ToggleFavorite());
await Future.delayed(Duration.zero);
expect(addBookBloc.state.title, 'Test');
addBookBloc.add(const ClearForm());
await Future.delayed(Duration.zero);
expect(addBookBloc.state.title, '');
expect(addBookBloc.state.author, '');
expect(addBookBloc.state.isFavorite, false);
});
});
group('SubmitBook', () {
test('creates book with form data and sets isSubmitted to true', () async {
addBookBloc.add(const UpdateFormField('title', 'New Book'));
addBookBloc.add(const UpdateFormField('author', 'New Author'));
addBookBloc.add(const UpdateFormField('genre', 'New Genre'));
addBookBloc.add(const UpdateFormField('annotation', 'New annotation'));
addBookBloc.add(const UpdateFormField('pages', 200));
addBookBloc.add(const UpdateFormField('language', 'English'));
addBookBloc.add(const UpdateFormField('publishedYear', 2023));
addBookBloc.add(const UpdateFormField('rating', 4.5));
addBookBloc.add(const UpdateFormField('status', BookStatus.wantToRead));
addBookBloc.add(const UpdateFormField('progress', 0));
await Future.delayed(Duration.zero);
addBookBloc.add(const SubmitBook());
await Future.delayed(Duration.zero);
expect(addBookBloc.state.isSubmitted, true);
expect(addBookBloc.state.submittedBook?.title, 'New Book');
expect(addBookBloc.state.submittedBook?.author, 'New Author');
});
test('uses default values for empty fields', () async {
addBookBloc.add(const SubmitBook());
await Future.delayed(Duration.zero);
expect(addBookBloc.state.submittedBook?.title, 'Unknown');
expect(addBookBloc.state.submittedBook?.author, 'Unknown');
expect(addBookBloc.state.submittedBook?.genre, 'Unknown');
expect(addBookBloc.state.submittedBook?.coverUrl?.isNotEmpty, true);
});
});
});
}