chore: import upstream snapshot with attribution
i18n - Build Validation / Validate i18n Builds (24) (push) Has been cancelled
CI - Node.js / Lint (24) (push) Has been cancelled
CI - Node.js / Build (24) (push) Has been cancelled
CI - Node.js / Test (24) (push) Has been cancelled
CI - Node.js / Test - Upcoming Changes (24) (push) Has been cancelled
CI - Node.js / Test - i18n (italian, 24) (push) Has been cancelled
CI - Node.js / Test - i18n (portuguese, 24) (push) Has been cancelled
CD - Docker - GHCR Images / Build and Push Images (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 11:55:53 +08:00
commit dde272c4b8
19405 changed files with 2730632 additions and 0 deletions
+400
View File
@@ -0,0 +1,400 @@
/* eslint-disable jsdoc/require-jsdoc */
import { Static } from '@fastify/type-provider-typebox';
import {
ExamEnvironmentConfig,
ExamEnvironmentQuestionType,
ExamEnvironmentExamAttempt,
ExamEnvironmentExam,
ExamEnvironmentGeneratedExam,
ExamEnvironmentQuestionSet,
ExamEnvironmentChallenge
} from '@prisma/client';
import { ObjectId } from 'bson';
import { examEnvironmentPostExamAttempt } from '../src/exam-environment/schemas/index.js';
const defaultUserId = '5bd30e0f1caf6ac3ddddddb5';
export const oid = () => new ObjectId().toString();
export const examId = oid();
export const config = {
totalTimeInS: 2 * 60 * 60,
tags: [],
name: 'Test Exam',
note: 'Some exam note...',
passingPercent: 80,
questionSets: [
{
type: ExamEnvironmentQuestionType.MultipleChoice,
numberOfSet: 1,
numberOfQuestions: 1,
numberOfCorrectAnswers: 1,
numberOfIncorrectAnswers: 1
},
{
type: ExamEnvironmentQuestionType.MultipleChoice,
numberOfSet: 1,
numberOfQuestions: 1,
numberOfCorrectAnswers: 2,
numberOfIncorrectAnswers: 1
},
{
type: ExamEnvironmentQuestionType.Dialogue,
numberOfSet: 1,
numberOfQuestions: 2,
numberOfCorrectAnswers: 1,
numberOfIncorrectAnswers: 1
}
],
retakeTimeInS: 24 * 60 * 60
} satisfies ExamEnvironmentConfig;
export const questionSets: ExamEnvironmentQuestionSet[] = [
{
id: oid(),
type: ExamEnvironmentQuestionType.MultipleChoice,
context: null,
questions: [
{
id: oid(),
tags: ['q1t1'],
text: 'Question 1',
deprecated: false,
audio: null,
answers: [
{
id: oid(),
text: 'Answer 1',
isCorrect: true
},
{
id: oid(),
text: 'Answer 2',
isCorrect: true
},
{
id: oid(),
text: 'Answer 3',
isCorrect: false
}
]
}
]
},
{
id: oid(),
type: ExamEnvironmentQuestionType.MultipleChoice,
context: null,
questions: [
{
id: oid(),
tags: [],
text: 'Question 1',
deprecated: false,
audio: null,
answers: [
{
id: oid(),
text: 'Answer 1',
isCorrect: true
},
{
id: oid(),
text: 'Answer 2',
isCorrect: false
},
{
id: oid(),
text: 'Answer 3',
isCorrect: false
}
]
}
]
},
{
id: oid(),
type: ExamEnvironmentQuestionType.Dialogue,
context: 'Dialogue 1 context',
questions: [
{
id: oid(),
tags: ['q1t1'],
text: 'Question 1',
deprecated: false,
audio: null,
answers: [
{
id: oid(),
text: 'Answer 1',
isCorrect: true
},
{
id: oid(),
text: 'Answer 2',
isCorrect: false
},
{
id: oid(),
text: 'Answer 3',
isCorrect: false
}
]
},
{
id: oid(),
tags: ['q2t1', 'q2t2'],
text: 'Question 2',
deprecated: true,
audio: {
url: 'https://freecodecamp.org',
captions: null
},
answers: [
{
id: oid(),
text: 'Answer 1',
isCorrect: true
},
{
id: oid(),
text: 'Answer 2',
isCorrect: false
},
{
id: oid(),
text: 'Answer 3',
isCorrect: false
}
]
},
{
id: oid(),
tags: ['q3t1', 'q3t2'],
text: 'Question 3',
deprecated: false,
audio: null,
answers: [
{
id: oid(),
text: 'Answer 1',
isCorrect: true
},
{
id: oid(),
text: 'Answer 2',
isCorrect: false
},
{
id: oid(),
text: 'Answer 3',
isCorrect: false
}
]
}
]
}
];
export const generatedExam: ExamEnvironmentGeneratedExam = {
examId,
id: oid(),
deprecated: false,
questionSets: [
{
id: questionSets[0]!.id,
questions: [
{
id: questionSets[0]!.questions[0]!.id,
answers: [
questionSets[0]!.questions[0]!.answers[0]!.id,
questionSets[0]!.questions[0]!.answers[1]!.id
]
}
]
},
{
id: questionSets[1]!.id,
questions: [
{
id: questionSets[1]!.questions[0]!.id,
answers: [
questionSets[1]!.questions[0]!.answers[0]!.id,
questionSets[1]!.questions[0]!.answers[1]!.id,
questionSets[1]!.questions[0]!.answers[2]!.id
]
}
]
},
{
id: questionSets[2]!.id,
questions: [
{
id: questionSets[2]!.questions[0]!.id,
answers: [
questionSets[2]!.questions[0]!.answers[0]!.id,
questionSets[2]!.questions[0]!.answers[1]!.id,
questionSets[2]!.questions[0]!.answers[2]!.id
]
},
{
id: questionSets[2]!.questions[1]!.id,
answers: [
questionSets[2]!.questions[1]!.answers[0]!.id,
questionSets[2]!.questions[1]!.answers[1]!.id,
questionSets[2]!.questions[1]!.answers[2]!.id
]
}
]
}
],
version: 2
};
export const examAttempt: ExamEnvironmentExamAttempt = {
examId,
generatedExamId: generatedExam.id,
examModerationId: null,
id: oid(),
questionSets: [
{
id: generatedExam.questionSets[0]!.id,
questions: [
{
id: generatedExam.questionSets[0]!.questions[0]!.id,
answers: [generatedExam.questionSets[0]!.questions[0]!.answers[0]!],
submissionTime: new Date()
}
]
},
{
id: generatedExam.questionSets[1]!.id,
questions: [
{
id: generatedExam.questionSets[1]!.questions[0]!.id,
answers: [generatedExam.questionSets[1]!.questions[0]!.answers[1]!],
submissionTime: new Date()
}
]
},
{
id: generatedExam.questionSets[2]!.id,
questions: [
{
id: generatedExam.questionSets[2]!.questions[0]!.id,
answers: [generatedExam.questionSets[2]!.questions[0]!.answers[1]!],
submissionTime: new Date()
},
{
id: generatedExam.questionSets[2]!.questions[1]!.id,
answers: [generatedExam.questionSets[2]!.questions[1]!.answers[0]!],
submissionTime: new Date()
}
]
}
],
startTime: new Date(),
userId: defaultUserId,
version: 2
};
export const examAttemptSansSubmissionTime: Static<
typeof examEnvironmentPostExamAttempt.body
>['attempt'] = {
examId,
questionSets: [
{
id: generatedExam.questionSets[0]!.id,
questions: [
{
id: generatedExam.questionSets[0]!.questions[0]!.id,
answers: [generatedExam.questionSets[0]!.questions[0]!.answers[0]!]
}
]
},
{
id: generatedExam.questionSets[1]!.id,
questions: [
{
id: generatedExam.questionSets[1]!.questions[0]!.id,
answers: [generatedExam.questionSets[1]!.questions[0]!.answers[1]!]
}
]
},
{
id: generatedExam.questionSets[2]!.id,
questions: [
{
id: generatedExam.questionSets[2]!.questions[0]!.id,
answers: [generatedExam.questionSets[2]!.questions[0]!.answers[1]!]
},
{
id: generatedExam.questionSets[2]!.questions[1]!.id,
answers: [generatedExam.questionSets[2]!.questions[1]!.answers[0]!]
}
]
}
]
};
export const exam = {
id: examId,
config,
questionSets,
prerequisites: ['67112fe1c994faa2c26d0b1d'],
deprecated: false,
version: 2
} satisfies ExamEnvironmentExam;
export const examEnvironmentChallenge: ExamEnvironmentChallenge = {
id: oid(),
examId,
// Id of the certified full stack developer exam challenge page
challengeId: '645147516c245de4d11eb7ba',
version: 1
};
export async function seedEnvExam() {
await clearEnvExam();
await fastifyTestInstance.prisma.examEnvironmentExam.create({
data: exam
});
await fastifyTestInstance.prisma.examEnvironmentGeneratedExam.create({
data: generatedExam
});
// TODO: This would be nice to use, but the test logic for examAttempt need to account
// for dynamic ids.
// let numberOfExamsGenerated = 0;
// while (numberOfExamsGenerated < 2) {
// try {
// const generatedExam = generateExam(exam);
// await fastifyTestInstance.prisma.examEnvironmentGeneratedExam.create({
// data: generatedExam
// });
// numberOfExamsGenerated++;
// } catch (_e) {
// //
// }
// }
}
export async function clearEnvExam() {
await fastifyTestInstance.prisma.examEnvironmentExamAttempt.deleteMany({});
await fastifyTestInstance.prisma.examEnvironmentGeneratedExam.deleteMany({});
await fastifyTestInstance.prisma.examEnvironmentExam.deleteMany({});
}
export async function seedEnvExamAttempt() {
await fastifyTestInstance.prisma.examEnvironmentExamAttempt.create({
data: examAttempt
});
}
export async function seedExamEnvExamAuthToken() {
return fastifyTestInstance.prisma.examEnvironmentAuthorizationToken.create({
data: { userId: defaultUserId, expireAt: new Date(Date.now() + 60000) }
});
}
+233
View File
@@ -0,0 +1,233 @@
import { expect } from 'vitest';
export const examChallengeId = '647e22d18acb466c97ccbef8';
export const examJson = {
id: examChallengeId,
title: 'Exam Certification',
numberOfQuestionsInExam: 3,
passingPercent: 10,
prerequisites: [
{
id: '647f85d407d29547b3bee1bb',
title: 'challenge-title'
}
],
questions: [
{
id: '3bbl2mx2mq',
question: 'Question 1?',
wrongAnswers: [
{ id: 'ex7hii9zup', answer: 'Q1: Wrong Answer 1' },
{ id: 'lmr1ew7m67', answer: 'Q1: Wrong Answer 2' },
{ id: 'qh5sz9qdiq', answer: 'Q1: Wrong Answer 3' },
{ id: 'g489kbwn6a', answer: 'Q1: Wrong Answer 4' },
{ id: '7vu84wl4lc', answer: 'Q1: Wrong Answer 5' },
{ id: 'em59kw6avu', answer: 'Q1: Wrong Answer 6' }
],
correctAnswers: [
{ id: 'dzlokqdc73', answer: 'Q1: Correct Answer 1' },
{ id: 'f5gk39ske9', answer: 'Q1: Correct Answer 2' }
]
},
{
id: 'oqis5gzs0h',
question: 'Question 2?',
wrongAnswers: [
{ id: 'ojhnoxh5r5', answer: 'Q2: Wrong Answer 1' },
{ id: 'onx06if0uh', answer: 'Q2: Wrong Answer 2' },
{ id: 'zbxnsko712', answer: 'Q2: Wrong Answer 3' },
{ id: 'bqv5y68jyp', answer: 'Q2: Wrong Answer 4' },
{ id: 'i5xipitiss', answer: 'Q2: Wrong Answer 5' },
{ id: 'wycrnloajd', answer: 'Q2: Wrong Answer 6' }
],
correctAnswers: [
{ id: 't9ezcsupdl', answer: 'Q2: Correct Answer 1' },
{ id: 'agert35dk0', answer: 'Q2: Correct Answer 2' }
]
},
{
id: 'oqis5gzs0a',
question: 'Question 3?',
wrongAnswers: [
{ id: 'ojhnoxh5ra', answer: 'Q3: Wrong Answer 1' },
{ id: 'onx06if0ub', answer: 'Q3: Wrong Answer 2' },
{ id: 'zbxnsko71c', answer: 'Q3: Wrong Answer 3' },
{ id: 'bqv5y68jyd', answer: 'Q3: Wrong Answer 4' },
{ id: 'i5xipitise', answer: 'Q3: Wrong Answer 5' },
{ id: 'wycrnloajf', answer: 'Q3: Wrong Answer 6' }
],
correctAnswers: [
{ id: 't9ezcsupda', answer: 'Q3: Correct Answer 1' },
{ id: 'agert35dkb', answer: 'Q3: Correct Answer 2' }
]
}
]
};
export const completedTrophyChallenges = [
{
id: '647f85d407d29547b3bee1bb',
solution: 'challenge-solution',
completedDate: 1695064765244,
files: []
}
];
export type ExamSubmission = {
userExamQuestions: {
id: string;
question: string;
answer: {
id: string;
answer: string;
};
}[];
examTimeInSeconds: number;
};
// failed: 0 correct
export const examWithZeroCorrect: ExamSubmission = {
userExamQuestions: [
{
id: '3bbl2mx2mq',
question: 'Question 1?',
answer: { id: 'g489kbwn6a', answer: 'Q1: Wrong Answer 4' }
},
{
id: 'oqis5gzs0h',
question: 'Question 2?',
answer: { id: 'i5xipitiss', answer: 'Q2: Wrong Answer 5' }
},
{
id: 'oqis5gzs0a',
question: 'Question 3?',
answer: { id: 'ojhnoxh5ra', answer: 'Q3: Wrong Answer 1' }
}
],
examTimeInSeconds: 20
};
// passed: 1 correct
export const examWithOneCorrect: ExamSubmission = {
userExamQuestions: [
{
id: '3bbl2mx2mq',
question: 'Question 1?',
answer: { id: 'dzlokqdc73', answer: 'Q1: Correct Answer 1' }
},
{
id: 'oqis5gzs0h',
question: 'Question 2?',
answer: { id: 'i5xipitiss', answer: 'Q2: Wrong Answer 5' }
},
{
id: 'oqis5gzs0a',
question: 'Question 3?',
answer: { id: 'ojhnoxh5ra', answer: 'Q3: Wrong Answer 1' }
}
],
examTimeInSeconds: 20
};
// passed: 2 correct
export const examWithTwoCorrect: ExamSubmission = {
userExamQuestions: [
{
id: '3bbl2mx2mq',
question: 'Question 1?',
answer: { id: 'dzlokqdc73', answer: 'Q1: Correct Answer 1' }
},
{
id: 'oqis5gzs0h',
question: 'Question 2?',
answer: { id: 't9ezcsupdl', answer: 'Q2: Correct Answer 1' }
},
{
id: 'oqis5gzs0a',
question: 'Question 3?',
answer: { id: 'ojhnoxh5ra', answer: 'Q3: Wrong Answer 1' }
}
],
examTimeInSeconds: 20
};
// passed: 3 correct
export const examWithAllCorrect: ExamSubmission = {
userExamQuestions: [
{
id: '3bbl2mx2mq',
question: 'Question 1?',
answer: { id: 'dzlokqdc73', answer: 'Q1: Correct Answer 1' }
},
{
id: 'oqis5gzs0h',
question: 'Question 2?',
answer: { id: 't9ezcsupdl', answer: 'Q2: Correct Answer 1' }
},
{
id: 'oqis5gzs0a',
question: 'Question 3?',
answer: { id: 'agert35dkb', answer: 'Q3: Correct Answer 2' }
}
],
examTimeInSeconds: 20
};
export const mockResultsZeroCorrect = {
numberOfCorrectAnswers: 0,
numberOfQuestionsInExam: 3,
percentCorrect: 0,
passingPercent: 10,
passed: false,
examTimeInSeconds: 20
};
export const mockResultsOneCorrect = {
numberOfCorrectAnswers: 1,
numberOfQuestionsInExam: 3,
percentCorrect: 33.3,
passingPercent: 10,
passed: true,
examTimeInSeconds: 20
};
export const mockResultsTwoCorrect = {
numberOfCorrectAnswers: 2,
numberOfQuestionsInExam: 3,
percentCorrect: 66.7,
passingPercent: 10,
passed: true,
examTimeInSeconds: 20
};
export const mockResultsAllCorrect = {
numberOfCorrectAnswers: 3,
numberOfQuestionsInExam: 3,
percentCorrect: 100,
passingPercent: 10,
passed: true,
examTimeInSeconds: 20
};
const completedExamChallenge = {
id: examChallengeId,
challengeType: 17,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
completedDate: expect.any(Number)
};
export const completedExamChallengeOneCorrect = {
...completedExamChallenge,
examResults: mockResultsOneCorrect
};
export const completedExamChallengeTwoCorrect = {
...completedExamChallenge,
examResults: mockResultsTwoCorrect
};
export const completedExamChallengeAllCorrect = {
...completedExamChallenge,
examResults: mockResultsAllCorrect
};