220 lines
6.5 KiB
Dart
220 lines
6.5 KiB
Dart
import 'package:dio/dio.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:social_app/data/network/i_api_client.dart';
|
|
import 'package:social_app/data/cache/cache_store.dart';
|
|
import 'package:social_app/features/calendar/data/repositories/calendar_repository.dart';
|
|
import 'package:social_app/features/contacts/data/repositories/friend_repository.dart';
|
|
import 'package:social_app/features/messages/data/repositories/inbox_repository.dart';
|
|
import 'package:social_app/features/contacts/data/models/friend_request.dart';
|
|
import 'package:social_app/features/messages/data/models/inbox_message.dart';
|
|
import 'package:social_app/features/calendar/data/models/schedule_item_model.dart';
|
|
import 'package:social_app/features/contacts/data/repositories/user_repository.dart';
|
|
|
|
class _FakeApiClient implements IApiClient {
|
|
final Map<String, dynamic> _getResponses = <String, dynamic>{};
|
|
final Map<String, dynamic> _postResponses = <String, dynamic>{};
|
|
final Map<String, dynamic> _patchResponses = <String, dynamic>{};
|
|
|
|
void setGet(String path, dynamic data) => _getResponses[path] = data;
|
|
|
|
void setPost(String path, dynamic data) => _postResponses[path] = data;
|
|
|
|
void setPatch(String path, dynamic data) => _patchResponses[path] = data;
|
|
|
|
@override
|
|
Future<Response<T>> get<T>(
|
|
String path, {
|
|
Map<String, String>? queryParameters,
|
|
Options? options,
|
|
}) async {
|
|
if (!_getResponses.containsKey(path)) {
|
|
throw StateError('missing GET mock for $path');
|
|
}
|
|
return Response<T>(
|
|
requestOptions: RequestOptions(path: path),
|
|
data: _getResponses[path] as T,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<Response<T>> post<T>(
|
|
String path, {
|
|
dynamic data,
|
|
Options? options,
|
|
}) async {
|
|
if (!_postResponses.containsKey(path)) {
|
|
throw StateError('missing POST mock for $path');
|
|
}
|
|
return Response<T>(
|
|
requestOptions: RequestOptions(path: path),
|
|
data: _postResponses[path] as T,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<Response<T>> patch<T>(
|
|
String path, {
|
|
dynamic data,
|
|
Options? options,
|
|
}) async {
|
|
if (!_patchResponses.containsKey(path)) {
|
|
throw StateError('missing PATCH mock for $path');
|
|
}
|
|
return Response<T>(
|
|
requestOptions: RequestOptions(path: path),
|
|
data: _patchResponses[path] as T,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<Response<T>> delete<T>(String path, {dynamic data, Options? options}) {
|
|
throw UnimplementedError();
|
|
}
|
|
|
|
@override
|
|
Future<Stream<String>> getSseLines(
|
|
String path, {
|
|
Map<String, String>? headers,
|
|
}) {
|
|
throw UnimplementedError();
|
|
}
|
|
|
|
@override
|
|
Future<Response<T>> put<T>(String path, {dynamic data, Options? options}) {
|
|
throw UnimplementedError();
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
test('InboxRepository maps message type and status', () async {
|
|
final client = _FakeApiClient();
|
|
client.setGet('/api/v1/inbox/messages?is_read=false', [
|
|
{
|
|
'id': 'm1',
|
|
'recipient_id': 'u1',
|
|
'sender_id': 'u2',
|
|
'message_type': 'calendar',
|
|
'schedule_item_id': 's1',
|
|
'friendship_id': null,
|
|
'content': {'type': 'invite'},
|
|
'is_read': false,
|
|
'status': 'pending',
|
|
'created_at': '2026-03-27T08:00:00Z',
|
|
},
|
|
]);
|
|
|
|
final repository = InboxRepositoryImpl(
|
|
apiClient: client,
|
|
store: HybridCacheStore(
|
|
memory: MemoryCacheStore(),
|
|
persistent: PersistentCacheStore(),
|
|
),
|
|
);
|
|
final result = await repository.getMessages(isRead: false);
|
|
|
|
expect(result.single.messageType, InboxMessageType.calendar);
|
|
expect(result.single.status, InboxMessageStatus.pending);
|
|
expect(result.single.scheduleItemId, 's1');
|
|
});
|
|
|
|
test('FriendRepository maps request status', () async {
|
|
final client = _FakeApiClient();
|
|
client.setGet('/api/v1/friends/requests/f1', {
|
|
'id': 'f1',
|
|
'sender': {'id': 'u1', 'username': 'alice', 'avatar_url': null},
|
|
'recipient': {'id': 'u2', 'username': 'bob', 'avatar_url': null},
|
|
'content': {'message': 'hi'},
|
|
'status': 'accepted',
|
|
'created_at': '2026-03-27T08:00:00Z',
|
|
});
|
|
|
|
final repository = FriendRepositoryImpl(
|
|
apiClient: client,
|
|
store: HybridCacheStore(
|
|
memory: MemoryCacheStore(),
|
|
persistent: PersistentCacheStore(),
|
|
),
|
|
);
|
|
final request = await repository.getRequestById('f1');
|
|
|
|
expect(request.status, FriendRequestStatus.accepted);
|
|
expect(request.sender.username, 'alice');
|
|
});
|
|
|
|
test(
|
|
'FriendRepository batch lookup fails when any request is missing',
|
|
() async {
|
|
final client = _FakeApiClient();
|
|
client.setGet('/api/v1/friends/requests/f1', {
|
|
'id': 'f1',
|
|
'sender': {'id': 'u1', 'username': 'alice', 'avatar_url': null},
|
|
'recipient': {'id': 'u2', 'username': 'bob', 'avatar_url': null},
|
|
'content': {'message': 'hi'},
|
|
'status': 'pending',
|
|
'created_at': '2026-03-27T08:00:00Z',
|
|
});
|
|
|
|
final repository = FriendRepositoryImpl(
|
|
apiClient: client,
|
|
store: HybridCacheStore(
|
|
memory: MemoryCacheStore(),
|
|
persistent: PersistentCacheStore(),
|
|
),
|
|
);
|
|
await expectLater(
|
|
repository.getRequestsByIds(['f1', 'missing']),
|
|
throwsStateError,
|
|
);
|
|
},
|
|
);
|
|
|
|
test('CalendarRepository maps archived status', () async {
|
|
final client = _FakeApiClient();
|
|
client.setGet('/api/v1/schedule-items/e1', {
|
|
'id': 'e1',
|
|
'owner_id': 'u1',
|
|
'permission': 1,
|
|
'is_owner': true,
|
|
'title': 'event',
|
|
'description': null,
|
|
'start_at': '2026-03-27T08:00:00Z',
|
|
'end_at': null,
|
|
'timezone': 'UTC',
|
|
'metadata': null,
|
|
'source_type': 'manual',
|
|
'status': 'archived',
|
|
'created_at': '2026-03-27T08:00:00Z',
|
|
'updated_at': '2026-03-27T09:00:00Z',
|
|
});
|
|
|
|
final repository = CalendarRepository(
|
|
store: HybridCacheStore(
|
|
memory: MemoryCacheStore(),
|
|
persistent: PersistentCacheStore(),
|
|
),
|
|
apiClient: client,
|
|
);
|
|
final event = await repository.getById('e1');
|
|
|
|
expect(event.status, ScheduleStatus.archived);
|
|
});
|
|
|
|
test('UserRepository returns shared user summary', () async {
|
|
final client = _FakeApiClient();
|
|
client.setGet('/api/v1/users/me', {
|
|
'id': 'u1',
|
|
'username': 'alice',
|
|
'phone': null,
|
|
'avatar_url': 'https://img',
|
|
'bio': null,
|
|
});
|
|
|
|
final repository = UserRepositoryImpl(client);
|
|
final me = await repository.getMe();
|
|
|
|
expect(me.id, 'u1');
|
|
expect(me.username, 'alice');
|
|
expect(me.avatarUrl, 'https://img');
|
|
});
|
|
}
|