Files
GameTime/test/infrastructure/remote/share_api_test.dart

182 lines
5.4 KiB
Dart

import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:gametime/application/application.dart';
import 'package:gametime/domain/domain.dart';
import 'package:gametime/infrastructure/remote/remote.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
void main() {
test(
'sendShare maps local workout pack payload to server pack contract',
() async {
Map<String, Object?>? capturedBody;
final api = HttpRemoteShareApi(
HttpApiClient(
baseUrl: Uri.parse('http://api.example.test'),
client: MockClient((request) async {
capturedBody = _jsonMap(request.body);
expect(request.method, 'POST');
expect(request.url.path, '/shares');
expect(request.headers['authorization'], 'Bearer token-1');
return http.Response(
jsonEncode({
'shareId': 'share-1',
'recipientUserIds': ['user-2'],
'unresolvedEmails': const <String>[],
}),
201,
);
}),
),
);
await api.sendShare(
resourceType: ShareResourceType.pack,
payload: const {
'name': 'Pack reprise',
'workouts': [
{'id': 'template-1', 'name': 'Séance 1'},
{'id': 'template-2', 'name': 'Séance 2'},
],
},
recipientEmails: const ['friend@example.com'],
token: 'token-1',
);
expect(capturedBody, {
'shareKind': 'pack',
'packName': 'Pack reprise',
'items': [
{
'resourceType': 'workoutTemplate',
'payload': {'id': 'template-1', 'name': 'Séance 1'},
},
{
'resourceType': 'workoutTemplate',
'payload': {'id': 'template-2', 'name': 'Séance 2'},
},
],
'recipientEmails': ['friend@example.com'],
});
},
);
test(
'fetchInbox maps server pack payload without resourceType to local pack',
() async {
final api = HttpRemoteShareApi(
HttpApiClient(
baseUrl: Uri.parse('http://api.example.test'),
client: MockClient((request) async {
expect(request.method, 'GET');
expect(request.url.path, '/shares/inbox');
return http.Response(
jsonEncode({
'items': [
{
'shareId': 'share-pack-1',
'senderUserId': 'sender-1',
'shareKind': 'pack',
'packName': 'Pack été',
'resourceType': null,
'payload': {
'items': [
{
'resourceType': 'workoutTemplate',
'payload': {'id': 'template-1', 'name': 'Séance 1'},
},
],
},
'status': 'pending',
'createdAt': '2026-07-17T12:00:00.000Z',
'respondedAt': null,
},
],
}),
200,
);
}),
),
);
final items = await api.fetchInbox('token-1');
final payload = _jsonMap(items.single.payloadJson);
expect(items.single.resourceType, ShareResourceType.pack);
expect(payload, {
'name': 'Pack été',
'workouts': [
{'id': 'template-1', 'name': 'Séance 1'},
],
});
},
);
test(
'acceptShare returns every created resource from server packs',
() async {
final api = HttpRemoteShareApi(
HttpApiClient(
baseUrl: Uri.parse('http://api.example.test'),
client: MockClient((request) async {
expect(request.method, 'POST');
expect(request.url.path, '/shares/share-pack-1/accept');
return http.Response(
jsonEncode({
'createdResources': [
_createdResourceJson(
resourceType: 'program',
clientId: 'program-1',
serverId: 'server-program-1',
),
_createdResourceJson(
resourceType: 'workoutTemplate',
clientId: 'template-1',
serverId: 'server-template-1',
),
],
}),
200,
);
}),
),
);
final resources = await api.acceptShare('share-pack-1', 'token-1');
expect(resources.map((item) => item.resourceType), [
SyncResourceType.program,
SyncResourceType.workoutTemplate,
]);
expect(resources.map((item) => item.clientId), [
'program-1',
'template-1',
]);
},
);
}
Map<String, Object?> _createdResourceJson({
required String resourceType,
required String clientId,
required String serverId,
}) {
return {
'resourceType': resourceType,
'clientId': clientId,
'serverId': serverId,
'schemaVersion': 1,
'clientUpdatedAt': '2026-07-17T12:00:00.000Z',
'serverUpdatedAt': '2026-07-17T12:01:00.000Z',
'deletedAt': null,
'payload': {'id': clientId},
};
}
Map<String, Object?> _jsonMap(String source) {
final decoded = jsonDecode(source);
return Map<String, Object?>.from(decoded as Map);
}