1import 'package:coves_flutter/services/api_exceptions.dart'; 2import 'package:coves_flutter/services/vote_service.dart'; 3import 'package:dio/dio.dart'; 4import 'package:flutter_test/flutter_test.dart'; 5 6void main() { 7 group('VoteService', () { 8 group('createVote', () { 9 10 test('should create vote successfully', () async { 11 // Create a real VoteService instance that we can test with 12 // We'll use a minimal test to verify the VoteResponse parsing logic 13 14 const response = VoteResponse( 15 uri: 'at://did:plc:test/social.coves.interaction.vote/456', 16 cid: 'bafy123', 17 rkey: '456', 18 deleted: false, 19 ); 20 21 expect(response.uri, 'at://did:plc:test/social.coves.interaction.vote/456'); 22 expect(response.cid, 'bafy123'); 23 expect(response.rkey, '456'); 24 expect(response.deleted, false); 25 }); 26 27 test('should return deleted response when vote is toggled off', () { 28 const response = VoteResponse(deleted: true); 29 30 expect(response.deleted, true); 31 expect(response.uri, null); 32 expect(response.cid, null); 33 }); 34 35 test('should throw ApiException on Dio network error', () { 36 // Test ApiException.fromDioError for connection errors 37 final dioError = DioException( 38 requestOptions: RequestOptions(path: '/test'), 39 type: DioExceptionType.connectionError, 40 ); 41 42 final exception = ApiException.fromDioError(dioError); 43 44 expect(exception, isA<NetworkException>()); 45 expect( 46 exception.message, 47 contains('Connection failed'), 48 ); 49 }); 50 51 test('should throw ApiException on Dio timeout', () { 52 final dioError = DioException( 53 requestOptions: RequestOptions(path: '/test'), 54 type: DioExceptionType.connectionTimeout, 55 ); 56 57 final exception = ApiException.fromDioError(dioError); 58 59 expect(exception, isA<NetworkException>()); 60 expect(exception.message, contains('timeout')); 61 }); 62 63 test('should throw AuthenticationException on 401 response', () { 64 final dioError = DioException( 65 requestOptions: RequestOptions(path: '/test'), 66 type: DioExceptionType.badResponse, 67 response: Response( 68 requestOptions: RequestOptions(path: '/test'), 69 statusCode: 401, 70 data: {'message': 'Unauthorized'}, 71 ), 72 ); 73 74 final exception = ApiException.fromDioError(dioError); 75 76 expect(exception, isA<AuthenticationException>()); 77 expect(exception.statusCode, 401); 78 expect(exception.message, 'Unauthorized'); 79 }); 80 81 test('should throw NotFoundException on 404 response', () { 82 final dioError = DioException( 83 requestOptions: RequestOptions(path: '/test'), 84 type: DioExceptionType.badResponse, 85 response: Response( 86 requestOptions: RequestOptions(path: '/test'), 87 statusCode: 404, 88 data: {'message': 'Post not found'}, 89 ), 90 ); 91 92 final exception = ApiException.fromDioError(dioError); 93 94 expect(exception, isA<NotFoundException>()); 95 expect(exception.statusCode, 404); 96 expect(exception.message, 'Post not found'); 97 }); 98 99 test('should throw ServerException on 500 response', () { 100 final dioError = DioException( 101 requestOptions: RequestOptions(path: '/test'), 102 type: DioExceptionType.badResponse, 103 response: Response( 104 requestOptions: RequestOptions(path: '/test'), 105 statusCode: 500, 106 data: {'error': 'Internal server error'}, 107 ), 108 ); 109 110 final exception = ApiException.fromDioError(dioError); 111 112 expect(exception, isA<ServerException>()); 113 expect(exception.statusCode, 500); 114 expect(exception.message, 'Internal server error'); 115 }); 116 117 test('should extract error message from response data', () { 118 final dioError = DioException( 119 requestOptions: RequestOptions(path: '/test'), 120 type: DioExceptionType.badResponse, 121 response: Response( 122 requestOptions: RequestOptions(path: '/test'), 123 statusCode: 400, 124 data: {'message': 'Invalid post URI'}, 125 ), 126 ); 127 128 final exception = ApiException.fromDioError(dioError); 129 130 expect(exception.message, 'Invalid post URI'); 131 expect(exception.statusCode, 400); 132 }); 133 134 test('should use default message if no error message in response', () { 135 final dioError = DioException( 136 requestOptions: RequestOptions(path: '/test'), 137 type: DioExceptionType.badResponse, 138 response: Response( 139 requestOptions: RequestOptions(path: '/test'), 140 statusCode: 400, 141 data: {}, 142 ), 143 ); 144 145 final exception = ApiException.fromDioError(dioError); 146 147 expect(exception.message, 'Server error'); 148 }); 149 150 test('should handle cancelled requests', () { 151 final dioError = DioException( 152 requestOptions: RequestOptions(path: '/test'), 153 type: DioExceptionType.cancel, 154 ); 155 156 final exception = ApiException.fromDioError(dioError); 157 158 expect(exception.message, contains('cancelled')); 159 }); 160 161 test('should handle bad certificate errors', () { 162 final dioError = DioException( 163 requestOptions: RequestOptions(path: '/test'), 164 type: DioExceptionType.badCertificate, 165 ); 166 167 final exception = ApiException.fromDioError(dioError); 168 169 expect(exception, isA<NetworkException>()); 170 expect(exception.message, contains('certificate')); 171 }); 172 173 test('should handle unknown errors', () { 174 final dioError = DioException( 175 requestOptions: RequestOptions(path: '/test'), 176 ); 177 178 final exception = ApiException.fromDioError(dioError); 179 180 expect(exception, isA<NetworkException>()); 181 expect(exception.message, contains('Network error')); 182 }); 183 }); 184 185 group('VoteResponse', () { 186 test('should create response with uri, cid, and rkey', () { 187 const response = VoteResponse( 188 uri: 'at://vote/123', 189 cid: 'bafy123', 190 rkey: '123', 191 deleted: false, 192 ); 193 194 expect(response.uri, 'at://vote/123'); 195 expect(response.cid, 'bafy123'); 196 expect(response.rkey, '123'); 197 expect(response.deleted, false); 198 }); 199 200 test('should create response with rkey extracted from uri', () { 201 const response = VoteResponse( 202 uri: 'at://vote/456', 203 cid: 'bafy456', 204 rkey: '456', 205 deleted: false, 206 ); 207 208 expect(response.uri, 'at://vote/456'); 209 expect(response.cid, 'bafy456'); 210 expect(response.rkey, '456'); 211 expect(response.deleted, false); 212 }); 213 214 test('should create deleted response', () { 215 const response = VoteResponse(deleted: true); 216 217 expect(response.deleted, true); 218 expect(response.uri, null); 219 expect(response.cid, null); 220 expect(response.rkey, null); 221 }); 222 }); 223 }); 224}