forked from wangziqi/gongxue-base
feat: add AI school recommendation foundation
This commit is contained in:
@@ -1649,6 +1649,70 @@ async function testScoreline() {
|
||||
assert.ok(years.items?.includes(2026), 'scoreline years should include 2026');
|
||||
}
|
||||
|
||||
async function testAiSchoolRecommendationRequiresSvip() {
|
||||
const denied = await request('/api/ai/school-recommendations/generate', {
|
||||
userId: SECOND_STUDENT_USER_ID,
|
||||
method: 'POST',
|
||||
body: {
|
||||
regionId: ids.region,
|
||||
estimatedScore: 210,
|
||||
riskPreference: 'balanced',
|
||||
},
|
||||
expectStatus: 403,
|
||||
});
|
||||
assert.equal(denied.code, 'AI_SVIP_REQUIRED', 'AI school recommendation should require SVIP entitlement');
|
||||
}
|
||||
|
||||
async function testAiSchoolRecommendationAfterSvip() {
|
||||
const generated = await request('/api/ai/school-recommendations/generate', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
regionId: ids.region,
|
||||
estimatedScore: 210,
|
||||
riskPreference: 'balanced',
|
||||
constraints: '优先考虑计算机相关专业',
|
||||
recommendationLimit: 5,
|
||||
},
|
||||
});
|
||||
assert.equal(generated.item?.status, 'generated', 'AI school recommendation should generate report');
|
||||
assert.equal(generated.item?.provider, 'local_rules', 'AI recommendation should use deterministic local provider in tests');
|
||||
assert.equal(generated.item?.resultPayload?.schemaVersion, 'school-recommendation-report-v1', 'AI report should use stable schema');
|
||||
assert.ok(
|
||||
generated.item?.resultPayload?.recommendedSchools?.some(item => item.schoolName === '烟测学院'),
|
||||
'AI report should recommend from tenant scoreline context',
|
||||
);
|
||||
assert.ok(!JSON.stringify(generated).includes('secret'), 'AI recommendation response should not leak provider secrets');
|
||||
|
||||
const reports = await request('/api/ai/school-recommendations', {
|
||||
query: { limit: 5 },
|
||||
});
|
||||
assert.ok(reports.items?.some(item => item.id === generated.item.id), 'AI report list should include generated report');
|
||||
|
||||
const detail = await request('/api/ai/school-recommendations/detail', {
|
||||
query: { reportId: generated.item.id },
|
||||
});
|
||||
assert.equal(detail.item?.id, generated.item.id, 'AI report detail should load own report');
|
||||
|
||||
const otherStudentDenied = await request('/api/ai/school-recommendations/detail', {
|
||||
userId: SECOND_STUDENT_USER_ID,
|
||||
query: { reportId: generated.item.id },
|
||||
expectStatus: 404,
|
||||
});
|
||||
assert.equal(otherStudentDenied.code, 'AI_REPORT_NOT_FOUND', 'students must not read other students AI reports');
|
||||
|
||||
const partnerTenantDenied = await request('/api/ai/school-recommendations/generate', {
|
||||
tenantId: PARTNER_TENANT_ID,
|
||||
method: 'POST',
|
||||
body: {
|
||||
regionId: ids.region,
|
||||
estimatedScore: 210,
|
||||
riskPreference: 'balanced',
|
||||
},
|
||||
expectStatus: 404,
|
||||
});
|
||||
assert.equal(partnerTenantDenied.code, 'PROFILE_NOT_FOUND', 'AI recommendation must not use a student profile from another tenant');
|
||||
}
|
||||
|
||||
async function testVideos() {
|
||||
const single = await request(`/api/questions/${ids.question}/videos`);
|
||||
assert.ok(single.total >= 1, 'question should have videos');
|
||||
@@ -7181,9 +7245,11 @@ async function main() {
|
||||
await check('profile', testProfile);
|
||||
await check('learning leaderboard', testLearningLeaderboard);
|
||||
await check('scoreline', testScoreline);
|
||||
await check('AI school recommendation SVIP gate', testAiSchoolRecommendationRequiresSvip);
|
||||
await check('question videos', testVideos);
|
||||
await check('vocabulary', testVocabulary);
|
||||
await check('commerce', testCommerce);
|
||||
await check('AI school recommendation', testAiSchoolRecommendationAfterSvip);
|
||||
await check('tenant isolation', testTenantIsolation);
|
||||
await check('tenant content admin', testTenantContentAdmin);
|
||||
await check('tenant content assets and imports', testTenantContentAssetsAndImports);
|
||||
|
||||
Reference in New Issue
Block a user