GerbilStatus: Active→Breeding, add Pet; Deceased/GivenAway are now DERIVED. GerbilStatusService.Derive(): central precedence: DateOfDeath→Deceased (1), ReceiverContactId→GivenAway (2), age>7y→Deceased presumed (3), user choice (4). All write paths (gerbil CRUD, contracts, importers) call GerbilStatusService.Apply(). Startup sweep flips >7y gerbils to Deceased at next app restart. Migration StatusModel: Active→Breeding rename + backfill derived statuses. 10 new tests; 200/200 green; has-pending=No. Enum string values: Breeding (was Active), Pet (new), Deceased, GivenAway, ForSale. FE contract: status field values updated (see Done-Report).
88 lines
4.9 KiB
C#
88 lines
4.9 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using System.Text.Json;
|
|
|
|
namespace GerbilManager.Tests;
|
|
|
|
/// <summary>WEB-0: CMS snapshot shape, Abgabetiere auto-resolution from ForSale, block reorder.</summary>
|
|
public class CmsTests : IClassFixture<ApiFactory>
|
|
{
|
|
private readonly HttpClient _client;
|
|
public CmsTests(ApiFactory factory) => _client = factory.CreateClient();
|
|
|
|
[Fact]
|
|
public async Task Snapshot_has_site_nav_and_seeded_pages()
|
|
{
|
|
var doc = JsonDocument.Parse(await _client.GetStringAsync("/api/site-snapshot"));
|
|
var root = doc.RootElement;
|
|
|
|
Assert.Equal("de", root.GetProperty("site").GetProperty("defaultLocale").GetString());
|
|
var nav = root.GetProperty("site").GetProperty("navOrder").EnumerateArray().Select(x => x.GetString()).ToList();
|
|
// main nav = 6 core pages (Impressum/Datenschutz are footer-only, not in navOrder)
|
|
Assert.Equal(new[] { "start", "ueber-die-zucht", "abgabetiere", "abgabebedingungen", "farben-genetik", "kontakt" }, nav);
|
|
|
|
var pages = root.GetProperty("pages").EnumerateArray().ToList();
|
|
// 8 pages: 6 core + impressum + datenschutz (footer-only legal pages)
|
|
Assert.Equal(8, pages.Count);
|
|
Assert.Contains(pages, p => p.GetProperty("slug").GetString() == "impressum");
|
|
Assert.Contains(pages, p => p.GetProperty("slug").GetString() == "datenschutz");
|
|
// abgabetiere page carries an AbgabetiereList block with a resolved (possibly empty) animals array
|
|
var abg = pages.Single(p => p.GetProperty("slug").GetString() == "abgabetiere");
|
|
var listBlock = abg.GetProperty("blocks").EnumerateArray()
|
|
.Single(b => b.GetProperty("type").GetString() == "AbgabetiereList");
|
|
Assert.Equal("auto", listBlock.GetProperty("data").GetProperty("mode").GetString());
|
|
Assert.Equal(JsonValueKind.Array, listBlock.GetProperty("data").GetProperty("animals").ValueKind);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Abgabetiere_resolves_ForSale_animals_with_becken_group()
|
|
{
|
|
// a Becken + a ForSale gerbil in it
|
|
var encResp = await _client.PostAsJsonAsync("/enclosures", new { name = "Verkaufsbecken" });
|
|
var encId = JsonDocument.Parse(await encResp.Content.ReadAsStringAsync()).RootElement.GetProperty("id").GetString();
|
|
await _client.PostAsJsonAsync("/gerbils", new { name = "Verkaufsmaus", gender = "female", status = "ForSale", enclosureId = encId });
|
|
// a non-ForSale gerbil must NOT appear
|
|
await _client.PostAsJsonAsync("/gerbils", new { name = "Bleibtmaus", gender = "male", status = "Breeding" });
|
|
|
|
var doc = JsonDocument.Parse(await _client.GetStringAsync("/api/site-snapshot"));
|
|
var animals = doc.RootElement.GetProperty("pages").EnumerateArray()
|
|
.Single(p => p.GetProperty("slug").GetString() == "abgabetiere")
|
|
.GetProperty("blocks").EnumerateArray()
|
|
.Single(b => b.GetProperty("type").GetString() == "AbgabetiereList")
|
|
.GetProperty("data").GetProperty("animals").EnumerateArray().ToList();
|
|
|
|
var sale = animals.SingleOrDefault(a => a.GetProperty("name").GetString() == "Verkaufsmaus");
|
|
Assert.Equal(JsonValueKind.Object, sale.ValueKind);
|
|
Assert.Equal("Verkaufsbecken", sale.GetProperty("group").GetString());
|
|
Assert.Equal(JsonValueKind.Array, sale.GetProperty("photos").ValueKind);
|
|
Assert.DoesNotContain(animals, a => a.GetProperty("name").GetString() == "Bleibtmaus");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Block_crud_and_reorder()
|
|
{
|
|
// create a page + two blocks
|
|
var pageResp = await _client.PostAsJsonAsync("/api/pages", new { slug = "test-page", title = "Testseite" });
|
|
Assert.Equal(HttpStatusCode.Created, pageResp.StatusCode);
|
|
var pageId = JsonDocument.Parse(await pageResp.Content.ReadAsStringAsync()).RootElement.GetProperty("id").GetString();
|
|
|
|
async Task<Guid> AddBlock(string type, object data) =>
|
|
JsonDocument.Parse(await (await _client.PostAsJsonAsync($"/api/pages/{pageId}/blocks", new { type, data }))
|
|
.Content.ReadAsStringAsync()).RootElement.GetProperty("id").GetGuid();
|
|
|
|
var b1 = await AddBlock("Heading", new { text = "Erstes", level = 2 });
|
|
var b2 = await AddBlock("RichText", new { markdown = "**hallo**" });
|
|
|
|
// reorder: b2 before b1
|
|
var reorder = await _client.PutAsJsonAsync($"/api/pages/{pageId}/blocks/order", new { blockIds = new[] { b2, b1 } });
|
|
Assert.Equal(HttpStatusCode.NoContent, reorder.StatusCode);
|
|
|
|
var blocks = JsonDocument.Parse(await _client.GetStringAsync("/api/pages/test-page"))
|
|
.RootElement.GetProperty("blocks").EnumerateArray().ToList();
|
|
Assert.Equal(b2.ToString(), blocks[0].GetProperty("id").GetString());
|
|
Assert.Equal(b1.ToString(), blocks[1].GetProperty("id").GetString());
|
|
// RichText markdown round-trips inside data
|
|
Assert.Equal("**hallo**", blocks[0].GetProperty("data").GetProperty("markdown").GetString());
|
|
}
|
|
}
|