Main coves client
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('VoteResponse', () {
9 test('should create response with uri, cid, and rkey', () {
10 const response = VoteResponse(
11 uri: 'at://did:plc:test/social.coves.feed.vote/123',
12 cid: 'bafy123',
13 rkey: '123',
14 deleted: false,
15 );
16
17 expect(response.uri, 'at://did:plc:test/social.coves.feed.vote/123');
18 expect(response.cid, 'bafy123');
19 expect(response.rkey, '123');
20 expect(response.deleted, false);
21 });
22
23 test('should create deleted response', () {
24 const response = VoteResponse(deleted: true);
25
26 expect(response.deleted, true);
27 expect(response.uri, null);
28 expect(response.cid, null);
29 expect(response.rkey, null);
30 });
31 });
32
33 group('API Exception handling', () {
34 test('should throw ApiException on Dio network error', () {
35 final dioError = DioException(
36 requestOptions: RequestOptions(path: '/test'),
37 type: DioExceptionType.connectionError,
38 );
39
40 final exception = ApiException.fromDioError(dioError);
41
42 expect(exception, isA<NetworkException>());
43 expect(exception.message, contains('Connection failed'));
44 });
45
46 test('should throw ApiException on Dio timeout', () {
47 final dioError = DioException(
48 requestOptions: RequestOptions(path: '/test'),
49 type: DioExceptionType.connectionTimeout,
50 );
51
52 final exception = ApiException.fromDioError(dioError);
53
54 expect(exception, isA<NetworkException>());
55 expect(exception.message, contains('timeout'));
56 });
57
58 test('should throw AuthenticationException on 401 response', () {
59 final dioError = DioException(
60 requestOptions: RequestOptions(path: '/test'),
61 type: DioExceptionType.badResponse,
62 response: Response(
63 requestOptions: RequestOptions(path: '/test'),
64 statusCode: 401,
65 data: {'message': 'Unauthorized'},
66 ),
67 );
68
69 final exception = ApiException.fromDioError(dioError);
70
71 expect(exception, isA<AuthenticationException>());
72 expect(exception.statusCode, 401);
73 expect(exception.message, 'Unauthorized');
74 });
75
76 test('should throw NotFoundException on 404 response', () {
77 final dioError = DioException(
78 requestOptions: RequestOptions(path: '/test'),
79 type: DioExceptionType.badResponse,
80 response: Response(
81 requestOptions: RequestOptions(path: '/test'),
82 statusCode: 404,
83 data: {'message': 'Post not found'},
84 ),
85 );
86
87 final exception = ApiException.fromDioError(dioError);
88
89 expect(exception, isA<NotFoundException>());
90 expect(exception.statusCode, 404);
91 expect(exception.message, 'Post not found');
92 });
93
94 test('should throw ServerException on 500 response', () {
95 final dioError = DioException(
96 requestOptions: RequestOptions(path: '/test'),
97 type: DioExceptionType.badResponse,
98 response: Response(
99 requestOptions: RequestOptions(path: '/test'),
100 statusCode: 500,
101 data: {'error': 'Internal server error'},
102 ),
103 );
104
105 final exception = ApiException.fromDioError(dioError);
106
107 expect(exception, isA<ServerException>());
108 expect(exception.statusCode, 500);
109 expect(exception.message, 'Internal server error');
110 });
111
112 test('should extract error message from response data', () {
113 final dioError = DioException(
114 requestOptions: RequestOptions(path: '/test'),
115 type: DioExceptionType.badResponse,
116 response: Response(
117 requestOptions: RequestOptions(path: '/test'),
118 statusCode: 400,
119 data: {'message': 'Invalid post URI'},
120 ),
121 );
122
123 final exception = ApiException.fromDioError(dioError);
124
125 expect(exception.message, 'Invalid post URI');
126 expect(exception.statusCode, 400);
127 });
128
129 test('should use default message if no error message in response', () {
130 final dioError = DioException(
131 requestOptions: RequestOptions(path: '/test'),
132 type: DioExceptionType.badResponse,
133 response: Response(
134 requestOptions: RequestOptions(path: '/test'),
135 statusCode: 400,
136 data: {},
137 ),
138 );
139
140 final exception = ApiException.fromDioError(dioError);
141
142 expect(exception.message, 'Server error');
143 });
144
145 test('should handle cancelled requests', () {
146 final dioError = DioException(
147 requestOptions: RequestOptions(path: '/test'),
148 type: DioExceptionType.cancel,
149 );
150
151 final exception = ApiException.fromDioError(dioError);
152
153 expect(exception.message, contains('cancelled'));
154 });
155
156 test('should handle bad certificate errors', () {
157 final dioError = DioException(
158 requestOptions: RequestOptions(path: '/test'),
159 type: DioExceptionType.badCertificate,
160 );
161
162 final exception = ApiException.fromDioError(dioError);
163
164 expect(exception, isA<NetworkException>());
165 expect(exception.message, contains('certificate'));
166 });
167
168 test('should handle unknown errors', () {
169 final dioError = DioException(
170 requestOptions: RequestOptions(path: '/test'),
171 );
172
173 final exception = ApiException.fromDioError(dioError);
174
175 expect(exception, isA<NetworkException>());
176 expect(exception.message, contains('Network error'));
177 });
178 });
179 });
180}