forked from wangziqi/gongxue-base
feat: add learning leaderboards
This commit is contained in:
@@ -994,6 +994,55 @@ async function testProfile() {
|
||||
assert.equal(crossTenantFeedback.code, 'AUTH_TENANT_MISMATCH', 'feedback submission must use authenticated tenant context');
|
||||
}
|
||||
|
||||
async function testLearningLeaderboard() {
|
||||
const questions = await request('/api/learning/leaderboard', {
|
||||
query: { metric: 'questions', period: 'all', limit: 10 },
|
||||
});
|
||||
assert.equal(questions.metric, 'questions', 'question leaderboard should echo metric');
|
||||
assert.ok(questions.items?.some(item => item.userId === SECOND_STUDENT_USER_ID), 'question leaderboard should include second student');
|
||||
assert.ok(questions.items?.some(item => item.userId === USER_ID), 'question leaderboard should include current student');
|
||||
const secondQuestions = questions.items?.find(item => item.userId === SECOND_STUDENT_USER_ID);
|
||||
const currentQuestions = questions.currentUser;
|
||||
assert.ok(secondQuestions?.value >= currentQuestions?.value, 'second student should rank at least as high as smoke user by questions');
|
||||
assert.equal(currentQuestions?.userId, USER_ID, 'question leaderboard should include current user rank');
|
||||
assert.equal(currentQuestions?.isCurrentUser, true, 'current user rank should be flagged');
|
||||
|
||||
const score = await request('/api/learning/leaderboard', {
|
||||
query: { metric: 'score', period: 'all', limit: 10 },
|
||||
});
|
||||
const scoreLeader = score.items?.find(item => item.userId === SECOND_STUDENT_USER_ID);
|
||||
assert.ok(scoreLeader?.value >= 30, 'score leaderboard should use platform user score');
|
||||
assert.ok(score.currentUser?.value >= 10, 'score leaderboard should include current user score');
|
||||
|
||||
const vocabulary = await request('/api/learning/leaderboard', {
|
||||
query: { metric: 'vocabulary', period: 'all', limit: 10 },
|
||||
});
|
||||
const vocabularyLeader = vocabulary.items?.find(item => item.userId === SECOND_STUDENT_USER_ID);
|
||||
assert.equal(vocabularyLeader?.value, 2, 'vocabulary leaderboard should count mastered words');
|
||||
|
||||
const mockExam = await request('/api/learning/leaderboard', {
|
||||
query: { metric: 'mock_exam', period: '30d', limit: 10 },
|
||||
});
|
||||
const mockLeader = mockExam.items?.find(item => item.userId === SECOND_STUDENT_USER_ID);
|
||||
assert.equal(mockLeader?.value, 95, 'mock exam leaderboard should use best report score');
|
||||
assert.ok(mockExam.currentUser?.value >= 70, 'mock exam leaderboard should include current user best score');
|
||||
|
||||
const classScoped = await request('/api/learning/leaderboard', {
|
||||
query: { metric: 'questions', classId: ids.tenantClass, limit: 10 },
|
||||
});
|
||||
assert.ok(classScoped.items?.some(item => item.userId === USER_ID), 'class scoped leaderboard should include class student');
|
||||
assert.ok(!classScoped.items?.some(item => item.userId === SECOND_STUDENT_USER_ID), 'class scoped leaderboard should exclude other class student');
|
||||
|
||||
const trustedLogin = await loginBySms('13800000000');
|
||||
const crossTenantDenied = await request('/api/learning/leaderboard', {
|
||||
tenantId: PARTNER_TENANT_ID,
|
||||
userId: false,
|
||||
headers: { authorization: `Bearer ${trustedLogin.session.token}` },
|
||||
expectStatus: 403,
|
||||
});
|
||||
assert.equal(crossTenantDenied.code, 'AUTH_TENANT_MISMATCH', 'leaderboard must reject trusted session cross-tenant access');
|
||||
}
|
||||
|
||||
async function testScoreline() {
|
||||
const fields = await request('/api/scoreline/fields', { query: { regionId: ids.region } });
|
||||
assert.ok(fields.items?.some(item => item.fieldKey === 'minScore'), 'scoreline fields should include minScore');
|
||||
@@ -3326,6 +3375,7 @@ async function main() {
|
||||
await check('legacy auth headers disabled', testLegacyAuthHeadersDisabled);
|
||||
await check('catalog and learning', testCatalogAndLearning);
|
||||
await check('profile', testProfile);
|
||||
await check('learning leaderboard', testLearningLeaderboard);
|
||||
await check('scoreline', testScoreline);
|
||||
await check('question videos', testVideos);
|
||||
await check('vocabulary', testVocabulary);
|
||||
|
||||
Reference in New Issue
Block a user