## Corrections Critiques ### Race Condition - Statuts de Messages - Fix : Les icônes de statut (✓, ✓✓, ✓✓ bleu) ne s'affichaient pas - Cause : WebSocket delivery confirmations arrivaient avant messages locaux - Solution : Pattern Optimistic UI dans chat_bloc.dart - Création message temporaire immédiate - Ajout à la liste AVANT requête HTTP - Remplacement par message serveur à la réponse - Fichier : lib/presentation/state_management/chat_bloc.dart ## Implémentation TODOs (13/21) ### Social (social_header_widget.dart) - ✅ Copier lien du post dans presse-papiers - ✅ Partage natif via Share.share() - ✅ Dialogue de signalement avec 5 raisons ### Partage (share_post_dialog.dart) - ✅ Interface sélection d'amis avec checkboxes - ✅ Partage externe via Share API ### Média (media_upload_service.dart) - ✅ Parsing JSON réponse backend - ✅ Méthode deleteMedia() pour suppression - ✅ Génération miniature vidéo ### Posts (create_post_dialog.dart, edit_post_dialog.dart) - ✅ Extraction URL depuis uploads - ✅ Documentation chargement médias ### Chat (conversations_screen.dart) - ✅ Navigation vers notifications - ✅ ConversationSearchDelegate pour recherche ## Nouveaux Fichiers ### Configuration - build-prod.ps1 : Script build production avec dart-define - lib/core/constants/env_config.dart : Gestion environnements ### Documentation - TODOS_IMPLEMENTED.md : Documentation complète TODOs ## Améliorations ### Architecture - Refactoring injection de dépendances - Amélioration routing et navigation - Optimisation providers (UserProvider, FriendsProvider) ### UI/UX - Amélioration thème et couleurs - Optimisation animations - Meilleure gestion erreurs ### Services - Configuration API avec env_config - Amélioration datasources (events, users) - Optimisation modèles de données
211 lines
6.3 KiB
Dart
211 lines
6.3 KiB
Dart
import 'package:afterwork/domain/entities/friend.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
group('Friend Entity', () {
|
|
const tFriendId = 'friend123';
|
|
const tFirstName = 'Jane';
|
|
const tLastName = 'Smith';
|
|
const tEmail = 'jane.smith@example.com';
|
|
const tImageUrl = 'https://example.com/jane.jpg';
|
|
|
|
test('should create a Friend with required fields', () {
|
|
// Act
|
|
final friend = Friend(
|
|
friendId: tFriendId,
|
|
friendFirstName: tFirstName,
|
|
friendLastName: tLastName,
|
|
);
|
|
|
|
// Assert
|
|
expect(friend.friendId, tFriendId);
|
|
expect(friend.friendFirstName, tFirstName);
|
|
expect(friend.friendLastName, tLastName);
|
|
expect(friend.status, FriendStatus.unknown); // Default
|
|
expect(friend.isOnline, isFalse); // Default
|
|
expect(friend.isBestFriend, isFalse); // Default
|
|
expect(friend.hasKnownSinceChildhood, isFalse); // Default
|
|
});
|
|
|
|
test('should create a Friend with optional fields', () {
|
|
// Act
|
|
final friend = Friend(
|
|
friendId: tFriendId,
|
|
friendFirstName: tFirstName,
|
|
friendLastName: tLastName,
|
|
email: tEmail,
|
|
imageUrl: tImageUrl,
|
|
status: FriendStatus.accepted,
|
|
isOnline: true,
|
|
isBestFriend: true,
|
|
hasKnownSinceChildhood: true,
|
|
);
|
|
|
|
// Assert
|
|
expect(friend.email, tEmail);
|
|
expect(friend.imageUrl, tImageUrl);
|
|
expect(friend.status, FriendStatus.accepted);
|
|
expect(friend.isOnline, isTrue);
|
|
expect(friend.isBestFriend, isTrue);
|
|
expect(friend.hasKnownSinceChildhood, isTrue);
|
|
});
|
|
|
|
test('should use default name when firstName is not provided', () {
|
|
// Act
|
|
final friend = Friend(
|
|
friendId: tFriendId,
|
|
);
|
|
|
|
// Assert
|
|
expect(friend.friendFirstName, 'Ami inconnu');
|
|
expect(friend.friendLastName, '');
|
|
});
|
|
|
|
test('should support value equality using Equatable', () {
|
|
// Arrange
|
|
final friend1 = Friend(
|
|
friendId: tFriendId,
|
|
friendFirstName: tFirstName,
|
|
friendLastName: tLastName,
|
|
);
|
|
|
|
final friend2 = Friend(
|
|
friendId: tFriendId,
|
|
friendFirstName: tFirstName,
|
|
friendLastName: tLastName,
|
|
);
|
|
|
|
// Assert
|
|
expect(friend1, equals(friend2));
|
|
expect(friend1.hashCode, equals(friend2.hashCode));
|
|
});
|
|
|
|
test('fromJson should create Friend from valid JSON', () {
|
|
// Arrange
|
|
final json = {
|
|
'friendId': tFriendId,
|
|
'friendFirstName': tFirstName,
|
|
'friendLastName': tLastName,
|
|
'email': tEmail,
|
|
'friendProfileImageUrl': tImageUrl,
|
|
'status': 'accepted',
|
|
'isOnline': true,
|
|
'isBestFriend': false,
|
|
'hasKnownSinceChildhood': false,
|
|
};
|
|
|
|
// Act
|
|
final friend = Friend.fromJson(json);
|
|
|
|
// Assert
|
|
expect(friend.friendId, tFriendId);
|
|
expect(friend.friendFirstName, tFirstName);
|
|
expect(friend.friendLastName, tLastName);
|
|
expect(friend.email, tEmail);
|
|
expect(friend.imageUrl, tImageUrl);
|
|
expect(friend.status, FriendStatus.accepted);
|
|
expect(friend.isOnline, isTrue);
|
|
});
|
|
|
|
test('fromJson should use default values for missing fields', () {
|
|
// Arrange
|
|
final json = {
|
|
'friendId': tFriendId,
|
|
};
|
|
|
|
// Act
|
|
final friend = Friend.fromJson(json);
|
|
|
|
// Assert
|
|
expect(friend.friendId, tFriendId);
|
|
expect(friend.friendFirstName, 'Ami inconnu');
|
|
expect(friend.friendLastName, '');
|
|
expect(friend.status, FriendStatus.unknown);
|
|
});
|
|
|
|
test('fromJson should throw when friendId is missing', () {
|
|
// Arrange
|
|
final json = <String, dynamic>{};
|
|
|
|
// Act & Assert
|
|
expect(
|
|
() => Friend.fromJson(json),
|
|
throwsA(isA<ArgumentError>()),
|
|
);
|
|
});
|
|
|
|
test('toJson should serialize Friend correctly', () {
|
|
// Arrange
|
|
final friend = Friend(
|
|
friendId: tFriendId,
|
|
friendFirstName: tFirstName,
|
|
friendLastName: tLastName,
|
|
email: tEmail,
|
|
imageUrl: tImageUrl,
|
|
status: FriendStatus.accepted,
|
|
isOnline: true,
|
|
isBestFriend: false,
|
|
hasKnownSinceChildhood: false,
|
|
);
|
|
|
|
// Act
|
|
final json = friend.toJson();
|
|
|
|
// Assert
|
|
expect(json['friendId'], tFriendId);
|
|
expect(json['friendFirstName'], tFirstName);
|
|
expect(json['friendLastName'], tLastName);
|
|
expect(json['email'], tEmail);
|
|
expect(json['friendProfileImageUrl'], tImageUrl);
|
|
expect(json['status'], 'accepted');
|
|
expect(json['isOnline'], isTrue);
|
|
});
|
|
|
|
test('copyWith should create new instance with updated fields', () {
|
|
// Arrange
|
|
final original = Friend(
|
|
friendId: tFriendId,
|
|
friendFirstName: tFirstName,
|
|
friendLastName: tLastName,
|
|
status: FriendStatus.pending,
|
|
);
|
|
|
|
// Act
|
|
final updated = original.copyWith(
|
|
status: FriendStatus.accepted,
|
|
isOnline: true,
|
|
);
|
|
|
|
// Assert
|
|
expect(updated.friendId, original.friendId); // Unchanged
|
|
expect(updated.friendFirstName, original.friendFirstName); // Unchanged
|
|
expect(updated.status, FriendStatus.accepted); // Changed
|
|
expect(updated.isOnline, isTrue); // Changed
|
|
});
|
|
});
|
|
|
|
group('FriendStatus', () {
|
|
test('should have all required status values', () {
|
|
expect(FriendStatus.values.length, 4);
|
|
expect(FriendStatus.values, contains(FriendStatus.pending));
|
|
expect(FriendStatus.values, contains(FriendStatus.accepted));
|
|
expect(FriendStatus.values, contains(FriendStatus.blocked));
|
|
expect(FriendStatus.values, contains(FriendStatus.unknown));
|
|
});
|
|
|
|
test('parseStatus should handle different string formats', () {
|
|
// This tests the private method indirectly through fromJson
|
|
final jsonPending = {'friendId': '1', 'status': 'pending'};
|
|
final jsonAccepted = {'friendId': '1', 'status': 'accepted'};
|
|
final jsonBlocked = {'friendId': '1', 'status': 'blocked'};
|
|
final jsonUnknown = {'friendId': '1', 'status': 'invalid'};
|
|
|
|
expect(Friend.fromJson(jsonPending).status, FriendStatus.pending);
|
|
expect(Friend.fromJson(jsonAccepted).status, FriendStatus.accepted);
|
|
expect(Friend.fromJson(jsonBlocked).status, FriendStatus.blocked);
|
|
expect(Friend.fromJson(jsonUnknown).status, FriendStatus.unknown);
|
|
});
|
|
});
|
|
}
|
|
|