fix: make sure ext curriculum tests fail if missing meta (#61904)

This commit is contained in:
Oliver Eyton-Williams
2025-08-21 19:57:45 +02:00
committed by GitHub
parent b246d99b30
commit efe3d22b06
3 changed files with 134 additions and 116 deletions

View File

@@ -72,14 +72,18 @@ ${result.error.message}`
await readdirp.promise(`${clientStaticPath}/curriculum-data/${VERSION}`, {
directoryFilter: ['!challenges'],
fileFilter: entry => {
// path without extension:
const filePath = entry.path.replace(/\.json$/, '');
// The directory contains super block files and other curriculum-related files.
// We're only interested in super block ones.
const superBlocks = Object.values(SuperBlocks);
return superBlocks.includes(entry.basename);
return superBlocks.includes(filePath);
}
})
).map(file => file.path);
expect(fileArray.length).toBeGreaterThan(0);
fileArray.forEach(fileInArray => {
const fileContent = fs.readFileSync(
`${clientStaticPath}/curriculum-data/${VERSION}/${fileInArray}`,
@@ -100,14 +104,18 @@ ${result.error.message}`);
await readdirp.promise(`${clientStaticPath}/curriculum-data/${VERSION}`, {
directoryFilter: ['!challenges'],
fileFilter: entry => {
// path without extension:
const filePath = entry.path.replace(/\.json$/, '');
// The directory contains super block files and other curriculum-related files.
// We're only interested in super block ones.
const superBlocks = Object.values(SuperBlocks);
return superBlocks.includes(entry.basename);
return superBlocks.includes(filePath);
}
})
).map(file => file.path);
expect(superBlockFiles.length).toBeGreaterThan(0);
superBlockFiles.forEach(file => {
const fileContentJson = fs.readFileSync(
`${clientStaticPath}/curriculum-data/${VERSION}/${file}`,

View File

@@ -2,63 +2,68 @@ const Joi = require('joi');
const blockSchema = Joi.object({}).keys({
desc: Joi.array().min(1),
challenges: Joi.object({}).keys({
name: Joi.string().required(),
isUpcomingChange: Joi.bool().required(),
usesMultifileEditor: Joi.bool().optional(),
hasEditableBoundaries: Joi.bool().optional(),
dashedName: Joi.string().required(),
helpCategory: Joi.valid(
'JavaScript',
'HTML-CSS',
'Python',
'Backend Development',
'C-Sharp',
'English',
'Odin',
'Euler',
'Rosetta'
).required(),
order: Joi.number().when('superBlock', {
is: 'full-stack-developer',
then: Joi.forbidden(),
otherwise: Joi.required()
}),
template: Joi.string().allow(''),
required: Joi.array(),
superBlock: Joi.string().required(),
blockLayout: Joi.valid(
'challenge-list',
'challenge-grid',
'dialogue-grid',
'link',
'project-list',
'legacy-challenge-list',
'legacy-link',
'legacy-challenge-grid'
).required(),
blockType: Joi.valid(
'lecture',
'workshop',
'lab',
'review',
'quiz',
'exam'
).when('superBlock', {
is: 'full-stack-developer',
then: Joi.required(),
otherwise: Joi.optional()
}),
challengeOrder: Joi.array().items(
Joi.object({}).keys({
id: Joi.string(),
title: Joi.string()
})
),
disableLoopProtectTests: Joi.boolean(),
disableLoopProtectPreview: Joi.boolean(),
superOrder: Joi.number()
})
challenges: Joi.object({})
.keys({
name: Joi.string().required(),
isUpcomingChange: Joi.bool().required(),
usesMultifileEditor: Joi.bool().optional(),
hasEditableBoundaries: Joi.bool().optional(),
dashedName: Joi.string().required(),
helpCategory: Joi.valid(
'JavaScript',
'HTML-CSS',
'Python',
'Backend Development',
'C-Sharp',
'English',
'Odin',
'Euler',
'Rosetta'
).required(),
order: Joi.number().when('superBlock', {
is: 'full-stack-developer',
then: Joi.forbidden(),
otherwise: Joi.required()
}),
template: Joi.string().allow(''),
required: Joi.array(),
superBlock: Joi.string().required(),
blockLayout: Joi.valid(
'challenge-list',
'challenge-grid',
'dialogue-grid',
'link',
'project-list',
'legacy-challenge-list',
'legacy-link',
'legacy-challenge-grid'
).required(),
blockType: Joi.valid(
'lecture',
'workshop',
'lab',
'review',
'quiz',
'exam'
).when('superBlock', {
is: 'full-stack-developer',
then: Joi.required(),
otherwise: Joi.optional()
}),
challengeOrder: Joi.array()
.items(
Joi.object({}).keys({
id: Joi.string(),
title: Joi.string()
})
)
.min(1)
.required(),
disableLoopProtectTests: Joi.boolean(),
disableLoopProtectPreview: Joi.boolean(),
superOrder: Joi.number()
})
.required()
});
const subSchema = Joi.object({}).keys({

View File

@@ -7,63 +7,68 @@ const slugRE = new RegExp('^[a-z0-9-]+$');
const blockSchema = Joi.object().keys({
intro: Joi.array().min(1),
meta: Joi.object({}).keys({
name: Joi.string().required(),
isUpcomingChange: Joi.bool().required(),
usesMultifileEditor: Joi.bool().optional(),
hasEditableBoundaries: Joi.bool().optional(),
dashedName: Joi.string().required(),
helpCategory: Joi.valid(
'JavaScript',
'HTML-CSS',
'Python',
'Backend Development',
'C-Sharp',
'English',
'Odin',
'Euler',
'Rosetta'
).required(),
order: Joi.number().when('superBlock', {
is: chapterBasedSuperBlocks,
then: Joi.forbidden(),
otherwise: Joi.required()
}),
template: Joi.string().allow(''),
required: Joi.array(),
superBlock: Joi.string().required(),
blockLayout: Joi.valid(
'challenge-list',
'challenge-grid',
'dialogue-grid',
'link',
'project-list',
'legacy-challenge-list',
'legacy-link',
'legacy-challenge-grid'
).required(),
blockType: Joi.valid(
'lecture',
'workshop',
'lab',
'review',
'quiz',
'exam'
).when('superBlock', {
is: chapterBasedSuperBlocks,
then: Joi.required(),
otherwise: Joi.optional()
}),
challengeOrder: Joi.array().items(
Joi.object({}).keys({
id: Joi.string(),
title: Joi.string()
})
),
disableLoopProtectTests: Joi.boolean(),
disableLoopProtectPreview: Joi.boolean(),
superOrder: Joi.number()
})
meta: Joi.object({})
.keys({
name: Joi.string().required(),
isUpcomingChange: Joi.bool().required(),
usesMultifileEditor: Joi.bool().optional(),
hasEditableBoundaries: Joi.bool().optional(),
dashedName: Joi.string().required(),
helpCategory: Joi.valid(
'JavaScript',
'HTML-CSS',
'Python',
'Backend Development',
'C-Sharp',
'English',
'Odin',
'Euler',
'Rosetta'
).required(),
order: Joi.number().when('superBlock', {
is: chapterBasedSuperBlocks,
then: Joi.forbidden(),
otherwise: Joi.required()
}),
template: Joi.string().allow(''),
required: Joi.array(),
superBlock: Joi.string().required(),
blockLayout: Joi.valid(
'challenge-list',
'challenge-grid',
'dialogue-grid',
'link',
'project-list',
'legacy-challenge-list',
'legacy-link',
'legacy-challenge-grid'
).required(),
blockType: Joi.valid(
'lecture',
'workshop',
'lab',
'review',
'quiz',
'exam'
).when('superBlock', {
is: chapterBasedSuperBlocks,
then: Joi.required(),
otherwise: Joi.optional()
}),
challengeOrder: Joi.array().items(
Joi.object({})
.keys({
id: Joi.string(),
title: Joi.string()
})
.min(1)
.required()
),
disableLoopProtectTests: Joi.boolean(),
disableLoopProtectPreview: Joi.boolean(),
superOrder: Joi.number()
})
.required()
});
const blockBasedCurriculumSchema = Joi.object().pattern(