mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(api): add version to exam collections (#61644)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@@ -248,7 +248,8 @@ export const generatedExam: ExamEnvironmentGeneratedExam = {
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
version: 1
|
||||
};
|
||||
|
||||
export const examAttempt: ExamEnvironmentExamAttempt = {
|
||||
@@ -293,7 +294,8 @@ export const examAttempt: ExamEnvironmentExamAttempt = {
|
||||
}
|
||||
],
|
||||
startTimeInMS: Date.now(),
|
||||
userId: defaultUserId
|
||||
userId: defaultUserId,
|
||||
version: 1
|
||||
};
|
||||
|
||||
export const examAttemptSansSubmissionTimeInMS: Static<
|
||||
@@ -340,7 +342,8 @@ export const exam: ExamEnvironmentExam = {
|
||||
config,
|
||||
questionSets,
|
||||
prerequisites: ['67112fe1c994faa2c26d0b1d'],
|
||||
deprecated: false
|
||||
deprecated: false,
|
||||
version: 1
|
||||
};
|
||||
|
||||
export async function seedEnvExam() {
|
||||
|
||||
@@ -182,6 +182,9 @@ model ExamEnvironmentExam {
|
||||
prerequisites String[] @db.ObjectId
|
||||
/// If `deprecated`, the exam should no longer be considered for users
|
||||
deprecated Boolean
|
||||
/// Version of the record
|
||||
/// The default must be incremented by 1, if anything in the schema changes
|
||||
version Int @default(1)
|
||||
|
||||
// Relations
|
||||
generatedExams ExamEnvironmentGeneratedExam[]
|
||||
@@ -313,6 +316,9 @@ model ExamEnvironmentExamAttempt {
|
||||
questionSets ExamEnvironmentQuestionSetAttempt[]
|
||||
/// Time exam was started as milliseconds since epoch
|
||||
startTimeInMS Int
|
||||
/// Version of the record
|
||||
/// The default must be incremented by 1, if anything in the schema changes
|
||||
version Int @default(1)
|
||||
|
||||
// Relations
|
||||
user user @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
@@ -347,6 +353,9 @@ model ExamEnvironmentGeneratedExam {
|
||||
questionSets ExamEnvironmentGeneratedQuestionSet[]
|
||||
/// If `deprecated`, the generation should not longer be considered for users
|
||||
deprecated Boolean
|
||||
/// Version of the record
|
||||
/// The default must be incremented by 1, if anything in the schema changes
|
||||
version Int @default(1)
|
||||
|
||||
// Relations
|
||||
exam ExamEnvironmentExam @relation(fields: [examId], references: [id], onDelete: Cascade)
|
||||
@@ -549,6 +558,9 @@ model ExamEnvironmentExamModeration {
|
||||
|
||||
/// Date the exam attempt was added to the moderation queue
|
||||
submissionDate DateTime @default(now()) @db.Date
|
||||
/// Version of the record
|
||||
/// The default must be incremented by 1, if anything in the schema changes
|
||||
version Int @default(1)
|
||||
|
||||
// Relations
|
||||
examAttempt ExamEnvironmentExamAttempt @relation(fields: [examAttemptId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@ -512,7 +512,9 @@ describe('/exam-environment/', () => {
|
||||
generatedExamId: generatedExam!.id,
|
||||
questionSets: [],
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
startTimeInMS: expect.any(Number)
|
||||
startTimeInMS: expect.any(Number),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
version: expect.any(Number)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { ExamEnvironmentAnswer } from '@prisma/client';
|
||||
import {
|
||||
ExamEnvironmentAnswer,
|
||||
ExamEnvironmentQuestionType
|
||||
} from '@prisma/client';
|
||||
import { type Static } from '@fastify/type-provider-typebox';
|
||||
import {
|
||||
exam,
|
||||
examAttempt,
|
||||
generatedExam
|
||||
generatedExam,
|
||||
oid
|
||||
} from '../../../__mocks__/exam-environment-exam';
|
||||
import * as schemas from '../schemas';
|
||||
import { setupServer } from '../../../jest.utils';
|
||||
import {
|
||||
checkAttemptAgainstGeneratedExam,
|
||||
checkPrerequisites,
|
||||
@@ -408,3 +413,117 @@ describe('Exam Environment', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Exam Environment Schema', () => {
|
||||
setupServer();
|
||||
describe('ExamEnvironmentExam', () => {
|
||||
afterAll(async () => {
|
||||
await fastifyTestInstance.prisma.examEnvironmentExam.deleteMany({});
|
||||
});
|
||||
|
||||
it("If this test fails and you've deliberately altered the schema, then increment the `version` field by 1", async () => {
|
||||
const configQuestionSets = [
|
||||
{
|
||||
numberOfCorrectAnswers: 0,
|
||||
numberOfIncorrectAnswers: 0,
|
||||
numberOfQuestions: 0,
|
||||
numberOfSet: 0,
|
||||
type: ExamEnvironmentQuestionType.MultipleChoice
|
||||
}
|
||||
];
|
||||
const tags = [
|
||||
{
|
||||
group: [''],
|
||||
numberOfQuestions: 0
|
||||
}
|
||||
];
|
||||
const config = {
|
||||
name: '',
|
||||
note: '',
|
||||
passingPercent: 0.0,
|
||||
questionSets: configQuestionSets,
|
||||
retakeTimeInMS: 0,
|
||||
tags,
|
||||
totalTimeInMS: 0
|
||||
};
|
||||
|
||||
const questions = [
|
||||
{
|
||||
answers: [
|
||||
{
|
||||
id: oid(),
|
||||
isCorrect: false,
|
||||
text: ''
|
||||
}
|
||||
],
|
||||
audio: { captions: '', url: '' },
|
||||
deprecated: false,
|
||||
id: oid(),
|
||||
tags: [''],
|
||||
text: ''
|
||||
}
|
||||
];
|
||||
const questionSets = [
|
||||
{
|
||||
context: '',
|
||||
id: oid(),
|
||||
questions,
|
||||
type: ExamEnvironmentQuestionType.MultipleChoice
|
||||
}
|
||||
];
|
||||
const data = {
|
||||
config,
|
||||
deprecated: false,
|
||||
prerequisites: [oid()],
|
||||
questionSets
|
||||
};
|
||||
|
||||
await fastifyTestInstance.prisma.examEnvironmentExam.create({
|
||||
data
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('ExamEnvironmentGeneratedExam', () => {
|
||||
afterAll(async () => {
|
||||
await fastifyTestInstance.prisma.examEnvironmentGeneratedExam.deleteMany(
|
||||
{}
|
||||
);
|
||||
});
|
||||
it("If this test fails and you've deliberately altered the schema, then increment the `version` field by 1", async () => {
|
||||
await fastifyTestInstance.prisma.examEnvironmentGeneratedExam.create({
|
||||
data: {
|
||||
deprecated: false,
|
||||
examId: oid(),
|
||||
questionSets: [
|
||||
{ id: oid(), questions: [{ answers: [oid()], id: oid() }] }
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('ExamEnvironmentExamAttempt', () => {
|
||||
afterAll(async () => {
|
||||
await fastifyTestInstance.prisma.examEnvironmentExamAttempt.deleteMany(
|
||||
{}
|
||||
);
|
||||
});
|
||||
it("If this test fails and you've deliberately altered the schema, then increment the `version` field by 1", async () => {
|
||||
await fastifyTestInstance.prisma.examEnvironmentExamAttempt.create({
|
||||
data: {
|
||||
examId: oid(),
|
||||
generatedExamId: oid(),
|
||||
questionSets: [
|
||||
{
|
||||
id: oid(),
|
||||
questions: [
|
||||
{ answers: [oid()], id: oid(), submissionTimeInMS: 0 }
|
||||
]
|
||||
}
|
||||
],
|
||||
startTimeInMS: 0,
|
||||
userId: oid()
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ export function checkPrerequisites(
|
||||
|
||||
export type UserExam = Omit<
|
||||
ExamEnvironmentExam,
|
||||
'questionSets' | 'config' | 'id' | 'prerequisites' | 'deprecated'
|
||||
'questionSets' | 'config' | 'id' | 'prerequisites' | 'deprecated' | 'version'
|
||||
> & {
|
||||
config: Omit<ExamEnvironmentExam['config'], 'tags' | 'questionSets'>;
|
||||
questionSets: (Omit<ExamEnvironmentQuestionSet, 'questions'> & {
|
||||
@@ -280,7 +280,7 @@ export function userAttemptToDatabaseAttemptQuestionSets(
|
||||
*/
|
||||
export function generateExam(
|
||||
exam: ExamEnvironmentExam
|
||||
): Omit<ExamEnvironmentGeneratedExam, 'id'> {
|
||||
): Omit<ExamEnvironmentGeneratedExam, 'id' | 'version'> {
|
||||
const examCopy = structuredClone(exam);
|
||||
|
||||
const TIMEOUT_IN_MS = 5_000;
|
||||
|
||||
Reference in New Issue
Block a user