forked from gongxuegit/tiku-backend.net
feat: add study content readonly endpoints
This commit is contained in:
202
Tiku.IntegrationTests/Api/StudyContentEndpointTests.cs
Normal file
202
Tiku.IntegrationTests/Api/StudyContentEndpointTests.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
using Tiku.Domain.Content;
|
||||
using Tiku.Domain.Tenancy;
|
||||
|
||||
namespace Tiku.IntegrationTests.Api;
|
||||
|
||||
public sealed class StudyContentEndpointTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Vocabulary_units_are_active_sorted_and_region_scoped()
|
||||
{
|
||||
var tenantId = Guid.NewGuid();
|
||||
var regionId = Guid.NewGuid();
|
||||
await using var factory = new ApiTestFactory();
|
||||
await factory.SeedAsync(
|
||||
Tenant(tenantId, "master"),
|
||||
new VocabularyUnit
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
RegionId = regionId,
|
||||
Name = "核心词汇",
|
||||
SortOrder = 2,
|
||||
IsActive = true
|
||||
},
|
||||
new VocabularyUnit
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
Name = "全局词汇",
|
||||
SortOrder = 1,
|
||||
IsActive = true
|
||||
},
|
||||
new VocabularyUnit
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
RegionId = regionId,
|
||||
Name = "停用词汇",
|
||||
SortOrder = 0,
|
||||
IsActive = false
|
||||
});
|
||||
using var client = factory.CreateClient();
|
||||
|
||||
using var response = await client.GetAsync($"/api/catalog/vocabulary-units?tenantCode=master®ionId={regionId}");
|
||||
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 Vocabulary_words_support_unit_and_keyword_filters()
|
||||
{
|
||||
var tenantId = Guid.NewGuid();
|
||||
var unitId = Guid.NewGuid();
|
||||
await using var factory = new ApiTestFactory();
|
||||
await factory.SeedAsync(
|
||||
Tenant(tenantId, "master"),
|
||||
new VocabularyUnit { Id = unitId, TenantId = tenantId, Name = "Unit 1" },
|
||||
new VocabularyWord
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
UnitId = unitId,
|
||||
Word = "abandon",
|
||||
Meaning = "放弃",
|
||||
SortOrder = 1,
|
||||
IsActive = true
|
||||
},
|
||||
new VocabularyWord
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
UnitId = unitId,
|
||||
Word = "ability",
|
||||
Meaning = "能力",
|
||||
SortOrder = 2,
|
||||
IsActive = true
|
||||
},
|
||||
new VocabularyWord
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
Word = "other",
|
||||
Meaning = "其他",
|
||||
IsActive = true
|
||||
});
|
||||
using var client = factory.CreateClient();
|
||||
|
||||
using var response = await client.GetAsync($"/api/catalog/vocabulary-words?tenantCode=master&unitId={unitId}&keyword=放弃");
|
||||
var items = await ReadItemsAsync(response);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var item = Assert.Single(items);
|
||||
Assert.Equal("abandon", item.GetProperty("word").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handbook_chapters_are_filtered_by_subject()
|
||||
{
|
||||
var tenantId = Guid.NewGuid();
|
||||
var subjectId = Guid.NewGuid();
|
||||
await using var factory = new ApiTestFactory();
|
||||
await factory.SeedAsync(
|
||||
Tenant(tenantId, "master"),
|
||||
new HandbookSubject
|
||||
{
|
||||
Id = subjectId,
|
||||
TenantId = tenantId,
|
||||
Name = "语文手册",
|
||||
IsActive = true
|
||||
},
|
||||
new HandbookChapter
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
SubjectId = subjectId,
|
||||
Name = "古诗词",
|
||||
SortOrder = 1,
|
||||
IsActive = true
|
||||
},
|
||||
new HandbookChapter
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
Name = "其他章节",
|
||||
SortOrder = 2,
|
||||
IsActive = true
|
||||
});
|
||||
using var client = factory.CreateClient();
|
||||
|
||||
using var response = await client.GetAsync($"/api/catalog/handbook-chapters?tenantCode=master&subjectId={subjectId}");
|
||||
var items = await ReadItemsAsync(response);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("古诗词", Assert.Single(items).GetProperty("name").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handbook_entries_hide_content_until_requested()
|
||||
{
|
||||
var tenantId = Guid.NewGuid();
|
||||
var chapterId = Guid.NewGuid();
|
||||
await using var factory = new ApiTestFactory();
|
||||
await factory.SeedAsync(
|
||||
Tenant(tenantId, "master"),
|
||||
new HandbookChapter
|
||||
{
|
||||
Id = chapterId,
|
||||
TenantId = tenantId,
|
||||
Name = "章节",
|
||||
IsActive = true
|
||||
},
|
||||
new HandbookEntry
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
ChapterId = chapterId,
|
||||
Title = "知识点",
|
||||
Summary = "摘要",
|
||||
Content = "完整正文",
|
||||
SortOrder = 1,
|
||||
IsActive = true
|
||||
});
|
||||
using var client = factory.CreateClient();
|
||||
|
||||
using var listResponse = await client.GetAsync($"/api/catalog/handbook-entries?tenantCode=master&chapterId={chapterId}");
|
||||
using var detailResponse = await client.GetAsync($"/api/catalog/handbook-entries?tenantCode=master&chapterId={chapterId}&includeContent=true");
|
||||
var listItem = Assert.Single(await ReadItemsAsync(listResponse));
|
||||
var detailItem = Assert.Single(await ReadItemsAsync(detailResponse));
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
|
||||
Assert.Equal(HttpStatusCode.OK, detailResponse.StatusCode);
|
||||
Assert.Equal(JsonValueKind.Null, listItem.GetProperty("content").ValueKind);
|
||||
Assert.Equal("完整正文", detailItem.GetProperty("content").GetString());
|
||||
}
|
||||
|
||||
private static Tenant Tenant(Guid id, string slug)
|
||||
{
|
||||
return new Tenant
|
||||
{
|
||||
Id = id,
|
||||
Slug = slug,
|
||||
Name = slug,
|
||||
Status = TenantStatus.Active,
|
||||
Metadata = JsonDefaults.Object()
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task<JsonElement[]> ReadItemsAsync(HttpResponseMessage response)
|
||||
{
|
||||
var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
|
||||
return body.RootElement
|
||||
.GetProperty("items")
|
||||
.EnumerateArray()
|
||||
.Select(item => item.Clone())
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user