fix(tools): ensure module name is available in external curricula data (#60610)

This commit is contained in:
Huyen Nguyen
2025-05-31 00:07:37 +07:00
committed by GitHub
parent 85bda9c63d
commit ac09fc0839
2 changed files with 55 additions and 18 deletions
+2
View File
@@ -1787,6 +1787,7 @@
"css-variables": "Variables", "css-variables": "Variables",
"css-grid": "Grid", "css-grid": "Grid",
"css-animations": "Animations", "css-animations": "Animations",
"review-css": "CSS Review",
"exam-css": "CSS Exam", "exam-css": "CSS Exam",
"code-editors": "Code Editors", "code-editors": "Code Editors",
"javascript-variables-and-strings": "Variables and Strings", "javascript-variables-and-strings": "Variables and Strings",
@@ -1809,6 +1810,7 @@
"recursion": "Recursion", "recursion": "Recursion",
"functional-programming": "Functional Programming", "functional-programming": "Functional Programming",
"asynchronous-javascript": "Asynchronous JavaScript", "asynchronous-javascript": "Asynchronous JavaScript",
"review-javascript": "JavaScript Review",
"exam-javascript": "JavaScript Exam", "exam-javascript": "JavaScript Exam",
"react-fundamentals": "React Fundamentals", "react-fundamentals": "React Fundamentals",
"react-state-hooks-and-routing": "React State, Hooks, and Routing", "react-state-hooks-and-routing": "React State, Hooks, and Routing",
@@ -74,18 +74,25 @@ ${result.error.message}`
}); });
test('the super block files generated should have the correct schema', async () => { test('the super block files generated should have the correct schema', async () => {
const superBlocks = Object.values(SuperBlocks);
const fileArray = ( const fileArray = (
await readdirp.promise(`${clientStaticPath}/curriculum-data/${VERSION}`, { await readdirp.promise(`${clientStaticPath}/curriculum-data/${VERSION}`, {
directoryFilter: ['!challenges'], directoryFilter: ['!challenges'],
fileFilter: entry => { fileFilter: entry => {
// The directory contains super block files and other curriculum-related files. // The directory contains super block files and other curriculum-related files.
// We're only interested in super block ones. // We're only interested in super block ones.
const superBlocks = Object.values(SuperBlocks); const isSuperBlock = superBlocks.some(superBlock =>
return superBlocks.includes(entry.basename); entry.basename.includes(superBlock)
);
return isSuperBlock;
} }
}) })
).map(file => file.path); ).map(file => file.path);
expect(fileArray.length).toBeGreaterThan(0);
fileArray.forEach(fileInArray => { fileArray.forEach(fileInArray => {
const fileContent = fs.readFileSync( const fileContent = fs.readFileSync(
`${clientStaticPath}/curriculum-data/${VERSION}/${fileInArray}`, `${clientStaticPath}/curriculum-data/${VERSION}/${fileInArray}`,
@@ -102,21 +109,30 @@ ${result.error.message}`);
}); });
test('block-based super blocks and blocks should have the correct data', async () => { test('block-based super blocks and blocks should have the correct data', async () => {
const superBlocks = Object.values(SuperBlocks);
const superBlockFiles = ( const superBlockFiles = (
await readdirp.promise(`${clientStaticPath}/curriculum-data/${VERSION}`, { await readdirp.promise(`${clientStaticPath}/curriculum-data/${VERSION}`, {
directoryFilter: ['!challenges'], directoryFilter: ['!challenges'],
fileFilter: entry => { fileFilter: entry => {
// The directory contains super block files and other curriculum-related files. // The directory contains super block files and other curriculum-related files.
// We're only interested in super block ones. // We're only interested in super block ones.
const superBlocks = Object.values(SuperBlocks); const isSuperBlock = superBlocks.some(superBlock =>
return ( entry.basename.includes(superBlock)
superBlocks.includes(entry.basename) &&
!chapterBasedSuperBlocks.includes(entry.basename)
); );
const isChapterBasedSuperBlock = chapterBasedSuperBlocks.some(
chapterBasedSuperBlock =>
entry.basename.includes(chapterBasedSuperBlock)
);
return isSuperBlock && !isChapterBasedSuperBlock;
} }
}) })
).map(file => file.path); ).map(file => file.path);
expect(superBlockFiles.length).toBeGreaterThan(0);
superBlockFiles.forEach(file => { superBlockFiles.forEach(file => {
const fileContentJson = fs.readFileSync( const fileContentJson = fs.readFileSync(
`${clientStaticPath}/curriculum-data/${VERSION}/${file}`, `${clientStaticPath}/curriculum-data/${VERSION}/${file}`,
@@ -135,33 +151,43 @@ ${result.error.message}`);
// Randomly pick a block to check its data. // Randomly pick a block to check its data.
const blocks = superBlockData.blocks; const blocks = superBlockData.blocks;
const randomBlockIndex = Math.floor(Math.random() * blocks.length); const randomBlockIndex = Math.floor(Math.random() * blocks.length);
const randomBlock = blocks[randomBlockIndex];
expect(superBlockData.intro).toEqual(intros[superBlock].intro); expect(superBlockData.intro).toEqual(intros[superBlock].intro);
expect(superBlockData.blocks[randomBlockIndex].intro).toEqual( expect(superBlockData.blocks[randomBlockIndex].intro).toEqual(
intros[superBlock].blocks[randomBlockIndex].intro intros[superBlock].blocks[randomBlock.meta.dashedName as string].intro
); );
expect(superBlockData.blocks[randomBlockIndex].meta.name).toEqual( expect(superBlockData.blocks[randomBlockIndex].meta.name).toEqual(
intros[superBlock].blocks[randomBlockIndex].title intros[superBlock].blocks[randomBlock.meta.dashedName as string].title
); );
}); });
}); });
test('chapter-based super blocks and blocks should have the correct data', async () => { test('chapter-based super blocks and blocks should have the correct data', async () => {
const superBlocks = Object.values(SuperBlocks);
const superBlockFiles = ( const superBlockFiles = (
await readdirp.promise(`${clientStaticPath}/curriculum-data/${VERSION}`, { await readdirp.promise(`${clientStaticPath}/curriculum-data/${VERSION}`, {
directoryFilter: ['!challenges'], directoryFilter: ['!challenges'],
fileFilter: entry => { fileFilter: entry => {
// The directory contains super block files and other curriculum-related files. // The directory contains super block files and other curriculum-related files.
// We're only interested in super block ones. // We're only interested in super block ones.
const superBlocks = Object.values(SuperBlocks); const isSuperBlock = superBlocks.some(superBlock =>
return ( entry.basename.includes(superBlock)
superBlocks.includes(entry.basename) &&
chapterBasedSuperBlocks.includes(entry.basename)
); );
const isChapterBasedSuperBlock = chapterBasedSuperBlocks.some(
chapterBasedSuperBlock =>
entry.basename.includes(chapterBasedSuperBlock)
);
return isSuperBlock && isChapterBasedSuperBlock;
} }
}) })
).map(file => file.path); ).map(file => file.path);
expect(superBlockFiles.length).toBeGreaterThan(0);
superBlockFiles.forEach(file => { superBlockFiles.forEach(file => {
const fileContentJson = fs.readFileSync( const fileContentJson = fs.readFileSync(
`${clientStaticPath}/curriculum-data/${VERSION}/${file}`, `${clientStaticPath}/curriculum-data/${VERSION}/${file}`,
@@ -182,42 +208,51 @@ ${result.error.message}`);
] as ChapterBasedCurriculumIntros[SuperBlocks]; ] as ChapterBasedCurriculumIntros[SuperBlocks];
// Randomly pick a chapter. // Randomly pick a chapter.
const chapters = superBlockData.chapters; const chapters = superBlockData.chapters.filter(
({ comingSoon }) => !comingSoon
);
const randomChapterIndex = Math.floor(Math.random() * chapters.length); const randomChapterIndex = Math.floor(Math.random() * chapters.length);
const randomChapter = chapters[randomChapterIndex]; const randomChapter = chapters[randomChapterIndex];
// Randomly pick a module. // Randomly pick a module.
const modules = randomChapter.modules; const modules = randomChapter.modules.filter(
({ comingSoon }) => !comingSoon
);
const randomModuleIndex = Math.floor(Math.random() * modules.length); const randomModuleIndex = Math.floor(Math.random() * modules.length);
const randomModule = modules[randomModuleIndex]; const randomModule = modules[randomModuleIndex];
// Randomly pick a block. // Randomly pick a block.
const blocks = randomModule.blocks; const blocks = randomModule.blocks;
const randomBlockIndex = Math.floor(Math.random() * blocks.length); const randomBlockIndex = Math.floor(Math.random() * blocks.length);
const randomBlock = blocks[randomBlockIndex];
// Check super block data // Check super block data
expect(superBlockData.intro).toEqual(superBlockIntros.intro); expect(superBlockData.intro).toEqual(superBlockIntros.intro);
// Check chapter data // Check chapter data
expect(superBlockData.chapters[randomChapterIndex].name).toEqual( expect(superBlockData.chapters[randomChapterIndex].name).toEqual(
superBlockIntros.chapters[randomChapterIndex] superBlockIntros.chapters[randomChapter.dashedName]
); );
// Check module data // Check module data
expect( expect(
superBlockData.chapters[randomChapterIndex].modules[randomModuleIndex] superBlockData.chapters[randomChapterIndex].modules[randomModuleIndex]
.name .name
).toEqual(superBlockIntros.modules[randomModuleIndex]); ).toEqual(superBlockIntros.modules[randomModule.dashedName]);
// Check block data // Check block data
expect( expect(
superBlockData.chapters[randomChapterIndex].modules[randomModuleIndex] superBlockData.chapters[randomChapterIndex].modules[randomModuleIndex]
.blocks[randomBlockIndex].intro .blocks[randomBlockIndex].intro
).toEqual(superBlockIntros.blocks[randomBlockIndex].intro); ).toEqual(
superBlockIntros.blocks[randomBlock.meta.dashedName as string].intro
);
expect( expect(
superBlockData.chapters[randomChapterIndex].modules[randomModuleIndex] superBlockData.chapters[randomChapterIndex].modules[randomModuleIndex]
.blocks[randomBlockIndex].meta.name .blocks[randomBlockIndex].meta.name
).toEqual(superBlockIntros.blocks[randomBlockIndex].title); ).toEqual(
superBlockIntros.blocks[randomBlock.meta.dashedName as string].title
);
}); });
}); });