feat(post_creation): added multiple image posts creation and validation

This commit is contained in:
misha
2026-08-04 17:47:43 +03:00
parent 3210f38d4a
commit 04de956769
21 changed files with 2791 additions and 982 deletions

View File

@@ -11,6 +11,7 @@ import 'package:eatvio_app/features/blog_post_create/presentation/pages/blog_pos
import 'package:eatvio_app/features/blog_post_create/repositories/blog_post_repository.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
import 'package:eatvio_app/features/feed/models/post_feed_pagination_model.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart';
import 'package:eatvio_app/generated/l10n.dart';
@@ -19,14 +20,15 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:mocktail/mocktail.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:network_image_mock/network_image_mock.dart';
import 'blog_post_create_screen_test.mocks.dart';
class MockBlogPostRepository extends Mock implements BlogPostRepository {}
class MockFeedCubit extends Mock implements FeedCubit {}
@GenerateMocks([BlogPostRepository, BlogPostCreateCubit, FeedCubit])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@@ -37,13 +39,22 @@ void main() {
setUp(() async {
await sl.reset();
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
dotenv.loadFromString(
envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost',
);
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
registerFallbackValue(<XFile>[]);
registerFallbackValue(<int>[]);
mockBlogPostRepository = MockBlogPostRepository();
blogPostCreateCubit = BlogPostCreateCubit(blogPostRepository: mockBlogPostRepository);
blogPostCreateCubit = BlogPostCreateCubit(
blogPostRepository: mockBlogPostRepository,
);
mockFeedCubit = MockFeedCubit();
when(mockFeedCubit.state).thenReturn(const FeedState.loading());
when(mockFeedCubit.stream).thenAnswer((_) => Stream.value(const FeedState.loading()));
when(() => mockFeedCubit.state).thenReturn(const FeedState.loading());
when(
() => mockFeedCubit.stream,
).thenAnswer((_) => Stream.value(const FeedState.loading()));
when(() => mockFeedCubit.loadFeedBlogPostList()).thenAnswer((_) async {});
sl.registerLazySingleton<FeedCubit>(() => mockFeedCubit);
sl.registerLazySingleton<BlogPostCreateCubit>(() => blogPostCreateCubit);
});
@@ -52,19 +63,25 @@ void main() {
blogPostCreateCubit.close();
});
Widget createTestWidget({FeedBlogPostModel? feedBlogPostModel, bool canPop = false}) {
Widget createTestWidget({
FeedBlogPostModel? feedBlogPostModel,
bool canPop = false,
}) {
final router = GoRouter(
initialLocation: '/blog-post-create',
routes: [
GoRoute(
path: '/home',
builder: (context, state) => const Scaffold(body: Center(child: Text('Home'))),
builder: (context, state) =>
const Scaffold(body: Center(child: Text('Home'))),
),
GoRoute(
path: '/blog-post-create',
builder: (context, state) => MultiBlocProvider(
providers: [
BlocProvider<BlogPostCreateCubit>.value(value: blogPostCreateCubit),
BlocProvider<BlogPostCreateCubit>.value(
value: blogPostCreateCubit,
),
BlocProvider<FeedCubit>.value(value: mockFeedCubit),
],
child: BlogPostCreateScreen(feedBlogPostModel: feedBlogPostModel),
@@ -87,28 +104,46 @@ void main() {
);
}
testWidgets('displays all form fields when creating new blog post', (tester) async {
testWidgets('displays all form fields when creating new blog post', (
tester,
) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
expect(find.text('Заголовок'), findsOneWidget);
expect(find.text('Описание'), findsOneWidget);
expect(find.text('Изображение поста'), findsOneWidget);
expect(find.textContaining('Изображения'), findsOneWidget);
expect(find.text('Ссылка на видео'), findsOneWidget);
expect(find.byKey(AppKeys.blogPostCreateScreenTitleTextField), findsOneWidget);
expect(find.byKey(AppKeys.blogPostCreateScreenContentTextField), findsOneWidget);
expect(find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField), findsOneWidget);
expect(
find.byKey(AppKeys.blogPostCreateScreenTitleTextField),
findsOneWidget,
);
expect(
find.byKey(AppKeys.blogPostCreateScreenContentTextField),
findsOneWidget,
);
expect(
find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField),
findsOneWidget,
);
});
testWidgets('pre-fills form fields when editing existing blog post', (tester) async {
testWidgets('pre-fills form fields when editing existing blog post', (
tester,
) async {
final existingPost = FeedBlogPostModel(
id: 1,
title: 'Test Title',
description: 'Test Description',
videoUrl: 'https://youtube.com/watch?v=test',
image: '', // Changed: removed image so video field is visible
videoUrl: 'https://rutube.ru/video/12345/',
image: '',
state: 'published',
author: const Author(authorSlug: 'test-author', authorName: 'Test Author', authorProfileIcon: 'avatar.jpg', authorIsMe: true),
author: const Author(
authorSlug: 'test-author',
authorName: 'Test Author',
authorProfileIcon: 'avatar.jpg',
authorIsMe: true,
),
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
totalLikes: 0,
@@ -117,24 +152,299 @@ void main() {
wasLikedByMe: false,
);
await tester.pumpWidget(createTestWidget(feedBlogPostModel: existingPost));
await tester.pumpWidget(
createTestWidget(feedBlogPostModel: existingPost),
);
await tester.pumpAndSettle();
final titleField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenTitleTextField));
final titleField = tester.widget<CustomTextFormField>(
find.byKey(AppKeys.blogPostCreateScreenTitleTextField),
);
expect(titleField.controller?.text, 'Test Title');
final descriptionField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenContentTextField));
final descriptionField = tester.widget<CustomTextFormField>(
find.byKey(AppKeys.blogPostCreateScreenContentTextField),
);
expect(descriptionField.controller?.text, 'Test Description');
final videoFieldFinder = find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField);
if (videoFieldFinder.evaluate().isNotEmpty) {
final videoField = tester.widget<CustomTextFormField>(videoFieldFinder);
expect(videoField.controller?.text, 'https://youtube.com/watch?v=test');
}
final videoField = tester.widget<CustomTextFormField>(
find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField),
);
expect(videoField.controller?.text, 'https://rutube.ru/video/12345/');
expect(find.text('Сохранить'), findsOneWidget);
});
testWidgets('hides video field when image is present', (tester) async {
testWidgets('shows video and gallery fields together', (tester) async {
await mockNetworkImagesFor(() async {
final existingPost = FeedBlogPostModel(
id: 1,
title: 'Test Title',
description: 'Test Description',
videoUrl: 'https://rutube.ru/video/12345/',
image: 'http://localhost/storage/test_image.jpg',
state: 'published',
author: const Author(
authorSlug: 'test-author',
authorName: 'Test Author',
authorProfileIcon: 'http://localhost/storage/avatar.jpg',
authorIsMe: true,
),
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
totalLikes: 0,
totalViews: 0,
totalComments: 0,
wasLikedByMe: false,
images: const [
FeedGalleryImage(
id: 10,
url: 'http://localhost/storage/test_image.jpg',
),
],
);
await tester.pumpWidget(
createTestWidget(feedBlogPostModel: existingPost),
);
await tester.pumpAndSettle();
expect(find.text('Ссылка на видео'), findsOneWidget);
expect(
find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField),
findsOneWidget,
);
expect(find.textContaining('Изображения'), findsOneWidget);
});
});
testWidgets('allows entering text in title field', (tester) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenTitleTextField),
'New Title',
);
await tester.pump();
final titleField = tester.widget<CustomTextFormField>(
find.byKey(AppKeys.blogPostCreateScreenTitleTextField),
);
expect(titleField.controller?.text, 'New Title');
});
testWidgets('allows entering text in description field', (tester) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenContentTextField),
'New Description',
);
await tester.pump();
final descriptionField = tester.widget<CustomTextFormField>(
find.byKey(AppKeys.blogPostCreateScreenContentTextField),
);
expect(descriptionField.controller?.text, 'New Description');
});
testWidgets('allows entering text in video URL field', (tester) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField),
'https://youtube.com/watch?v=new',
);
await tester.pump();
final videoField = tester.widget<CustomTextFormField>(
find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField),
);
expect(videoField.controller?.text, 'https://youtube.com/watch?v=new');
});
testWidgets('displays create button', (tester) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
expect(find.text('Создать'), findsOneWidget);
});
testWidgets('does not submit when form is empty', (tester) async {
when(
() => mockBlogPostRepository.createBlogPost(
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
images: any(named: 'images'),
),
).thenAnswer((_) async {});
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
final createButton = find.text('Создать');
await tester.ensureVisible(createButton);
await tester.tap(createButton);
await tester.pumpAndSettle();
verifyNever(
() => mockBlogPostRepository.createBlogPost(
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
images: any(named: 'images'),
),
);
expect(
find.text(
'Добавьте заголовок, описание, изображение или ссылку на видео',
),
findsOneWidget,
);
});
testWidgets('does not submit when video url is invalid', (tester) async {
when(
() => mockBlogPostRepository.createBlogPost(
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
images: any(named: 'images'),
),
).thenAnswer((_) async {});
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenTitleTextField),
'Test Title',
);
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField),
'https://youtube.com/watch?v=abc',
);
await tester.pump();
final createButton = find.text('Создать');
await tester.ensureVisible(createButton);
await tester.tap(createButton);
await tester.pumpAndSettle();
verifyNever(
() => mockBlogPostRepository.createBlogPost(
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
images: any(named: 'images'),
),
);
expect(
find.text('Поддерживаются только Rutube, VK и OK'),
findsOneWidget,
);
});
testWidgets('shows loading state when creating blog post', (tester) async {
when(
() => mockBlogPostRepository.createBlogPost(
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
images: any(named: 'images'),
),
).thenAnswer((_) async {
await Future.delayed(const Duration(milliseconds: 100));
return;
});
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenTitleTextField),
'Test Title',
);
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenContentTextField),
'Test Description',
);
await tester.pump();
final createButton = find.text('Создать');
await tester.ensureVisible(createButton);
await tester.tap(createButton);
await tester.pump();
expect(find.byType(Loader), findsWidgets);
await tester.pump(const Duration(milliseconds: 150));
await tester.pumpAndSettle();
});
testWidgets(
'calls FeedCubit.loadFeedBlogPostList when blog post is created successfully',
(tester) async {
when(
() => mockBlogPostRepository.createBlogPost(
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
images: any(named: 'images'),
),
).thenAnswer((_) async {
return;
});
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
final titleField = find.byKey(
AppKeys.blogPostCreateScreenTitleTextField,
);
final contentField = find.byKey(
AppKeys.blogPostCreateScreenContentTextField,
);
await tester.ensureVisible(titleField);
await tester.ensureVisible(contentField);
await tester.pumpAndSettle();
await tester.enterText(titleField, 'Test Title');
await tester.enterText(contentField, 'Test Description');
await tester.pump();
final createButton = find.text('Создать');
await tester.ensureVisible(createButton);
await tester.tap(createButton, warnIfMissed: false);
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
await tester.pumpAndSettle();
verify(() => mockFeedCubit.loadFeedBlogPostList()).called(1);
},
);
testWidgets('does not submit update when video url is invalid', (
tester,
) async {
await mockNetworkImagesFor(() async {
when(
() => mockBlogPostRepository.updateBlogPost(
id: any(named: 'id'),
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
existingMediaIds: any(named: 'existingMediaIds'),
newImages: any(named: 'newImages'),
mediaIdsToDelete: any(named: 'mediaIdsToDelete'),
),
).thenAnswer((_) async {});
final existingPost = FeedBlogPostModel(
id: 1,
title: 'Test Title',
@@ -154,136 +464,140 @@ void main() {
totalViews: 0,
totalComments: 0,
wasLikedByMe: false,
images: const [
FeedGalleryImage(
id: 10,
url: 'http://localhost/storage/test_image.jpg',
),
],
);
await tester.pumpWidget(createTestWidget(feedBlogPostModel: existingPost));
await tester.pumpWidget(
createTestWidget(feedBlogPostModel: existingPost),
);
await tester.pumpAndSettle();
expect(find.text('Ссылка на видео'), findsNothing);
expect(find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField), findsNothing);
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField),
'https://youtube.com/watch?v=abc',
);
await tester.pump();
final saveButton = find.text('Сохранить');
await tester.ensureVisible(saveButton);
await tester.tap(saveButton);
await tester.pumpAndSettle();
verifyNever(
() => mockBlogPostRepository.updateBlogPost(
id: any(named: 'id'),
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
existingMediaIds: any(named: 'existingMediaIds'),
newImages: any(named: 'newImages'),
mediaIdsToDelete: any(named: 'mediaIdsToDelete'),
),
);
expect(
find.text('Поддерживаются только Rutube, VK и OK'),
findsOneWidget,
);
});
});
testWidgets('hides image field when video URL is present', (tester) async {
final existingPost = FeedBlogPostModel(
id: 1,
title: 'Test Title',
description: 'Test Description',
videoUrl: 'https://youtube.com/watch?v=test',
image: '',
state: 'published',
author: const Author(authorSlug: 'test-author', authorName: 'Test Author', authorProfileIcon: 'avatar.jpg', authorIsMe: true),
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
totalLikes: 0,
totalViews: 0,
totalComments: 0,
wasLikedByMe: false,
);
await tester.pumpWidget(createTestWidget(feedBlogPostModel: existingPost));
await tester.pumpAndSettle();
expect(find.text('Изображение поста'), findsNothing);
});
testWidgets('allows entering text in title field', (tester) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenTitleTextField), 'New Title');
await tester.pump();
final titleField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenTitleTextField));
expect(titleField.controller?.text, 'New Title');
});
testWidgets('allows entering text in description field', (tester) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenContentTextField), 'New Description');
await tester.pump();
final descriptionField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenContentTextField));
expect(descriptionField.controller?.text, 'New Description');
});
testWidgets('allows entering text in video URL field', (tester) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField), 'https://youtube.com/watch?v=new');
await tester.pump();
final videoField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField));
expect(videoField.controller?.text, 'https://youtube.com/watch?v=new');
});
testWidgets('displays create button', (tester) async {
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
expect(find.text('Создать'), findsOneWidget);
});
testWidgets('shows loading state when creating blog post', (tester) async {
when(mockBlogPostRepository.createBlogPost(any, any, any, any)).thenAnswer((_) async {
await Future.delayed(const Duration(milliseconds: 100));
return;
});
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenTitleTextField), 'Test Title');
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenContentTextField), 'Test Description');
await tester.pump();
final createButton = find.text('Создать');
await tester.ensureVisible(createButton);
await tester.tap(createButton);
await tester.pump();
expect(find.byType(Loader), findsWidgets);
await tester.pump(const Duration(milliseconds: 150));
await tester.pumpAndSettle();
});
testWidgets('calls FeedCubit.loadFeedBlogPostList when blog post is created successfully', (tester) async {
when(mockBlogPostRepository.createBlogPost(any, any, any, any)).thenAnswer((_) async {
return;
});
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
final titleField = find.byKey(AppKeys.blogPostCreateScreenTitleTextField);
final contentField = find.byKey(AppKeys.blogPostCreateScreenContentTextField);
await tester.ensureVisible(titleField);
await tester.ensureVisible(contentField);
await tester.pumpAndSettle();
await tester.enterText(titleField, 'Test Title');
await tester.enterText(contentField, 'Test Description');
await tester.pump();
final createButton = find.text('Создать');
await tester.ensureVisible(createButton);
await tester.tap(createButton, warnIfMissed: false);
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
await tester.pumpAndSettle();
verify(mockFeedCubit.loadFeedBlogPostList()).called(1);
});
testWidgets('calls updateBlogPost when editing existing post', (tester) async {
testWidgets('does not submit update when form content is cleared', (
tester,
) async {
await mockNetworkImagesFor(() async {
when(mockBlogPostRepository.updateBlogPost(any, any, any, any, any, any)).thenAnswer((_) async {
when(
() => mockBlogPostRepository.updateBlogPost(
id: any(named: 'id'),
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
existingMediaIds: any(named: 'existingMediaIds'),
newImages: any(named: 'newImages'),
mediaIdsToDelete: any(named: 'mediaIdsToDelete'),
),
).thenAnswer((_) async {});
final existingPost = FeedBlogPostModel(
id: 1,
title: 'Test Title',
description: 'Test Description',
videoUrl: '',
image: '',
state: 'published',
author: const Author(
authorSlug: 'test-author',
authorName: 'Test Author',
authorProfileIcon: 'http://localhost/storage/avatar.jpg',
authorIsMe: true,
),
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
totalLikes: 0,
totalViews: 0,
totalComments: 0,
wasLikedByMe: false,
);
await tester.pumpWidget(
createTestWidget(feedBlogPostModel: existingPost),
);
await tester.pumpAndSettle();
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenTitleTextField),
'',
);
await tester.enterText(
find.byKey(AppKeys.blogPostCreateScreenContentTextField),
'',
);
await tester.pump();
final saveButton = find.text('Сохранить');
await tester.ensureVisible(saveButton);
await tester.tap(saveButton);
await tester.pumpAndSettle();
verifyNever(
() => mockBlogPostRepository.updateBlogPost(
id: any(named: 'id'),
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
existingMediaIds: any(named: 'existingMediaIds'),
newImages: any(named: 'newImages'),
mediaIdsToDelete: any(named: 'mediaIdsToDelete'),
),
);
expect(
find.text(
'Добавьте заголовок, описание, изображение или ссылку на видео',
),
findsOneWidget,
);
});
});
testWidgets('calls updateBlogPost when editing existing post', (
tester,
) async {
await mockNetworkImagesFor(() async {
when(
() => mockBlogPostRepository.updateBlogPost(
id: any(named: 'id'),
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
existingMediaIds: any(named: 'existingMediaIds'),
newImages: any(named: 'newImages'),
mediaIdsToDelete: any(named: 'mediaIdsToDelete'),
),
).thenAnswer((_) async {
return;
});
@@ -306,26 +620,46 @@ void main() {
totalViews: 0,
totalComments: 0,
wasLikedByMe: false,
images: const [
FeedGalleryImage(
id: 10,
url: 'http://localhost/storage/test_image.jpg',
),
],
);
await tester.pumpWidget(createTestWidget(feedBlogPostModel: existingPost, canPop: true));
await tester.pumpWidget(
createTestWidget(feedBlogPostModel: existingPost, canPop: true),
);
await tester.pumpAndSettle();
final titleField = find.byKey(AppKeys.blogPostCreateScreenTitleTextField);
final titleField = find.byKey(
AppKeys.blogPostCreateScreenTitleTextField,
);
expect(titleField, findsOneWidget);
await tester.enterText(titleField, 'Updated Title');
await tester.pump();
final createButton = find.text('Создать');
await tester.ensureVisible(createButton);
await tester.tap(createButton, warnIfMissed: false);
final saveButton = find.text('Сохранить');
await tester.ensureVisible(saveButton);
await tester.tap(saveButton, warnIfMissed: false);
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
await tester.pumpAndSettle();
verify(mockBlogPostRepository.updateBlogPost(any, any, any, any, any, any)).called(1);
verify(
() => mockBlogPostRepository.updateBlogPost(
id: any(named: 'id'),
title: any(named: 'title'),
videoUrl: any(named: 'videoUrl'),
description: any(named: 'description'),
existingMediaIds: any(named: 'existingMediaIds'),
newImages: any(named: 'newImages'),
mediaIdsToDelete: any(named: 'mediaIdsToDelete'),
),
).called(1);
});
});
@@ -344,8 +678,9 @@ void main() {
});
testWidgets('renders error state', (tester) async {
blogPostCreateCubit.emit(const BlogPostCreateState.error(errorMessage: 'Error creating post'));
blogPostCreateCubit.emit(
const BlogPostCreateState(errorMessage: 'Error creating post'),
);
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
@@ -354,7 +689,7 @@ void main() {
});
testWidgets('renders loading state', (tester) async {
blogPostCreateCubit.emit(const BlogPostCreateState.loading());
blogPostCreateCubit.emit(const BlogPostCreateState(isLoading: true));
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();