using System.Net; using System.Text.Json; using Tiku.Domain.Catalog; using Tiku.Domain.Common; using Tiku.Domain.Tenancy; namespace Tiku.IntegrationTests.Api; public sealed class CatalogEndpointTests { [Fact] public async Task Regions_are_filtered_by_active_tenant() { var tenantId = Guid.NewGuid(); var otherTenantId = Guid.NewGuid(); await using var factory = new ApiTestFactory(); await factory.SeedAsync( Tenant(tenantId, "master"), Tenant(otherTenantId, "other"), new Region { Id = Guid.NewGuid(), TenantId = tenantId, Name = "浙江", SortOrder = 2, IsActive = true }, new Region { Id = Guid.NewGuid(), TenantId = tenantId, Name = "北京", SortOrder = 1, IsActive = true }, new Region { Id = Guid.NewGuid(), TenantId = tenantId, Name = "停用地区", SortOrder = 0, IsActive = false }, new Region { Id = Guid.NewGuid(), TenantId = otherTenantId, Name = "其他租户地区", IsActive = true }); using var client = factory.CreateClient(); using var response = await client.GetAsync("/api/catalog/regions?tenantCode=master"); var items = await ReadItemsAsync(response); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(["北京", "浙江"], items.Select(item => item.GetProperty("name").GetString()!).ToArray()); } [Fact] public async Task Subjects_support_common_filters() { var tenantId = Guid.NewGuid(); var regionId = Guid.NewGuid(); var schoolId = Guid.NewGuid(); var majorId = Guid.NewGuid(); await using var factory = new ApiTestFactory(); await factory.SeedAsync( Tenant(tenantId, "master"), new Region { Id = regionId, TenantId = tenantId, Name = "浙江" }, new School { Id = schoolId, TenantId = tenantId, RegionId = regionId, Name = "测试院校" }, new Major { Id = majorId, TenantId = tenantId, RegionId = regionId, SchoolId = schoolId, Name = "视觉传达" }, new Subject { Id = Guid.NewGuid(), TenantId = tenantId, RegionId = regionId, SchoolId = schoolId, MajorId = majorId, Name = "专业理论", Type = SubjectType.Professional, SortOrder = 1, IsActive = true }, new Subject { Id = Guid.NewGuid(), TenantId = tenantId, RegionId = regionId, SchoolId = schoolId, MajorId = majorId, Name = "公共英语", Type = SubjectType.Cultural, SortOrder = 2, IsActive = true }, new Subject { Id = Guid.NewGuid(), TenantId = tenantId, RegionId = regionId, Name = "停用科目", Type = SubjectType.Professional, IsActive = false }); using var client = factory.CreateClient(); using var response = await client.GetAsync( $"/api/catalog/subjects?tenantCode=master®ionId={regionId}&schoolId={schoolId}&majorId={majorId}&type=professional&keyword=理论"); var items = await ReadItemsAsync(response); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var item = Assert.Single(items); Assert.Equal("专业理论", item.GetProperty("name").GetString()); } [Fact] public async Task Module_nodes_support_root_filter() { var tenantId = Guid.NewGuid(); var parentId = Guid.NewGuid(); await using var factory = new ApiTestFactory(); await factory.SeedAsync( Tenant(tenantId, "master"), new ModuleNode { Id = parentId, TenantId = tenantId, Name = "根节点", Type = ModuleNodeType.Category, IsActive = true }, new ModuleNode { Id = Guid.NewGuid(), TenantId = tenantId, ParentId = parentId, Name = "子节点", Type = ModuleNodeType.Chapter, IsActive = true }); using var client = factory.CreateClient(); using var response = await client.GetAsync("/api/catalog/module-nodes?tenantCode=master&parentId=root"); var items = await ReadItemsAsync(response); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var item = Assert.Single(items); Assert.Equal("根节点", item.GetProperty("name").GetString()); } [Fact] public async Task Catalog_requires_known_tenant_for_anonymous_requests() { await using var factory = new ApiTestFactory(); using var client = factory.CreateClient(); using var response = await client.GetAsync("/api/catalog/regions"); var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); Assert.Equal("tenant_not_found", body.RootElement.GetProperty("code").GetString()); } private static Tenant Tenant(Guid id, string slug) { return new Tenant { Id = id, Slug = slug, Name = slug, Status = TenantStatus.Active }; } private static async Task ReadItemsAsync(HttpResponseMessage response) { var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); return body.RootElement .GetProperty("items") .EnumerateArray() .Select(item => item.Clone()) .ToArray(); } }