214 lines
6.6 KiB
Dart
214 lines
6.6 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_expose_exact_count_only_when_last_page_is_loaded', () 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();
|
|
expect(model.exactCount, isNull);
|
|
|
|
await model.loadMore();
|
|
expect(model.exactCount, 2);
|
|
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();
|
|
});
|
|
}
|