forked from eatvio/eatvio_app
feat(test): comments, auth, feed
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -19,4 +19,5 @@ ios/XCBuildData/
|
||||
env/.env
|
||||
.env
|
||||
android/key.properties
|
||||
app/upload-keystore.jks
|
||||
app/upload-keystore.jks
|
||||
coverage/
|
||||
419
test/core/comments/comments_cubit/comments_cubit_test.dart
Normal file
419
test/core/comments/comments_cubit/comments_cubit_test.dart
Normal file
@@ -0,0 +1,419 @@
|
||||
import 'package:eatvio_app/core/comments/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/core/comments/comments_cubit/comments_state.dart';
|
||||
import 'package:eatvio_app/core/comments/repositories/comments_repository.dart';
|
||||
import 'package:eatvio_app/core/models/pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/comment_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/comments_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'comments_cubit_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([
|
||||
MockSpec<FeedRepository>(),
|
||||
MockSpec<CommentsRepository>(),
|
||||
])
|
||||
void main() {
|
||||
group('CommentsCubit', () {
|
||||
CommentsCubit? commentsCubit;
|
||||
late MockFeedRepository mockFeedRepository;
|
||||
late MockCommentsRepository mockCommentsRepository;
|
||||
late CommentModel testCommentModel;
|
||||
|
||||
setUp(() {
|
||||
mockFeedRepository = MockFeedRepository();
|
||||
mockCommentsRepository = MockCommentsRepository();
|
||||
|
||||
testCommentModel = CommentModel(
|
||||
data: [],
|
||||
links: const Links(first: '', last: '', prev: null, next: null),
|
||||
meta: const Meta(
|
||||
currentPage: 1,
|
||||
from: null,
|
||||
lastPage: 1,
|
||||
links: [],
|
||||
path: null,
|
||||
perPage: 10,
|
||||
to: null,
|
||||
total: 0,
|
||||
totalMinPrice: null,
|
||||
totalMaxPrice: null,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (commentsCubit != null && !commentsCubit!.isClosed) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
commentsCubit!.close();
|
||||
commentsCubit = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('начальное состояние - CommentsState', () {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
expect(commentsCubit!.state, const CommentsState());
|
||||
});
|
||||
|
||||
test('getComments - успешная загрузка комментариев для blogPost', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const postId = '1';
|
||||
|
||||
when(mockFeedRepository.getBlogPostComments(id: postId))
|
||||
.thenAnswer((_) async => testCommentModel);
|
||||
|
||||
await commentsCubit!.getComments(postId, CommentSourceType.blogPost, true);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(commentsCubit!.state, isA<CommentsStateLoaded>());
|
||||
final loadedState = commentsCubit!.state as CommentsStateLoaded;
|
||||
expect(loadedState.comment, testCommentModel);
|
||||
verify(mockFeedRepository.getBlogPostComments(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('getComments - успешная загрузка комментариев для diet', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const dietId = '1';
|
||||
|
||||
when(mockFeedRepository.getDietsComments(id: dietId))
|
||||
.thenAnswer((_) async => testCommentModel);
|
||||
|
||||
await commentsCubit!.getComments(dietId, CommentSourceType.diet, true);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(commentsCubit!.state, isA<CommentsStateLoaded>());
|
||||
verify(mockFeedRepository.getDietsComments(id: dietId)).called(1);
|
||||
});
|
||||
|
||||
test('getComments - успешная загрузка комментариев для recipe', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const recipeId = 'recipe-slug';
|
||||
|
||||
when(mockFeedRepository.getRecipesComments(id: recipeId))
|
||||
.thenAnswer((_) async => testCommentModel);
|
||||
|
||||
await commentsCubit!.getComments(recipeId, CommentSourceType.recipe, true);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(commentsCubit!.state, isA<CommentsStateLoaded>());
|
||||
verify(mockFeedRepository.getRecipesComments(id: recipeId)).called(1);
|
||||
});
|
||||
|
||||
test('getComments - успешная загрузка комментариев для plan', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const planSlug = 'plan-slug';
|
||||
|
||||
when(mockFeedRepository.getPlansComments(slug: planSlug))
|
||||
.thenAnswer((_) async => testCommentModel);
|
||||
|
||||
await commentsCubit!.getComments(planSlug, CommentSourceType.plan, true);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(commentsCubit!.state, isA<CommentsStateLoaded>());
|
||||
verify(mockFeedRepository.getPlansComments(slug: planSlug)).called(1);
|
||||
});
|
||||
|
||||
test('getComments - переход в состояние loading при первом запросе', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const postId = '1';
|
||||
|
||||
when(mockFeedRepository.getBlogPostComments(id: postId))
|
||||
.thenAnswer((_) async {
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
return testCommentModel;
|
||||
});
|
||||
|
||||
final future = commentsCubit!.getComments(postId, CommentSourceType.blogPost, true);
|
||||
await Future.delayed(const Duration(milliseconds: 10));
|
||||
|
||||
expect(commentsCubit!.state, const CommentsState.loading());
|
||||
await future;
|
||||
});
|
||||
|
||||
test('getComments - обработка ошибки', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const postId = '1';
|
||||
|
||||
when(mockFeedRepository.getBlogPostComments(id: postId))
|
||||
.thenThrow(Exception('Ошибка загрузки'));
|
||||
|
||||
await commentsCubit!.getComments(postId, CommentSourceType.blogPost, true);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(commentsCubit!.state, isA<CommentsStateError>());
|
||||
final errorState = commentsCubit!.state as CommentsStateError;
|
||||
expect(errorState.errorMessage, contains('Exception'));
|
||||
});
|
||||
|
||||
test('sendComment - успешная отправка комментария для blogPost', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const postId = '1';
|
||||
const commentText = 'Тестовый комментарий';
|
||||
|
||||
// Устанавливаем начальное состояние
|
||||
commentsCubit!.emit(CommentsState.loaded(comment: testCommentModel));
|
||||
|
||||
when(mockFeedRepository.sendBlogPostComment(
|
||||
id: postId,
|
||||
commentText: commentText,
|
||||
parentCommentId: null,
|
||||
)).thenAnswer((_) async => Future.value());
|
||||
|
||||
when(mockFeedRepository.getBlogPostComments(id: postId))
|
||||
.thenAnswer((_) async => testCommentModel);
|
||||
|
||||
await commentsCubit!.sendComment(
|
||||
id: postId,
|
||||
commentText: commentText,
|
||||
commentSourceType: CommentSourceType.blogPost,
|
||||
);
|
||||
|
||||
verify(mockFeedRepository.sendBlogPostComment(
|
||||
id: postId,
|
||||
commentText: commentText,
|
||||
parentCommentId: null,
|
||||
)).called(1);
|
||||
verify(mockFeedRepository.getBlogPostComments(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('sendComment - обработка ошибки при отправке', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const postId = '1';
|
||||
const commentText = 'Тестовый комментарий';
|
||||
|
||||
commentsCubit!.emit(CommentsState.loaded(comment: testCommentModel));
|
||||
|
||||
when(mockFeedRepository.sendBlogPostComment(
|
||||
id: postId,
|
||||
commentText: commentText,
|
||||
parentCommentId: null,
|
||||
)).thenThrow(Exception('Ошибка отправки'));
|
||||
|
||||
await commentsCubit!.sendComment(
|
||||
id: postId,
|
||||
commentText: commentText,
|
||||
commentSourceType: CommentSourceType.blogPost,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(commentsCubit!.state, isA<CommentsStateError>());
|
||||
});
|
||||
|
||||
test('deleteComment - успешное удаление комментария', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const commentId = 1;
|
||||
|
||||
final commentWithData = testCommentModel.copyWith(
|
||||
data: [
|
||||
Comment(
|
||||
id: commentId,
|
||||
body: 'Комментарий для удаления',
|
||||
authorName: 'Автор',
|
||||
authorSlug: 'author-slug',
|
||||
authorProfileIcon: 'https://example.com/photo.jpg',
|
||||
createdAt: DateTime.now(),
|
||||
childrenComments: [],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
commentsCubit!.emit(CommentsState.loaded(comment: commentWithData));
|
||||
|
||||
when(mockCommentsRepository.deleteComment(id: commentId))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
final result = await commentsCubit!.deleteComment(id: commentId);
|
||||
|
||||
expect(result, true);
|
||||
expect(commentsCubit!.state, isA<CommentsStateLoaded>());
|
||||
final loadedState = commentsCubit!.state as CommentsStateLoaded;
|
||||
expect(loadedState.comment.data, isEmpty);
|
||||
verify(mockCommentsRepository.deleteComment(id: commentId)).called(1);
|
||||
});
|
||||
|
||||
test('deleteComment - возвращает false если состояние не loaded', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const commentId = 1;
|
||||
|
||||
commentsCubit!.emit(const CommentsState());
|
||||
|
||||
final result = await commentsCubit!.deleteComment(id: commentId);
|
||||
|
||||
expect(result, false);
|
||||
verifyNever(mockCommentsRepository.deleteComment(id: commentId));
|
||||
});
|
||||
|
||||
test('deleteComment - обработка ошибки при удалении', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const commentId = 1;
|
||||
|
||||
final commentWithData = testCommentModel.copyWith(
|
||||
data: [
|
||||
Comment(
|
||||
id: commentId,
|
||||
body: 'Комментарий',
|
||||
authorName: 'Автор',
|
||||
authorSlug: 'author-slug',
|
||||
authorProfileIcon: 'https://example.com/photo.jpg',
|
||||
createdAt: DateTime.now(),
|
||||
childrenComments: [],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
commentsCubit!.emit(CommentsState.loaded(comment: commentWithData));
|
||||
|
||||
when(mockCommentsRepository.deleteComment(id: commentId))
|
||||
.thenThrow(Exception('Ошибка удаления'));
|
||||
|
||||
final result = await commentsCubit!.deleteComment(id: commentId);
|
||||
|
||||
expect(result, false);
|
||||
// Состояние должно вернуться к исходному
|
||||
final loadedState = commentsCubit!.state as CommentsStateLoaded;
|
||||
expect(loadedState.comment.data.length, 1);
|
||||
});
|
||||
|
||||
test('updateComment - успешное обновление комментария', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const commentId = 1;
|
||||
const newBody = 'Обновлённый комментарий';
|
||||
|
||||
final commentWithData = testCommentModel.copyWith(
|
||||
data: [
|
||||
Comment(
|
||||
id: commentId,
|
||||
body: 'Старый комментарий',
|
||||
authorName: 'Автор',
|
||||
authorSlug: 'author-slug',
|
||||
authorProfileIcon: 'https://example.com/photo.jpg',
|
||||
createdAt: DateTime.now(),
|
||||
childrenComments: [],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
commentsCubit!.emit(CommentsState.loaded(comment: commentWithData));
|
||||
|
||||
when(mockCommentsRepository.updateComment(id: commentId, body: newBody))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
final result = await commentsCubit!.updateComment(id: commentId, body: newBody);
|
||||
|
||||
expect(result, true);
|
||||
expect(commentsCubit!.state, isA<CommentsStateLoaded>());
|
||||
final loadedState = commentsCubit!.state as CommentsStateLoaded;
|
||||
expect(loadedState.comment.data.first.body, newBody);
|
||||
verify(mockCommentsRepository.updateComment(id: commentId, body: newBody)).called(1);
|
||||
});
|
||||
|
||||
test('updateComment - обработка ошибки при обновлении', () async {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const commentId = 1;
|
||||
const newBody = 'Обновлённый комментарий';
|
||||
const oldBody = 'Старый комментарий';
|
||||
|
||||
final commentWithData = testCommentModel.copyWith(
|
||||
data: [
|
||||
Comment(
|
||||
id: commentId,
|
||||
body: oldBody,
|
||||
authorName: 'Автор',
|
||||
authorSlug: 'author-slug',
|
||||
authorProfileIcon: 'https://example.com/photo.jpg',
|
||||
createdAt: DateTime.now(),
|
||||
childrenComments: [],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
commentsCubit!.emit(CommentsState.loaded(comment: commentWithData));
|
||||
|
||||
when(mockCommentsRepository.updateComment(id: commentId, body: newBody))
|
||||
.thenThrow(Exception('Ошибка обновления'));
|
||||
|
||||
final result = await commentsCubit!.updateComment(id: commentId, body: newBody);
|
||||
|
||||
expect(result, false);
|
||||
// Состояние должно вернуться к исходному
|
||||
final loadedState = commentsCubit!.state as CommentsStateLoaded;
|
||||
expect(loadedState.comment.data.first.body, oldBody);
|
||||
});
|
||||
|
||||
test('setReplyId - устанавливает ID ответа', () {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
const replyId = 5;
|
||||
|
||||
commentsCubit!.emit(CommentsState.loaded(comment: testCommentModel));
|
||||
|
||||
commentsCubit!.setReplyId(replyId);
|
||||
|
||||
expect(commentsCubit!.state, isA<CommentsStateLoaded>());
|
||||
final loadedState = commentsCubit!.state as CommentsStateLoaded;
|
||||
expect(loadedState.replyId, replyId);
|
||||
});
|
||||
|
||||
test('setReplyId - сбрасывает ID ответа', () {
|
||||
commentsCubit = CommentsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
commentsRepository: mockCommentsRepository,
|
||||
);
|
||||
|
||||
commentsCubit!.emit(CommentsState.loaded(comment: testCommentModel, replyId: 5));
|
||||
|
||||
commentsCubit!.setReplyId(null);
|
||||
|
||||
expect(commentsCubit!.state, isA<CommentsStateLoaded>());
|
||||
final loadedState = commentsCubit!.state as CommentsStateLoaded;
|
||||
expect(loadedState.replyId, isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import 'package:eatvio_app/core/comments/models/comment_update_model.dart';
|
||||
import 'package:eatvio_app/core/comments/repositories/comments_repository.dart';
|
||||
import 'package:eatvio_app/core/comments/services/comments_service.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'comments_repository_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<CommentsService>()])
|
||||
void main() {
|
||||
group('CommentsRepository', () {
|
||||
late CommentsRepository commentsRepository;
|
||||
late MockCommentsService mockCommentsService;
|
||||
|
||||
setUp(() {
|
||||
mockCommentsService = MockCommentsService();
|
||||
commentsRepository = CommentsRepository(service: mockCommentsService);
|
||||
});
|
||||
|
||||
test('deleteComment - успешное удаление комментария', () async {
|
||||
const commentId = 1;
|
||||
|
||||
when(mockCommentsService.deleteComment(commentId))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
await commentsRepository.deleteComment(id: commentId);
|
||||
|
||||
verify(mockCommentsService.deleteComment(commentId)).called(1);
|
||||
});
|
||||
|
||||
test('deleteComment - пробрасывает исключение', () async {
|
||||
const commentId = 1;
|
||||
|
||||
when(mockCommentsService.deleteComment(commentId))
|
||||
.thenThrow(Exception('Ошибка удаления'));
|
||||
|
||||
expect(
|
||||
() => commentsRepository.deleteComment(id: commentId),
|
||||
throwsException,
|
||||
);
|
||||
});
|
||||
|
||||
test('updateComment - успешное обновление комментария', () async {
|
||||
const commentId = 1;
|
||||
const newBody = 'Обновлённый текст комментария';
|
||||
final updateModel = CommentUpdateModel(body: newBody);
|
||||
|
||||
when(mockCommentsService.updateComment(commentId, updateModel))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
await commentsRepository.updateComment(id: commentId, body: newBody);
|
||||
|
||||
verify(mockCommentsService.updateComment(
|
||||
commentId,
|
||||
argThat(
|
||||
predicate<CommentUpdateModel>(
|
||||
(m) => m.body == newBody,
|
||||
),
|
||||
),
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('updateComment - пробрасывает исключение', () async {
|
||||
const commentId = 1;
|
||||
const newBody = 'Обновлённый текст';
|
||||
|
||||
when(mockCommentsService.updateComment(
|
||||
commentId,
|
||||
any,
|
||||
)).thenThrow(Exception('Ошибка обновления'));
|
||||
|
||||
expect(
|
||||
() => commentsRepository.updateComment(id: commentId, body: newBody),
|
||||
throwsException,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
import 'package:eatvio_app/core/prefs.dart';
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
import 'package:eatvio_app/features/auth/models/token_model.dart';
|
||||
import 'package:eatvio_app/features/auth/presentation/bloc/oauth_cubit/oauth_cubit.dart';
|
||||
import 'package:eatvio_app/features/auth/presentation/bloc/oauth_cubit/oauth_state.dart';
|
||||
import 'package:eatvio_app/features/auth/repositories/auth_repository.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../../../fixtures/doubles/auth_doubles.dart';
|
||||
import '../../../../../fixtures/fixture_reader.dart';
|
||||
import 'oauth_cubit_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<AuthRepository>(), MockSpec<Prefs>()])
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('OAuthCubit', () {
|
||||
OAuthCubit? oauthCubit;
|
||||
late MockAuthRepository mockAuthRepository;
|
||||
late MockPrefs mockPrefs;
|
||||
late TokenModel tokenFixture;
|
||||
late Map<String, dynamic> signInRequestFixture;
|
||||
late Map<String, dynamic> signUpRequestFixture;
|
||||
|
||||
setUp(() async {
|
||||
tokenFixture = TokenModel.fromJson(FixtureReader.readAsMap('auth/token_response.json'));
|
||||
signInRequestFixture = FixtureReader.readAsMap('auth/oauth_signin_request.json');
|
||||
signUpRequestFixture = FixtureReader.readAsMap('auth/oauth_signup_request.json');
|
||||
|
||||
mockAuthRepository = MockAuthRepository();
|
||||
mockPrefs = MockPrefs();
|
||||
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
|
||||
// Mock Fluttertoast plugin
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(const MethodChannel('PonnamKarthik/fluttertoast'), (
|
||||
MethodCall methodCall,
|
||||
) async {
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (oauthCubit != null && !oauthCubit!.isClosed) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
oauthCubit!.close();
|
||||
oauthCubit = null;
|
||||
}
|
||||
|
||||
// Clear mock handlers
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(const MethodChannel('PonnamKarthik/fluttertoast'), null);
|
||||
});
|
||||
|
||||
test('начальное состояние - OAuthState', () {
|
||||
oauthCubit = OAuthCubit(authRepository: mockAuthRepository, prefs: mockPrefs);
|
||||
expect(oauthCubit!.state, const OAuthState());
|
||||
});
|
||||
|
||||
test('signInViaSocialMedia - успешный вход через соцсеть', () async {
|
||||
oauthCubit = OAuthCubit(authRepository: mockAuthRepository, prefs: mockPrefs);
|
||||
|
||||
when(
|
||||
mockAuthRepository.signInViaSocialMedia(
|
||||
provider: signInRequestFixture['provider'] as String,
|
||||
accessToken: signInRequestFixture['accessToken'] as String,
|
||||
refreshToken: signInRequestFixture['refreshToken'] as String,
|
||||
clientId: signInRequestFixture['clientId'] as String,
|
||||
),
|
||||
).thenAnswer((_) async => tokenFixture);
|
||||
|
||||
await oauthCubit!.signInViaSocialMedia(
|
||||
provider: signInRequestFixture['provider'] as String,
|
||||
accessToken: signInRequestFixture['accessToken'] as String,
|
||||
refreshToken: signInRequestFixture['refreshToken'] as String,
|
||||
clientId: signInRequestFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(oauthCubit!.state, isA<OAuthStateLoaded>());
|
||||
final loadedState = oauthCubit!.state as OAuthStateLoaded;
|
||||
expect(loadedState.token, tokenFixture.token);
|
||||
|
||||
// Проверяем, что токен сохранён
|
||||
final savedToken = await TokenStorage.getTokenFromStorage();
|
||||
expect(savedToken, tokenFixture.token);
|
||||
});
|
||||
|
||||
test('signInViaSocialMedia - переход в состояние loading', () async {
|
||||
oauthCubit = OAuthCubit(authRepository: mockAuthRepository, prefs: mockPrefs);
|
||||
|
||||
when(
|
||||
mockAuthRepository.signInViaSocialMedia(
|
||||
provider: anyNamed('provider'),
|
||||
accessToken: anyNamed('accessToken'),
|
||||
refreshToken: anyNamed('refreshToken'),
|
||||
clientId: anyNamed('clientId'),
|
||||
),
|
||||
).thenAnswer((_) async {
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
return tokenFixture;
|
||||
});
|
||||
|
||||
final future = oauthCubit!.signInViaSocialMedia(
|
||||
provider: signInRequestFixture['provider'] as String,
|
||||
accessToken: signInRequestFixture['accessToken'] as String,
|
||||
refreshToken: signInRequestFixture['refreshToken'] as String,
|
||||
clientId: signInRequestFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 10));
|
||||
expect(oauthCubit!.state, isA<OAuthStateLoading>());
|
||||
await future;
|
||||
});
|
||||
|
||||
test('signInViaSocialMedia - обработка ошибки', () async {
|
||||
oauthCubit = OAuthCubit(authRepository: mockAuthRepository, prefs: mockPrefs);
|
||||
|
||||
when(
|
||||
mockAuthRepository.signInViaSocialMedia(
|
||||
provider: anyNamed('provider'),
|
||||
accessToken: anyNamed('accessToken'),
|
||||
refreshToken: anyNamed('refreshToken'),
|
||||
clientId: anyNamed('clientId'),
|
||||
),
|
||||
).thenThrow(Exception('Ошибка авторизации'));
|
||||
|
||||
await oauthCubit!.signInViaSocialMedia(
|
||||
provider: signInRequestFixture['provider'] as String,
|
||||
accessToken: signInRequestFixture['accessToken'] as String,
|
||||
refreshToken: signInRequestFixture['refreshToken'] as String,
|
||||
clientId: signInRequestFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(oauthCubit!.state, isA<OAuthStateError>());
|
||||
final errorState = oauthCubit!.state as OAuthStateError;
|
||||
expect(errorState.errorMessage, contains('Exception'));
|
||||
});
|
||||
|
||||
test('signUpViaSocialMedia - успешная регистрация через соцсеть', () async {
|
||||
oauthCubit = OAuthCubit(authRepository: mockAuthRepository, prefs: mockPrefs);
|
||||
|
||||
when(
|
||||
mockAuthRepository.signUpViaSocialMedia(
|
||||
provider: anyNamed('provider'),
|
||||
accessToken: anyNamed('accessToken'),
|
||||
id: anyNamed('id'),
|
||||
refreshToken: anyNamed('refreshToken'),
|
||||
firstName: anyNamed('firstName'),
|
||||
lastName: anyNamed('lastName'),
|
||||
email: anyNamed('email'),
|
||||
phone: anyNamed('phone'),
|
||||
dateOfBirth: anyNamed('dateOfBirth'),
|
||||
gender: anyNamed('gender'),
|
||||
weight: anyNamed('weight'),
|
||||
height: anyNamed('height'),
|
||||
clientId: anyNamed('clientId'),
|
||||
),
|
||||
).thenAnswer((_) async => tokenFixture.token);
|
||||
|
||||
when(mockPrefs.setString(any, any)).thenAnswer((_) async => Future.value());
|
||||
|
||||
final result = await oauthCubit!.signUpViaSocialMedia(
|
||||
provider: signUpRequestFixture['provider'] as String,
|
||||
accessToken: signUpRequestFixture['accessToken'] as String,
|
||||
id: signUpRequestFixture['id'] as String,
|
||||
refreshToken: signUpRequestFixture['refreshToken'] as String,
|
||||
firstName: signUpRequestFixture['firstName'] as String,
|
||||
lastName: signUpRequestFixture['lastName'] as String,
|
||||
email: signUpRequestFixture['email'] as String,
|
||||
phone: signUpRequestFixture['phone'] as String,
|
||||
dateOfBirth: signUpRequestFixture['dateOfBirth'] as String,
|
||||
gender: signUpRequestFixture['gender'] as String,
|
||||
weight: signUpRequestFixture['weight'] as int,
|
||||
height: signUpRequestFixture['height'] as int,
|
||||
clientId: signUpRequestFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(result, isNull); // Нет ошибок валидации
|
||||
expect(oauthCubit!.state, isA<OAuthStateLoaded>());
|
||||
final loadedState = oauthCubit!.state as OAuthStateLoaded;
|
||||
expect(loadedState.token, tokenFixture.token);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
import 'package:eatvio_app/features/auth/presentation/bloc/reset_password_cubit/reset_password_cubit.dart';
|
||||
import 'package:eatvio_app/features/auth/presentation/bloc/reset_password_cubit/reset_password_state.dart';
|
||||
import 'package:eatvio_app/features/auth/repositories/reset_password_repository.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import '../../../../../fixtures/fixture_reader.dart';
|
||||
import 'reset_password_cubit_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<ResetPasswordRepository>()])
|
||||
void main() {
|
||||
group('ResetPasswordCubit', () {
|
||||
ResetPasswordCubit? resetPasswordCubit;
|
||||
late MockResetPasswordRepository mockResetPasswordRepository;
|
||||
late Map<String, dynamic> resetPasswordFixture;
|
||||
|
||||
setUp(() {
|
||||
resetPasswordFixture = FixtureReader.readAsMap('auth/reset_password_request.json');
|
||||
mockResetPasswordRepository = MockResetPasswordRepository();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (resetPasswordCubit != null && !resetPasswordCubit!.isClosed) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
resetPasswordCubit!.close();
|
||||
resetPasswordCubit = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('начальное состояние - ResetPasswordState.empty', () {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.empty());
|
||||
});
|
||||
|
||||
test('trySendEmailCode - успешная отправка кода', () async {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
|
||||
when(mockResetPasswordRepository.sendEmailCodeForPasswordChange(
|
||||
resetPasswordFixture['email'] as String,
|
||||
)).thenAnswer((_) async => true);
|
||||
|
||||
await resetPasswordCubit!.trySendEmailCode(
|
||||
resetPasswordFixture['email'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.codeSendSuccess());
|
||||
verify(mockResetPasswordRepository.sendEmailCodeForPasswordChange(
|
||||
resetPasswordFixture['email'] as String,
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('trySendEmailCode - переход в состояние loading', () async {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
|
||||
when(mockResetPasswordRepository.sendEmailCodeForPasswordChange(
|
||||
any,
|
||||
)).thenAnswer((_) async {
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
return true;
|
||||
});
|
||||
|
||||
final future = resetPasswordCubit!.trySendEmailCode(
|
||||
resetPasswordFixture['email'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 10));
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.loadingSendEmailCode());
|
||||
await future;
|
||||
});
|
||||
|
||||
test('trySendEmailCode - ошибка отправки кода', () async {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
|
||||
when(mockResetPasswordRepository.sendEmailCodeForPasswordChange(
|
||||
resetPasswordFixture['email'] as String,
|
||||
)).thenAnswer((_) async => false);
|
||||
|
||||
await resetPasswordCubit!.trySendEmailCode(
|
||||
resetPasswordFixture['email'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.codeSendError());
|
||||
});
|
||||
|
||||
test('trySendEmailCode - обработка исключения', () async {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
|
||||
when(mockResetPasswordRepository.sendEmailCodeForPasswordChange(
|
||||
resetPasswordFixture['email'] as String,
|
||||
)).thenThrow(Exception('Ошибка сети'));
|
||||
|
||||
await resetPasswordCubit!.trySendEmailCode(
|
||||
resetPasswordFixture['email'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.codeSendError());
|
||||
});
|
||||
|
||||
test('tryResetPassword - успешный сброс пароля', () async {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
|
||||
when(mockResetPasswordRepository.confirmPasswordChange(
|
||||
resetPasswordFixture['code'] as String,
|
||||
resetPasswordFixture['password'] as String,
|
||||
resetPasswordFixture['passwordConfirmation'] as String,
|
||||
resetPasswordFixture['email'] as String,
|
||||
)).thenAnswer((_) async => true);
|
||||
|
||||
await resetPasswordCubit!.tryResetPassword(
|
||||
resetPasswordFixture['email'] as String,
|
||||
resetPasswordFixture['code'] as String,
|
||||
resetPasswordFixture['password'] as String,
|
||||
resetPasswordFixture['passwordConfirmation'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.resetPasswordSuccess());
|
||||
verify(mockResetPasswordRepository.confirmPasswordChange(
|
||||
resetPasswordFixture['code'] as String,
|
||||
resetPasswordFixture['password'] as String,
|
||||
resetPasswordFixture['passwordConfirmation'] as String,
|
||||
resetPasswordFixture['email'] as String,
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('tryResetPassword - переход в состояние loading', () async {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
|
||||
when(mockResetPasswordRepository.confirmPasswordChange(
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
)).thenAnswer((_) async {
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
return true;
|
||||
});
|
||||
|
||||
final future = resetPasswordCubit!.tryResetPassword(
|
||||
resetPasswordFixture['email'] as String,
|
||||
resetPasswordFixture['code'] as String,
|
||||
resetPasswordFixture['password'] as String,
|
||||
resetPasswordFixture['passwordConfirmation'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 10));
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.loadingResetPassword());
|
||||
await future;
|
||||
});
|
||||
|
||||
test('tryResetPassword - ошибка сброса пароля', () async {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
|
||||
when(mockResetPasswordRepository.confirmPasswordChange(
|
||||
resetPasswordFixture['code'] as String,
|
||||
resetPasswordFixture['password'] as String,
|
||||
resetPasswordFixture['passwordConfirmation'] as String,
|
||||
resetPasswordFixture['email'] as String,
|
||||
)).thenAnswer((_) async => false);
|
||||
|
||||
await resetPasswordCubit!.tryResetPassword(
|
||||
resetPasswordFixture['email'] as String,
|
||||
resetPasswordFixture['code'] as String,
|
||||
resetPasswordFixture['password'] as String,
|
||||
resetPasswordFixture['passwordConfirmation'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.resetPasswordError());
|
||||
});
|
||||
|
||||
test('tryResetPassword - обработка исключения', () async {
|
||||
resetPasswordCubit = ResetPasswordCubit(
|
||||
resetPasswordRepository: mockResetPasswordRepository,
|
||||
);
|
||||
|
||||
when(mockResetPasswordRepository.confirmPasswordChange(
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
)).thenThrow(Exception('Неверный код'));
|
||||
|
||||
await resetPasswordCubit!.tryResetPassword(
|
||||
resetPasswordFixture['email'] as String,
|
||||
resetPasswordFixture['code'] as String,
|
||||
resetPasswordFixture['password'] as String,
|
||||
resetPasswordFixture['passwordConfirmation'] as String,
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(resetPasswordCubit!.state, const ResetPasswordState.resetPasswordError());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
237
test/features/auth/repositories/auth_repository_test.dart
Normal file
237
test/features/auth/repositories/auth_repository_test.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
import 'package:eatvio_app/features/auth/models/credentials_model.dart';
|
||||
import 'package:eatvio_app/features/auth/models/oauth_login_request.dart';
|
||||
import 'package:eatvio_app/features/auth/models/oauth_model.dart';
|
||||
import 'package:eatvio_app/features/auth/models/token_model.dart';
|
||||
import 'package:eatvio_app/features/auth/repositories/auth_repository.dart';
|
||||
import 'package:eatvio_app/features/auth/services/auth_service.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import '../../../fixtures/fixture_reader.dart';
|
||||
import 'auth_repository_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<AuthService>()])
|
||||
void main() {
|
||||
group('AuthRepository', () {
|
||||
late AuthRepository authRepository;
|
||||
late MockAuthService mockAuthService;
|
||||
late TokenModel tokenFixture;
|
||||
late Map<String, dynamic> credentialsFixture;
|
||||
late Map<String, dynamic> oauthSignInFixture;
|
||||
late Map<String, dynamic> oauthSignUpFixture;
|
||||
|
||||
setUp(() {
|
||||
tokenFixture = TokenModel.fromJson(FixtureReader.readAsMap('auth/token_response.json'));
|
||||
credentialsFixture = FixtureReader.readAsMap('auth/login_credentials.json');
|
||||
oauthSignInFixture = FixtureReader.readAsMap('auth/oauth_signin_request.json');
|
||||
oauthSignUpFixture = FixtureReader.readAsMap('auth/oauth_signup_request.json');
|
||||
|
||||
mockAuthService = MockAuthService();
|
||||
authRepository = AuthRepository(authService: mockAuthService);
|
||||
});
|
||||
|
||||
test('getTokenByCredentials - успешное получение токена', () async {
|
||||
final credentials = CredentialsModel(
|
||||
email: credentialsFixture['email'] as String,
|
||||
password: credentialsFixture['password'] as String,
|
||||
);
|
||||
|
||||
when(mockAuthService.getTokenByCredentials(credentials: credentials))
|
||||
.thenAnswer((_) async => tokenFixture);
|
||||
|
||||
final result = await authRepository.getTokenByCredentials(
|
||||
credentialsFixture['email'] as String,
|
||||
credentialsFixture['password'] as String,
|
||||
);
|
||||
|
||||
expect(result, isA<TokenModel>());
|
||||
expect(result.token, tokenFixture.token);
|
||||
verify(mockAuthService.getTokenByCredentials(credentials: credentials)).called(1);
|
||||
});
|
||||
|
||||
test('getTokenByCredentials - пробрасывает исключение', () async {
|
||||
final credentials = CredentialsModel(
|
||||
email: credentialsFixture['email'] as String,
|
||||
password: credentialsFixture['password'] as String,
|
||||
);
|
||||
|
||||
when(mockAuthService.getTokenByCredentials(credentials: credentials))
|
||||
.thenThrow(Exception('Ошибка авторизации'));
|
||||
|
||||
expect(
|
||||
() => authRepository.getTokenByCredentials(
|
||||
credentialsFixture['email'] as String,
|
||||
credentialsFixture['password'] as String,
|
||||
),
|
||||
throwsException,
|
||||
);
|
||||
});
|
||||
|
||||
test('signInViaSocialMedia - успешный вход через соцсеть', () async {
|
||||
final oauthRequest = OAuthLoginRequest(
|
||||
provider: oauthSignInFixture['provider'] as String,
|
||||
accessToken: oauthSignInFixture['accessToken'] as String,
|
||||
refreshToken: oauthSignInFixture['refreshToken'] as String,
|
||||
clientId: oauthSignInFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
when(mockAuthService.signInViaSocialMedia(body: oauthRequest))
|
||||
.thenAnswer((_) async => tokenFixture);
|
||||
|
||||
final result = await authRepository.signInViaSocialMedia(
|
||||
provider: oauthSignInFixture['provider'] as String,
|
||||
accessToken: oauthSignInFixture['accessToken'] as String,
|
||||
refreshToken: oauthSignInFixture['refreshToken'] as String,
|
||||
clientId: oauthSignInFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
expect(result, isA<TokenModel>());
|
||||
expect(result.token, tokenFixture.token);
|
||||
verify(mockAuthService.signInViaSocialMedia(body: oauthRequest)).called(1);
|
||||
});
|
||||
|
||||
test('signInViaSocialMedia - пробрасывает исключение', () async {
|
||||
final oauthRequest = OAuthLoginRequest(
|
||||
provider: oauthSignInFixture['provider'] as String,
|
||||
accessToken: oauthSignInFixture['accessToken'] as String,
|
||||
refreshToken: oauthSignInFixture['refreshToken'] as String,
|
||||
clientId: oauthSignInFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
when(mockAuthService.signInViaSocialMedia(body: oauthRequest))
|
||||
.thenThrow(Exception('Ошибка OAuth'));
|
||||
|
||||
expect(
|
||||
() => authRepository.signInViaSocialMedia(
|
||||
provider: oauthSignInFixture['provider'] as String,
|
||||
accessToken: oauthSignInFixture['accessToken'] as String,
|
||||
refreshToken: oauthSignInFixture['refreshToken'] as String,
|
||||
clientId: oauthSignInFixture['clientId'] as String,
|
||||
),
|
||||
throwsException,
|
||||
);
|
||||
});
|
||||
|
||||
test('signUpViaSocialMedia - успешная регистрация через соцсеть', () async {
|
||||
final oauthModel = OAuthModel(
|
||||
provider: oauthSignUpFixture['provider'] as String,
|
||||
accessToken: oauthSignUpFixture['accessToken'] as String,
|
||||
id: oauthSignUpFixture['id'] as String,
|
||||
refreshToken: oauthSignUpFixture['refreshToken'] as String,
|
||||
firstName: oauthSignUpFixture['firstName'] as String,
|
||||
lastName: oauthSignUpFixture['lastName'] as String,
|
||||
email: oauthSignUpFixture['email'] as String,
|
||||
phone: oauthSignUpFixture['phone'] as String,
|
||||
dateOfBirth: oauthSignUpFixture['dateOfBirth'] as String,
|
||||
gender: 'male', // Преобразуется из 'М'
|
||||
weight: oauthSignUpFixture['weight'] as int,
|
||||
height: oauthSignUpFixture['height'] as int,
|
||||
clientId: oauthSignUpFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
when(mockAuthService.signUpViaSocialMedia(body: oauthModel))
|
||||
.thenAnswer((_) async => <String, Object?>{'token': tokenFixture.token});
|
||||
|
||||
final result = await authRepository.signUpViaSocialMedia(
|
||||
provider: oauthSignUpFixture['provider'] as String,
|
||||
accessToken: oauthSignUpFixture['accessToken'] as String,
|
||||
id: oauthSignUpFixture['id'] as String,
|
||||
refreshToken: oauthSignUpFixture['refreshToken'] as String,
|
||||
firstName: oauthSignUpFixture['firstName'] as String,
|
||||
lastName: oauthSignUpFixture['lastName'] as String,
|
||||
email: oauthSignUpFixture['email'] as String,
|
||||
phone: oauthSignUpFixture['phone'] as String,
|
||||
dateOfBirth: oauthSignUpFixture['dateOfBirth'] as String,
|
||||
gender: oauthSignUpFixture['gender'] as String,
|
||||
weight: oauthSignUpFixture['weight'] as int,
|
||||
height: oauthSignUpFixture['height'] as int,
|
||||
clientId: oauthSignUpFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
expect(result, tokenFixture.token);
|
||||
verify(mockAuthService.signUpViaSocialMedia(body: oauthModel)).called(1);
|
||||
});
|
||||
|
||||
test('signUpViaSocialMedia - преобразует женский пол', () async {
|
||||
final oauthModel = OAuthModel(
|
||||
provider: oauthSignUpFixture['provider'] as String,
|
||||
accessToken: oauthSignUpFixture['accessToken'] as String,
|
||||
id: oauthSignUpFixture['id'] as String,
|
||||
refreshToken: oauthSignUpFixture['refreshToken'] as String,
|
||||
firstName: oauthSignUpFixture['firstName'] as String,
|
||||
lastName: oauthSignUpFixture['lastName'] as String,
|
||||
email: oauthSignUpFixture['email'] as String,
|
||||
phone: oauthSignUpFixture['phone'] as String,
|
||||
dateOfBirth: oauthSignUpFixture['dateOfBirth'] as String,
|
||||
gender: 'female', // Преобразуется из 'Ж'
|
||||
weight: oauthSignUpFixture['weight'] as int,
|
||||
height: oauthSignUpFixture['height'] as int,
|
||||
clientId: oauthSignUpFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
when(mockAuthService.signUpViaSocialMedia(body: oauthModel))
|
||||
.thenAnswer((_) async => <String, Object?>{'token': tokenFixture.token});
|
||||
|
||||
final result = await authRepository.signUpViaSocialMedia(
|
||||
provider: oauthSignUpFixture['provider'] as String,
|
||||
accessToken: oauthSignUpFixture['accessToken'] as String,
|
||||
id: oauthSignUpFixture['id'] as String,
|
||||
refreshToken: oauthSignUpFixture['refreshToken'] as String,
|
||||
firstName: oauthSignUpFixture['firstName'] as String,
|
||||
lastName: oauthSignUpFixture['lastName'] as String,
|
||||
email: oauthSignUpFixture['email'] as String,
|
||||
phone: oauthSignUpFixture['phone'] as String,
|
||||
dateOfBirth: oauthSignUpFixture['dateOfBirth'] as String,
|
||||
gender: 'Ж',
|
||||
weight: oauthSignUpFixture['weight'] as int,
|
||||
height: oauthSignUpFixture['height'] as int,
|
||||
clientId: oauthSignUpFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
expect(result, tokenFixture.token);
|
||||
verify(mockAuthService.signUpViaSocialMedia(body: oauthModel)).called(1);
|
||||
});
|
||||
|
||||
test('signUpViaSocialMedia - пробрасывает исключение', () async {
|
||||
final oauthModel = OAuthModel(
|
||||
provider: oauthSignUpFixture['provider'] as String,
|
||||
accessToken: oauthSignUpFixture['accessToken'] as String,
|
||||
id: oauthSignUpFixture['id'] as String,
|
||||
refreshToken: oauthSignUpFixture['refreshToken'] as String,
|
||||
firstName: oauthSignUpFixture['firstName'] as String,
|
||||
lastName: oauthSignUpFixture['lastName'] as String,
|
||||
email: oauthSignUpFixture['email'] as String,
|
||||
phone: oauthSignUpFixture['phone'] as String,
|
||||
dateOfBirth: oauthSignUpFixture['dateOfBirth'] as String,
|
||||
gender: 'male', // Преобразуется из 'М'
|
||||
weight: oauthSignUpFixture['weight'] as int,
|
||||
height: oauthSignUpFixture['height'] as int,
|
||||
clientId: oauthSignUpFixture['clientId'] as String,
|
||||
);
|
||||
|
||||
when(mockAuthService.signUpViaSocialMedia(body: oauthModel))
|
||||
.thenThrow(Exception('Ошибка регистрации'));
|
||||
|
||||
expect(
|
||||
() => authRepository.signUpViaSocialMedia(
|
||||
provider: oauthSignUpFixture['provider'] as String,
|
||||
accessToken: oauthSignUpFixture['accessToken'] as String,
|
||||
id: oauthSignUpFixture['id'] as String,
|
||||
refreshToken: oauthSignUpFixture['refreshToken'] as String,
|
||||
firstName: oauthSignUpFixture['firstName'] as String,
|
||||
lastName: oauthSignUpFixture['lastName'] as String,
|
||||
email: oauthSignUpFixture['email'] as String,
|
||||
phone: oauthSignUpFixture['phone'] as String,
|
||||
dateOfBirth: oauthSignUpFixture['dateOfBirth'] as String,
|
||||
gender: oauthSignUpFixture['gender'] as String,
|
||||
weight: oauthSignUpFixture['weight'] as int,
|
||||
height: oauthSignUpFixture['height'] as int,
|
||||
clientId: oauthSignUpFixture['clientId'] as String,
|
||||
),
|
||||
throwsException,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
import 'package:eatvio_app/core/models/pagination_model.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/feed_blog_post_settings_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/features/feed/repositories/feed_repository.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'feed_cubit_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<FeedRepository>()])
|
||||
void main() {
|
||||
group('FeedCubit', () {
|
||||
FeedCubit? feedCubit;
|
||||
late MockFeedRepository mockFeedRepository;
|
||||
late FeedBlogPostSettingsModel feedBlogPostsFixture;
|
||||
|
||||
setUp(() {
|
||||
mockFeedRepository = MockFeedRepository();
|
||||
|
||||
// Создаём тестовые данные
|
||||
final testPosts = [
|
||||
FeedBlogPostModel(
|
||||
id: 1,
|
||||
state: 'published',
|
||||
image: 'https://example.com/image1.jpg',
|
||||
description: 'Описание поста 1',
|
||||
author: const Author(
|
||||
authorSlug: 'author-1',
|
||||
authorName: 'Автор 1',
|
||||
authorProfileIcon: 'https://example.com/photo1.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
videoUrl: '',
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
title: 'Тестовый пост 1',
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
),
|
||||
FeedBlogPostModel(
|
||||
id: 2,
|
||||
state: 'published',
|
||||
image: 'https://example.com/image2.jpg',
|
||||
description: 'Описание поста 2',
|
||||
author: const Author(
|
||||
authorSlug: 'author-2',
|
||||
authorName: 'Автор 2',
|
||||
authorProfileIcon: 'https://example.com/photo2.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
videoUrl: '',
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
title: 'Тестовый пост 2',
|
||||
totalLikes: 20,
|
||||
totalViews: 200,
|
||||
totalComments: 10,
|
||||
wasLikedByMe: true,
|
||||
),
|
||||
];
|
||||
|
||||
feedBlogPostsFixture = FeedBlogPostSettingsModel(
|
||||
feedBlogPostList: testPosts,
|
||||
meta: const Meta(
|
||||
currentPage: 1,
|
||||
from: null,
|
||||
lastPage: 3,
|
||||
links: [],
|
||||
path: null,
|
||||
perPage: 10,
|
||||
to: null,
|
||||
total: 25,
|
||||
totalMinPrice: null,
|
||||
totalMaxPrice: null,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (feedCubit != null && !feedCubit!.isClosed) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
feedCubit!.close();
|
||||
feedCubit = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('начальное состояние - FeedStateLoading', () {
|
||||
feedCubit = FeedCubit(feedRepository: mockFeedRepository);
|
||||
expect(feedCubit!.state, const FeedState.loading());
|
||||
});
|
||||
|
||||
test('loadFeedBlogPostList - успешная загрузка постов', () async {
|
||||
feedCubit = FeedCubit(feedRepository: mockFeedRepository);
|
||||
|
||||
when(mockFeedRepository.getFeedBlogPosts(query: null))
|
||||
.thenAnswer((_) async => feedBlogPostsFixture);
|
||||
|
||||
await feedCubit!.loadFeedBlogPostList();
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(feedCubit!.state, isA<FeedStateLoaded>());
|
||||
final loadedState = feedCubit!.state as FeedStateLoaded;
|
||||
expect(loadedState.feedBlogPostList.length, 2);
|
||||
expect(loadedState.isLoading, false);
|
||||
expect(feedCubit!.lastPage, 3);
|
||||
});
|
||||
|
||||
test('loadFeedBlogPostList - загрузка с запросом', () async {
|
||||
feedCubit = FeedCubit(feedRepository: mockFeedRepository);
|
||||
const query = 'тест';
|
||||
|
||||
when(mockFeedRepository.getFeedBlogPosts(query: query))
|
||||
.thenAnswer((_) async => feedBlogPostsFixture);
|
||||
|
||||
await feedCubit!.loadFeedBlogPostList(query: query);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(feedCubit!.state, isA<FeedStateLoaded>());
|
||||
verify(mockFeedRepository.getFeedBlogPosts(query: query)).called(1);
|
||||
});
|
||||
|
||||
test('loadFeedBlogPostList - обработка ошибки', () async {
|
||||
feedCubit = FeedCubit(feedRepository: mockFeedRepository);
|
||||
|
||||
when(mockFeedRepository.getFeedBlogPosts(query: anyNamed('query')))
|
||||
.thenThrow(Exception('Ошибка загрузки'));
|
||||
|
||||
await feedCubit!.loadFeedBlogPostList();
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
expect(feedCubit!.state, isA<FeedStateError>());
|
||||
final errorState = feedCubit!.state as FeedStateError;
|
||||
expect(errorState.errorMessage, contains('Exception'));
|
||||
});
|
||||
|
||||
test('updateFeedBlogPostList - обновление лайка поста', () {
|
||||
feedCubit = FeedCubit(feedRepository: mockFeedRepository);
|
||||
|
||||
// Сначала загружаем посты
|
||||
when(mockFeedRepository.getFeedBlogPosts(query: anyNamed('query')))
|
||||
.thenAnswer((_) async => feedBlogPostsFixture);
|
||||
|
||||
// Устанавливаем состояние loaded вручную для теста
|
||||
feedCubit!.emit(FeedState.loaded(
|
||||
feedBlogPostList: feedBlogPostsFixture.feedBlogPostList,
|
||||
isLoading: false,
|
||||
));
|
||||
feedCubit!.lastPage = 3;
|
||||
|
||||
final postToUpdate = feedBlogPostsFixture.feedBlogPostList.first;
|
||||
feedCubit!.updateFeedBlogPostList(postToUpdate, true);
|
||||
|
||||
expect(feedCubit!.state, isA<FeedStateLoaded>());
|
||||
final loadedState = feedCubit!.state as FeedStateLoaded;
|
||||
final updatedPost = loadedState.feedBlogPostList.firstWhere((p) => p.id == postToUpdate.id);
|
||||
expect(updatedPost.wasLikedByMe, true);
|
||||
expect(updatedPost.totalLikes, postToUpdate.totalLikes + 1);
|
||||
});
|
||||
|
||||
test('updateFeedBlogPostList - снятие лайка', () {
|
||||
feedCubit = FeedCubit(feedRepository: mockFeedRepository);
|
||||
|
||||
feedCubit!.emit(FeedState.loaded(
|
||||
feedBlogPostList: feedBlogPostsFixture.feedBlogPostList,
|
||||
isLoading: false,
|
||||
));
|
||||
feedCubit!.lastPage = 3;
|
||||
|
||||
final postToUpdate = feedBlogPostsFixture.feedBlogPostList[1]; // У этого wasLikedByMe = true
|
||||
final initialLikes = postToUpdate.totalLikes;
|
||||
|
||||
feedCubit!.updateFeedBlogPostList(postToUpdate, false);
|
||||
|
||||
expect(feedCubit!.state, isA<FeedStateLoaded>());
|
||||
final loadedState = feedCubit!.state as FeedStateLoaded;
|
||||
final updatedPost = loadedState.feedBlogPostList.firstWhere((p) => p.id == postToUpdate.id);
|
||||
expect(updatedPost.wasLikedByMe, false);
|
||||
expect(updatedPost.totalLikes, initialLikes - 1);
|
||||
});
|
||||
|
||||
test('updateFeedBlogPostList - игнорирует обновление если состояние не loaded', () {
|
||||
feedCubit = FeedCubit(feedRepository: mockFeedRepository);
|
||||
|
||||
// Состояние loading
|
||||
feedCubit!.emit(const FeedState.loading());
|
||||
|
||||
final postToUpdate = feedBlogPostsFixture.feedBlogPostList.first;
|
||||
feedCubit!.updateFeedBlogPostList(postToUpdate, true);
|
||||
|
||||
// Состояние не должно измениться
|
||||
expect(feedCubit!.state, const FeedState.loading());
|
||||
});
|
||||
|
||||
test('updateFeedBlogPostList - игнорирует обновление если пост не найден', () {
|
||||
feedCubit = FeedCubit(feedRepository: mockFeedRepository);
|
||||
|
||||
feedCubit!.emit(FeedState.loaded(
|
||||
feedBlogPostList: feedBlogPostsFixture.feedBlogPostList,
|
||||
isLoading: false,
|
||||
));
|
||||
feedCubit!.lastPage = 3;
|
||||
|
||||
// Создаём пост с несуществующим ID
|
||||
final nonExistentPost = feedBlogPostsFixture.feedBlogPostList.first.copyWith(id: 999);
|
||||
feedCubit!.updateFeedBlogPostList(nonExistentPost, true);
|
||||
|
||||
// Список не должен измениться
|
||||
final loadedState = feedCubit!.state as FeedStateLoaded;
|
||||
expect(loadedState.feedBlogPostList.length, 2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
344
test/features/feed/repositories/feed_repository_test.dart
Normal file
344
test/features/feed/repositories/feed_repository_test.dart
Normal file
@@ -0,0 +1,344 @@
|
||||
import 'package:eatvio_app/core/models/pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/comment_model.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/feed_blog_post_settings_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/feed_consultant_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/recipes_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/recipes_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/view_model.dart';
|
||||
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/services/feed_service.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'feed_repository_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<FeedService>()])
|
||||
void main() {
|
||||
group('FeedRepository', () {
|
||||
late FeedRepository feedRepository;
|
||||
late MockFeedService mockFeedService;
|
||||
|
||||
setUp(() {
|
||||
mockFeedService = MockFeedService();
|
||||
feedRepository = FeedRepository(feedService: mockFeedService);
|
||||
});
|
||||
|
||||
test('getFeedBlogPosts - успешное получение постов', () async {
|
||||
final expectedModel = FeedBlogPostSettingsModel(
|
||||
feedBlogPostList: const [],
|
||||
meta: const Meta(
|
||||
currentPage: 1,
|
||||
from: null,
|
||||
lastPage: 1,
|
||||
links: [],
|
||||
path: null,
|
||||
perPage: 10,
|
||||
to: null,
|
||||
total: 0,
|
||||
totalMinPrice: null,
|
||||
totalMaxPrice: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockFeedService.getBlogPostList(page: 1, query: null))
|
||||
.thenAnswer((_) async => expectedModel);
|
||||
|
||||
final result = await feedRepository.getFeedBlogPosts();
|
||||
|
||||
expect(result, isA<FeedBlogPostSettingsModel>());
|
||||
verify(mockFeedService.getBlogPostList(page: 1, query: null)).called(1);
|
||||
});
|
||||
|
||||
test('getFeedBlogPosts - с запросом и страницей', () async {
|
||||
const query = 'тест';
|
||||
const page = 2;
|
||||
final expectedModel = FeedBlogPostSettingsModel(
|
||||
feedBlogPostList: const [],
|
||||
meta: const Meta(
|
||||
currentPage: page,
|
||||
from: null,
|
||||
lastPage: 2,
|
||||
links: [],
|
||||
path: null,
|
||||
perPage: 10,
|
||||
to: null,
|
||||
total: 15,
|
||||
totalMinPrice: null,
|
||||
totalMaxPrice: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockFeedService.getBlogPostList(page: page, query: query))
|
||||
.thenAnswer((_) async => expectedModel);
|
||||
|
||||
final result = await feedRepository.getFeedBlogPosts(query: query, page: page);
|
||||
|
||||
expect(result, isA<FeedBlogPostSettingsModel>());
|
||||
verify(mockFeedService.getBlogPostList(page: page, query: query)).called(1);
|
||||
});
|
||||
|
||||
test('getBlogPost - успешное получение поста', () async {
|
||||
const postId = 1;
|
||||
final expectedPost = FeedBlogPostModel(
|
||||
id: postId,
|
||||
state: 'published',
|
||||
image: 'https://example.com/image.jpg',
|
||||
description: 'Описание',
|
||||
author: const Author(
|
||||
authorSlug: 'author-slug',
|
||||
authorName: 'Автор',
|
||||
authorProfileIcon: 'https://example.com/photo.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
videoUrl: '',
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
title: 'Заголовок',
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
);
|
||||
|
||||
when(mockFeedService.getBlogPost(postId: postId))
|
||||
.thenAnswer((_) async => expectedPost);
|
||||
|
||||
final result = await feedRepository.getBlogPost(id: postId);
|
||||
|
||||
expect(result, isA<FeedBlogPostModel>());
|
||||
expect(result.id, postId);
|
||||
verify(mockFeedService.getBlogPost(postId: postId)).called(1);
|
||||
});
|
||||
|
||||
test('getRecipes - успешное получение рецептов', () async {
|
||||
final expectedRecipes = const RecipesPagination(
|
||||
recipesList: [],
|
||||
);
|
||||
|
||||
when(mockFeedService.getRecipes(query: null, tags: null, page: 1))
|
||||
.thenAnswer((_) async => expectedRecipes);
|
||||
|
||||
final result = await feedRepository.getRecipes();
|
||||
|
||||
expect(result, isA<List<Recipe>>());
|
||||
verify(mockFeedService.getRecipes(query: null, tags: null, page: 1)).called(1);
|
||||
});
|
||||
|
||||
test('getDiets - успешное получение диет', () async {
|
||||
final expectedDiets = DietsPagination(
|
||||
data: const [],
|
||||
links: const Links(first: '', last: '', prev: null, next: null),
|
||||
meta: const Meta(
|
||||
currentPage: 1,
|
||||
from: null,
|
||||
lastPage: 1,
|
||||
links: [],
|
||||
path: null,
|
||||
perPage: 10,
|
||||
to: null,
|
||||
total: 0,
|
||||
totalMinPrice: null,
|
||||
totalMaxPrice: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockFeedService.getDiets(
|
||||
page: 1,
|
||||
query: null,
|
||||
types: null,
|
||||
duration: null,
|
||||
sorting: null,
|
||||
)).thenAnswer((_) async => expectedDiets);
|
||||
|
||||
final result = await feedRepository.getDiets();
|
||||
|
||||
expect(result, isA<DietsPagination>());
|
||||
verify(mockFeedService.getDiets(
|
||||
page: 1,
|
||||
query: null,
|
||||
types: null,
|
||||
duration: null,
|
||||
sorting: null,
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('getPlans - успешное получение планов', () async {
|
||||
final expectedPlans = PlanPaginationModel(
|
||||
data: const [],
|
||||
links: const Links(first: '', last: '', prev: null, next: null),
|
||||
meta: const Meta(
|
||||
currentPage: 1,
|
||||
from: null,
|
||||
lastPage: 1,
|
||||
links: [],
|
||||
path: null,
|
||||
perPage: 10,
|
||||
to: null,
|
||||
total: 0,
|
||||
totalMinPrice: null,
|
||||
totalMaxPrice: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockFeedService.getPlans(
|
||||
page: 1,
|
||||
query: null,
|
||||
types: null,
|
||||
duration: null,
|
||||
minPrice: null,
|
||||
maxPrice: null,
|
||||
)).thenAnswer((_) async => expectedPlans);
|
||||
|
||||
final result = await feedRepository.getPlans();
|
||||
|
||||
expect(result, isA<PlanPaginationModel>());
|
||||
verify(mockFeedService.getPlans(
|
||||
page: 1,
|
||||
query: null,
|
||||
types: null,
|
||||
duration: null,
|
||||
minPrice: null,
|
||||
maxPrice: null,
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('getBlogPostComments - успешное получение комментариев', () async {
|
||||
const postId = '1';
|
||||
final expectedComments = CommentModel(
|
||||
data: [],
|
||||
links: const Links(first: '', last: '', prev: null, next: null),
|
||||
meta: const Meta(
|
||||
currentPage: 1,
|
||||
from: null,
|
||||
lastPage: 1,
|
||||
links: [],
|
||||
path: null,
|
||||
perPage: 10,
|
||||
to: null,
|
||||
total: 0,
|
||||
totalMinPrice: null,
|
||||
totalMaxPrice: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockFeedService.getBlogPostComments(id: postId))
|
||||
.thenAnswer((_) async => expectedComments);
|
||||
|
||||
final result = await feedRepository.getBlogPostComments(id: postId);
|
||||
|
||||
expect(result, isA<CommentModel>());
|
||||
verify(mockFeedService.getBlogPostComments(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('sendBlogPostComment - успешная отправка комментария', () async {
|
||||
const postId = '1';
|
||||
const commentText = 'Тестовый комментарий';
|
||||
|
||||
when(mockFeedService.sendBlogPostComment(
|
||||
id: postId,
|
||||
body: commentText,
|
||||
parentCommentId: null,
|
||||
)).thenAnswer((_) async => Future.value());
|
||||
|
||||
await feedRepository.sendBlogPostComment(id: postId, commentText: commentText);
|
||||
|
||||
verify(mockFeedService.sendBlogPostComment(
|
||||
id: postId,
|
||||
body: commentText,
|
||||
parentCommentId: null,
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('likeBlogPost - успешный лайк поста', () async {
|
||||
const postId = 1;
|
||||
|
||||
when(mockFeedService.likeBlogPost(id: postId))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
await feedRepository.likeBlogPost(id: postId);
|
||||
|
||||
verify(mockFeedService.likeBlogPost(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('unlikedBlogPost - успешное снятие лайка', () async {
|
||||
const postId = 1;
|
||||
|
||||
when(mockFeedService.unlikedBlogPost(id: postId))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
await feedRepository.unlikedBlogPost(id: postId);
|
||||
|
||||
verify(mockFeedService.unlikedBlogPost(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('getConsultants - успешное получение консультантов', () async {
|
||||
final expectedConsultants = FeedConsultantPaginationModel(
|
||||
data: const [],
|
||||
links: const Links(first: '', last: '', prev: null, next: null),
|
||||
meta: const Meta(
|
||||
currentPage: 1,
|
||||
from: null,
|
||||
lastPage: 1,
|
||||
links: [],
|
||||
path: null,
|
||||
perPage: 10,
|
||||
to: null,
|
||||
total: 0,
|
||||
totalMinPrice: null,
|
||||
totalMaxPrice: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockFeedService.getConsultants(name: null))
|
||||
.thenAnswer((_) async => expectedConsultants);
|
||||
|
||||
final result = await feedRepository.getConsultants();
|
||||
|
||||
expect(result, isA<List<FeedConsultantModel>>());
|
||||
verify(mockFeedService.getConsultants(name: null)).called(1);
|
||||
});
|
||||
|
||||
test('viewPost - успешное просмотр поста', () async {
|
||||
const postId = 1;
|
||||
|
||||
when(mockFeedService.viewPost(id: postId))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
await feedRepository.viewPost(postId);
|
||||
|
||||
verify(mockFeedService.viewPost(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('viewContent - успешный просмотр контента', () async {
|
||||
final viewModel = ViewModel(
|
||||
type: 'blog_post',
|
||||
ids: [1],
|
||||
slugs: null,
|
||||
);
|
||||
|
||||
when(mockFeedService.viewContent(viewModel: viewModel))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
await feedRepository.viewContent(viewModel: viewModel);
|
||||
|
||||
verify(mockFeedService.viewContent(viewModel: viewModel)).called(1);
|
||||
});
|
||||
|
||||
test('getFeedBlogPosts - пробрасывает исключение', () async {
|
||||
when(mockFeedService.getBlogPostList(page: 1, query: null))
|
||||
.thenThrow(Exception('Ошибка сети'));
|
||||
|
||||
expect(
|
||||
() => feedRepository.getFeedBlogPosts(),
|
||||
throwsException,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
7
test/fixtures/auth/oauth_signin_request.json
vendored
Normal file
7
test/fixtures/auth/oauth_signin_request.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"provider": "vk",
|
||||
"accessToken": "vk_access_token_123",
|
||||
"refreshToken": "vk_refresh_token_123",
|
||||
"clientId": "vk_client_id_123"
|
||||
}
|
||||
|
||||
16
test/fixtures/auth/oauth_signup_request.json
vendored
Normal file
16
test/fixtures/auth/oauth_signup_request.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"provider": "vk",
|
||||
"accessToken": "vk_access_token_123",
|
||||
"id": "vk_user_id_123",
|
||||
"refreshToken": "vk_refresh_token_123",
|
||||
"firstName": "Иван",
|
||||
"lastName": "Иванов",
|
||||
"email": "ivan@example.com",
|
||||
"phone": "+79001234567",
|
||||
"dateOfBirth": "1990-01-01",
|
||||
"gender": "М",
|
||||
"weight": 75,
|
||||
"height": 180,
|
||||
"clientId": "vk_client_id_123"
|
||||
}
|
||||
|
||||
7
test/fixtures/auth/reset_password_request.json
vendored
Normal file
7
test/fixtures/auth/reset_password_request.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"code": "123456",
|
||||
"password": "newPassword123",
|
||||
"passwordConfirmation": "newPassword123"
|
||||
}
|
||||
|
||||
33
test/fixtures/feed/feed_blog_posts_response.json
vendored
Normal file
33
test/fixtures/feed/feed_blog_posts_response.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"feedBlogPostList": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Тестовый пост",
|
||||
"content": "Содержимое поста",
|
||||
"author": "Автор",
|
||||
"createdAt": "2024-01-01T00:00:00Z",
|
||||
"totalLikes": 10,
|
||||
"wasLikedByMe": false,
|
||||
"totalComments": 5,
|
||||
"totalViews": 100
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Второй пост",
|
||||
"content": "Еще одно содержимое",
|
||||
"author": "Другой автор",
|
||||
"createdAt": "2024-01-02T00:00:00Z",
|
||||
"totalLikes": 20,
|
||||
"wasLikedByMe": true,
|
||||
"totalComments": 10,
|
||||
"totalViews": 200
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"currentPage": 1,
|
||||
"lastPage": 3,
|
||||
"perPage": 10,
|
||||
"total": 25
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user