Files
ReelShort/test/comment/comment_controller_test.dart
T

193 lines
6.1 KiB
Dart

// Author: fruit.com.cn
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/data/models/comment.dart';
import 'package:fruitshorts/core/data/models/interaction.dart';
import 'package:fruitshorts/core/data/remote/api_client.dart';
import 'package:fruitshorts/core/data/services/comment_controller.dart';
import '../support/fake_interaction_repositories.dart';
void main() {
CommentController controller(
FakeCommentRepository comments, {
FakeInteractionRepository? interactions,
}) => CommentController(
comments: comments,
interactions: interactions ?? FakeInteractionRepository(),
dramaId: '5',
);
test('should_append_next_page_with_cursor_when_has_more_is_true', () async {
final repository = FakeCommentRepository(
pages: [
CommentPage(
comments: [commentFixture(id: '2')],
nextCursor: '2',
hasMore: true,
),
CommentPage(comments: [commentFixture(id: '1')]),
],
);
final model = controller(repository);
await model.load();
await model.loadMore();
expect(model.comments.map((item) => item.id), ['2', '1']);
expect(model.hasMore, isFalse);
expect(repository.pageCalls[0].cursor, isNull);
expect(repository.pageCalls[1].cursor, '2');
expect(repository.pageCalls.every((call) => call.size == 20), isTrue);
model.dispose();
});
test('should_use_server_content_and_pending_status_when_review_is_returned', () async {
final repository = FakeCommentRepository(
publishResult: commentFixture(
id: '3',
content: 'replaced ***',
status: 'pending',
mine: true,
),
);
final model = controller(repository);
final result = await model.publish(' replaced badword ');
expect(result.isSuccess, isTrue);
expect(repository.publishCalls.single.content, 'replaced badword');
expect(model.comments.single.content, 'replaced ***');
expect(model.comments.single.isPending, isTrue);
model.dispose();
});
test('should_expose_backend_message_and_keep_existing_list_when_publish_is_blocked', () async {
final repository = FakeCommentRepository(
publishError: const ApiException(400, '评论包含敏感词'),
);
final model = controller(repository);
await model.load();
final result = await model.publish('blocked');
expect(result.isSuccess, isFalse);
expect(result.errorMessage, '评论包含敏感词');
expect(model.comments, isEmpty);
model.dispose();
});
test('should_insert_reply_under_root_and_request_replies_with_root_id', () async {
final root = commentFixture(id: '10', replyCount: 1);
final reply = commentFixture(
id: '11',
parentId: '10',
rootId: '10',
content: 'Reply',
mine: true,
);
final repository = FakeCommentRepository(
pages: [
CommentPage(comments: [root]),
CommentPage(comments: [reply]),
],
publishResult: reply,
);
final model = controller(repository);
await model.load();
await model.loadReplies('10');
final result = await model.publish('Reply', replyTo: root);
expect(result.isSuccess, isTrue);
expect(repository.publishCalls.single.parentId, '10');
expect(repository.pageCalls.last.rootId, '10');
expect(model.repliesFor('10').map((item) => item.id), ['11']);
model.dispose();
});
test('should_restore_comment_at_original_position_when_delete_fails', () async {
final first = commentFixture(id: '2', mine: true);
final second = commentFixture(id: '1');
final repository = FakeCommentRepository(
pages: [
CommentPage(comments: [first, second]),
],
deleteError: const ApiException(500, '删除失败'),
);
final model = controller(repository);
await model.load();
final result = await model.delete(first);
expect(result.isSuccess, isFalse);
expect(result.errorMessage, '删除失败');
expect(model.comments.map((item) => item.id), ['2', '1']);
expect(repository.deleteCalls, ['2']);
model.dispose();
});
test('should_remove_own_comment_when_delete_succeeds', () async {
final own = commentFixture(id: '2', mine: true);
final repository = FakeCommentRepository(
pages: [
CommentPage(comments: [own]),
],
);
final model = controller(repository);
await model.load();
final result = await model.delete(own);
expect(result.isSuccess, isTrue);
expect(model.comments, isEmpty);
model.dispose();
});
test('should_optimistically_update_comment_like_and_apply_server_count', () async {
final comment = commentFixture(id: '2', likeCount: 3, liked: false);
final interactions = FakeInteractionRepository(
nextLikeResult: const LikeToggleResult(liked: true, count: 8),
);
final repository = FakeCommentRepository(
pages: [
CommentPage(comments: [comment]),
],
);
final model = controller(repository, interactions: interactions);
await model.load();
final pending = model.toggleLike(comment);
expect(model.comments.single.liked, isTrue);
expect(model.comments.single.likeCount, 4);
final result = await pending;
expect(result.isSuccess, isTrue);
expect(model.comments.single.liked, isTrue);
expect(model.comments.single.likeCount, 8);
expect(interactions.likeTargets, ['COMMENT:2']);
model.dispose();
});
test('should_rollback_comment_like_when_request_fails', () async {
final comment = commentFixture(id: '2', likeCount: 3, liked: true);
final interactions = FakeInteractionRepository()
..likeError = const ApiException(500, '点赞失败');
final repository = FakeCommentRepository(
pages: [
CommentPage(comments: [comment]),
],
);
final model = controller(repository, interactions: interactions);
await model.load();
final result = await model.toggleLike(comment);
expect(result.isSuccess, isFalse);
expect(result.errorMessage, '点赞失败');
expect(model.comments.single.liked, isTrue);
expect(model.comments.single.likeCount, 3);
model.dispose();
});
}