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 = {
|
export const examAttempt: ExamEnvironmentExamAttempt = {
|
||||||
@@ -293,7 +294,8 @@ export const examAttempt: ExamEnvironmentExamAttempt = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
startTimeInMS: Date.now(),
|
startTimeInMS: Date.now(),
|
||||||
userId: defaultUserId
|
userId: defaultUserId,
|
||||||
|
version: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
export const examAttemptSansSubmissionTimeInMS: Static<
|
export const examAttemptSansSubmissionTimeInMS: Static<
|
||||||
@@ -340,7 +342,8 @@ export const exam: ExamEnvironmentExam = {
|
|||||||
config,
|
config,
|
||||||
questionSets,
|
questionSets,
|
||||||
prerequisites: ['67112fe1c994faa2c26d0b1d'],
|
prerequisites: ['67112fe1c994faa2c26d0b1d'],
|
||||||
deprecated: false
|
deprecated: false,
|
||||||
|
version: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function seedEnvExam() {
|
export async function seedEnvExam() {
|
||||||
|
|||||||
@@ -182,6 +182,9 @@ model ExamEnvironmentExam {
|
|||||||
prerequisites String[] @db.ObjectId
|
prerequisites String[] @db.ObjectId
|
||||||
/// If `deprecated`, the exam should no longer be considered for users
|
/// If `deprecated`, the exam should no longer be considered for users
|
||||||
deprecated Boolean
|
deprecated Boolean
|
||||||
|
/// Version of the record
|
||||||
|
/// The default must be incremented by 1, if anything in the schema changes
|
||||||
|
version Int @default(1)
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
generatedExams ExamEnvironmentGeneratedExam[]
|
generatedExams ExamEnvironmentGeneratedExam[]
|
||||||
@@ -313,6 +316,9 @@ model ExamEnvironmentExamAttempt {
|
|||||||
questionSets ExamEnvironmentQuestionSetAttempt[]
|
questionSets ExamEnvironmentQuestionSetAttempt[]
|
||||||
/// Time exam was started as milliseconds since epoch
|
/// Time exam was started as milliseconds since epoch
|
||||||
startTimeInMS Int
|
startTimeInMS Int
|
||||||
|
/// Version of the record
|
||||||
|
/// The default must be incremented by 1, if anything in the schema changes
|
||||||
|
version Int @default(1)
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
user user @relation(fields: [userId], references: [id], onDelete: Cascade)
|
user user @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
@@ -347,6 +353,9 @@ model ExamEnvironmentGeneratedExam {
|
|||||||
questionSets ExamEnvironmentGeneratedQuestionSet[]
|
questionSets ExamEnvironmentGeneratedQuestionSet[]
|
||||||
/// If `deprecated`, the generation should not longer be considered for users
|
/// If `deprecated`, the generation should not longer be considered for users
|
||||||
deprecated Boolean
|
deprecated Boolean
|
||||||
|
/// Version of the record
|
||||||
|
/// The default must be incremented by 1, if anything in the schema changes
|
||||||
|
version Int @default(1)
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
exam ExamEnvironmentExam @relation(fields: [examId], references: [id], onDelete: Cascade)
|
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
|
/// Date the exam attempt was added to the moderation queue
|
||||||
submissionDate DateTime @default(now()) @db.Date
|
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
|
// Relations
|
||||||
examAttempt ExamEnvironmentExamAttempt @relation(fields: [examAttemptId], references: [id], onDelete: Cascade)
|
examAttempt ExamEnvironmentExamAttempt @relation(fields: [examAttemptId], references: [id], onDelete: Cascade)
|
||||||
|
|||||||
@@ -512,7 +512,9 @@ describe('/exam-environment/', () => {
|
|||||||
generatedExamId: generatedExam!.id,
|
generatedExamId: generatedExam!.id,
|
||||||
questionSets: [],
|
questionSets: [],
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
// 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 { type Static } from '@fastify/type-provider-typebox';
|
||||||
import {
|
import {
|
||||||
exam,
|
exam,
|
||||||
examAttempt,
|
examAttempt,
|
||||||
generatedExam
|
generatedExam,
|
||||||
|
oid
|
||||||
} from '../../../__mocks__/exam-environment-exam';
|
} from '../../../__mocks__/exam-environment-exam';
|
||||||
import * as schemas from '../schemas';
|
import * as schemas from '../schemas';
|
||||||
|
import { setupServer } from '../../../jest.utils';
|
||||||
import {
|
import {
|
||||||
checkAttemptAgainstGeneratedExam,
|
checkAttemptAgainstGeneratedExam,
|
||||||
checkPrerequisites,
|
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<
|
export type UserExam = Omit<
|
||||||
ExamEnvironmentExam,
|
ExamEnvironmentExam,
|
||||||
'questionSets' | 'config' | 'id' | 'prerequisites' | 'deprecated'
|
'questionSets' | 'config' | 'id' | 'prerequisites' | 'deprecated' | 'version'
|
||||||
> & {
|
> & {
|
||||||
config: Omit<ExamEnvironmentExam['config'], 'tags' | 'questionSets'>;
|
config: Omit<ExamEnvironmentExam['config'], 'tags' | 'questionSets'>;
|
||||||
questionSets: (Omit<ExamEnvironmentQuestionSet, 'questions'> & {
|
questionSets: (Omit<ExamEnvironmentQuestionSet, 'questions'> & {
|
||||||
@@ -280,7 +280,7 @@ export function userAttemptToDatabaseAttemptQuestionSets(
|
|||||||
*/
|
*/
|
||||||
export function generateExam(
|
export function generateExam(
|
||||||
exam: ExamEnvironmentExam
|
exam: ExamEnvironmentExam
|
||||||
): Omit<ExamEnvironmentGeneratedExam, 'id'> {
|
): Omit<ExamEnvironmentGeneratedExam, 'id' | 'version'> {
|
||||||
const examCopy = structuredClone(exam);
|
const examCopy = structuredClone(exam);
|
||||||
|
|
||||||
const TIMEOUT_IN_MS = 5_000;
|
const TIMEOUT_IN_MS = 5_000;
|
||||||
|
|||||||
Reference in New Issue
Block a user