From cf3b8797a309cfecb3b2323891fc230f51d062a9 Mon Sep 17 00:00:00 2001 From: Brad Simpson Date: Sun, 21 Jun 2026 17:43:26 -0600 Subject: [PATCH] Fix: guard mcq migrations against components without _items The v4.1.0 > v4.2.0 mutates ("add item _isPartlyCorrect", "add item _score") and the v7.3.11 > v7.4.0 mutate ("add altText to _items") accessed MCQ._items.forEach(...) with no guard, throwing "TypeError: Cannot read properties of undefined (reading 'forEach')" for an mcq with no _items. The v4.2.0 testSuccessWhere (itemless mcq) already failed because of this. Use MCQ._items?.forEach(...) in the mutates and (MCQ._items ?? []).every(...) in the matching checks so an absent _items array is handled gracefully. Co-Authored-By: Claude Opus 4.8 (1M context) --- migrations/v4.js | 8 ++++---- migrations/v7.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/migrations/v4.js b/migrations/v4.js index f2e79cd..92944be 100644 --- a/migrations/v4.js +++ b/migrations/v4.js @@ -172,7 +172,7 @@ describe('MCQ - v4.1.0 to v4.2.0', async () => { }); mutateContent('MCQ - add item _isPartlyCorrect attribute', async (content) => { MCQs.forEach(MCQ => { - MCQ._items.forEach(item => { + MCQ._items?.forEach(item => { item._isPartlyCorrect = false; }); }); @@ -180,7 +180,7 @@ describe('MCQ - v4.1.0 to v4.2.0', async () => { }); mutateContent('MCQ - add item _score attribute', async (content) => { MCQs.forEach(MCQ => { - MCQ._items.forEach(item => { + MCQ._items?.forEach(item => { item._score = 0; }); }); @@ -193,14 +193,14 @@ describe('MCQ - v4.1.0 to v4.2.0', async () => { }); checkContent('MCQ - check item _isPartlyCorrect attribute', async(content) => { const isValid = MCQs.every(MCQ => { - return MCQ._items.every(item => _.has(item, '_isPartlyCorrect')); + return (MCQ._items ?? []).every(item => _.has(item, '_isPartlyCorrect')); }); if (!isValid) throw new Error('MCQ - no item _isPartlyCorrect found'); return true; }); checkContent('MCQ - check item _score attribute', async(content) => { const isValid = MCQs.every(MCQ => { - return MCQ._items.every(item => _.has(item, '_score')); + return (MCQ._items ?? []).every(item => _.has(item, '_score')); }); if (!isValid) throw new Error('MCQ - no item _score found'); return true; diff --git a/migrations/v7.js b/migrations/v7.js index 104a7a2..1494676 100644 --- a/migrations/v7.js +++ b/migrations/v7.js @@ -105,7 +105,7 @@ describe('MCQ - v7.3.11 to v7.4.0', async () => { }); mutateContent('MCQ - add altText attribute to _items', async (content) => { MCQs.forEach(MCQ => { - MCQ._items.forEach(item => { + MCQ._items?.forEach(item => { item.altText = ''; }); }); @@ -113,7 +113,7 @@ describe('MCQ - v7.3.11 to v7.4.0', async () => { }); checkContent('MCQ - check item altText attribute', async (content) => { const isValid = MCQs.every(MCQ => { - return MCQ._items.every(item => _.has(item, 'altText')); + return (MCQ._items ?? []).every(item => _.has(item, 'altText')); }); if (!isValid) throw new Error('MCQ - no item altText found'); return true;