using System.Net.Http.Json; using FamilyNido.Domain.Families; using FamilyNido.Domain.Identity; using FamilyNido.Persistence; using FluentAssertions; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; namespace FamilyNido.Tests.Integration; /// /// Helpers for assembling the minimum domain graph an integration test needs: /// a family, a user with a known local password, and one or more linked /// members. Returned by reference so tests can chain seeding calls and assert /// the persisted state. /// public static class TestSeed { /// Default password used by every seeded user. Hashed with PBKDF2 v3 by the password hasher. public const string DefaultPassword = "Test1234!"; /// Compact bundle returned by . public sealed record FamilyHandle(Family Family, FamilyMember Member, User User); /// /// Persist a family + an authenticable user with a linked member. Defaults /// produce an admin adult; pass to vary. /// public static async Task SeedFamilyAsync( ApplicationDbContext db, IServiceProvider services, string email = "dan@example.com", string displayName = "Dan", FamilyRole role = FamilyRole.Admin, string colorHex = "#C96442") { var hasher = services.GetRequiredService>(); var family = new Family { Name = "Familia Test", TimeZone = "Europe/Madrid" }; db.Families.Add(family); var user = new User { Email = email, DisplayName = displayName, Role = role }; db.Users.Add(user); var member = new FamilyMember { FamilyId = family.Id, DisplayName = displayName, MemberType = MemberType.Adult, ColorHex = colorHex, UserId = user.Id, }; db.FamilyMembers.Add(member); var credential = new UserCredential { UserId = user.Id, Provider = IdentityProvider.Local, PasswordHash = hasher.HashPassword(user, DefaultPassword), }; db.UserCredentials.Add(credential); await db.SaveChangesAsync(); return new FamilyHandle(family, member, user); } /// Append one extra member (not authenticable) to an existing family. public static async Task SeedMemberAsync( ApplicationDbContext db, Guid familyId, string displayName, MemberType type = MemberType.Child, string colorHex = "#7BA4A8", DateOnly? birthDate = null) { var member = new FamilyMember { FamilyId = familyId, DisplayName = displayName, MemberType = type, ColorHex = colorHex, BirthDate = birthDate, }; db.FamilyMembers.Add(member); await db.SaveChangesAsync(); return member; } /// /// Sign the supplied client in via POST /api/auth/local/login. The /// session cookie is preserved on the client because HandleCookies /// is enabled on the test factory. /// public static async Task LoginAsync(HttpClient client, string email, string password = DefaultPassword) { var response = await client.PostAsJsonAsync("/api/auth/local/login", new { email, password }); response.IsSuccessStatusCode.Should().BeTrue($"login should succeed (got {response.StatusCode})"); } }