···
+
import 'package:coves_flutter/models/comment.dart';
+
import 'package:coves_flutter/services/coves_api_service.dart';
+
import 'package:dio/dio.dart';
+
import 'package:flutter_test/flutter_test.dart';
+
import 'package:http_mock_adapter/http_mock_adapter.dart';
+
TestWidgetsFlutterBinding.ensureInitialized();
+
group('CovesApiService - getComments', () {
+
late DioAdapter dioAdapter;
+
late CovesApiService apiService;
+
dio = Dio(BaseOptions(baseUrl: 'https://api.test.coves.social'));
+
dioAdapter = DioAdapter(dio: dio);
+
apiService = CovesApiService(
+
tokenGetter: () async => 'test-token',
+
test('should successfully fetch comments', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'cursor': 'next-cursor',
+
'uri': 'at://did:plc:test/comment/1',
+
'content': 'Test comment 1',
+
'createdAt': '2025-01-01T12:00:00Z',
+
'indexedAt': '2025-01-01T12:00:00Z',
+
'did': 'did:plc:author1',
+
'handle': 'user1.test',
+
'displayName': 'User One',
+
'uri': 'at://did:plc:test/comment/2',
+
'content': 'Test comment 2',
+
'createdAt': '2025-01-01T13:00:00Z',
+
'indexedAt': '2025-01-01T13:00:00Z',
+
'did': 'did:plc:author2',
+
'handle': 'user2.test',
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(postUri: postUri);
+
expect(response, isA<CommentsResponse>());
+
expect(response.comments.length, 2);
+
expect(response.cursor, 'next-cursor');
+
expect(response.comments[0].comment.uri, 'at://did:plc:test/comment/1');
+
expect(response.comments[0].comment.content, 'Test comment 1');
+
expect(response.comments[1].comment.uri, 'at://did:plc:test/comment/2');
+
test('should handle empty comments response', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(postUri: postUri);
+
expect(response.comments, isEmpty);
+
expect(response.cursor, null);
+
test('should handle null comments array', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(postUri: postUri);
+
expect(response.comments, isEmpty);
+
test('should fetch comments with custom sort option', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'uri': 'at://did:plc:test/comment/1',
+
'content': 'Newest comment',
+
'createdAt': '2025-01-01T15:00:00Z',
+
'indexedAt': '2025-01-01T15:00:00Z',
+
'did': 'did:plc:author',
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(
+
expect(response.comments.length, 1);
+
expect(response.comments[0].comment.content, 'Newest comment');
+
test('should fetch comments with timeframe', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(
+
expect(response, isA<CommentsResponse>());
+
test('should fetch comments with cursor for pagination', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
const cursor = 'pagination-cursor-123';
+
'post': {'uri': postUri},
+
'cursor': 'next-cursor-456',
+
'uri': 'at://did:plc:test/comment/10',
+
'content': 'Paginated comment',
+
'createdAt': '2025-01-01T12:00:00Z',
+
'indexedAt': '2025-01-01T12:00:00Z',
+
'did': 'did:plc:author',
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(
+
expect(response.comments.length, 1);
+
expect(response.cursor, 'next-cursor-456');
+
test('should fetch comments with custom depth and limit', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(
+
expect(response, isA<CommentsResponse>());
+
test('should handle 404 error', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/nonexistent';
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(404, {
+
'error': 'NotFoundError',
+
'message': 'Post not found',
+
() => apiService.getComments(postUri: postUri),
+
throwsA(isA<Exception>()),
+
test('should handle 500 internal server error', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(500, {
+
'error': 'InternalServerError',
+
'message': 'Database connection failed',
+
() => apiService.getComments(postUri: postUri),
+
throwsA(isA<Exception>()),
+
test('should handle network timeout', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.throws(
+
DioException.connectionTimeout(
+
timeout: const Duration(seconds: 30),
+
requestOptions: RequestOptions(path: ''),
+
() => apiService.getComments(postUri: postUri),
+
throwsA(isA<DioException>()),
+
test('should handle network connection error', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.throws(
+
DioException.connectionError(
+
reason: 'Connection refused',
+
requestOptions: RequestOptions(path: ''),
+
() => apiService.getComments(postUri: postUri),
+
throwsA(isA<DioException>()),
+
test('should handle invalid JSON response', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, 'invalid json string'),
+
() => apiService.getComments(postUri: postUri),
+
throwsA(isA<Exception>()),
+
test('should handle malformed JSON with missing required fields', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'uri': 'at://did:plc:test/comment/1',
+
// Missing required 'cid' field
+
'createdAt': '2025-01-01T12:00:00Z',
+
'indexedAt': '2025-01-01T12:00:00Z',
+
'did': 'did:plc:author',
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
() => apiService.getComments(postUri: postUri),
+
throwsA(isA<Exception>()),
+
test('should handle comments with nested replies', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'uri': 'at://did:plc:test/comment/1',
+
'content': 'Parent comment',
+
'createdAt': '2025-01-01T12:00:00Z',
+
'indexedAt': '2025-01-01T12:00:00Z',
+
'did': 'did:plc:author1',
+
'handle': 'user1.test',
+
'uri': 'at://did:plc:test/comment/2',
+
'content': 'Reply comment',
+
'createdAt': '2025-01-01T13:00:00Z',
+
'indexedAt': '2025-01-01T13:00:00Z',
+
'did': 'did:plc:author2',
+
'handle': 'user2.test',
+
'uri': 'at://did:plc:test/comment/1',
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(postUri: postUri);
+
expect(response.comments.length, 1);
+
expect(response.comments[0].comment.content, 'Parent comment');
+
expect(response.comments[0].replies, isNotNull);
+
expect(response.comments[0].replies!.length, 1);
+
expect(response.comments[0].replies![0].comment.content, 'Reply comment');
+
test('should handle comments with viewer state', () async {
+
const postUri = 'at://did:plc:test/social.coves.post.record/123';
+
'post': {'uri': postUri},
+
'uri': 'at://did:plc:test/comment/1',
+
'content': 'Voted comment',
+
'createdAt': '2025-01-01T12:00:00Z',
+
'indexedAt': '2025-01-01T12:00:00Z',
+
'did': 'did:plc:author',
+
'/xrpc/social.coves.community.comment.getComments',
+
(server) => server.reply(200, mockResponse),
+
final response = await apiService.getComments(postUri: postUri);
+
expect(response.comments.length, 1);
+
expect(response.comments[0].comment.viewer, isNotNull);
+
expect(response.comments[0].comment.viewer!.vote, 'upvote');