fix: Include metadata for blocked sequence units to enable proper navigation (#36485)
The original issue was that when a sequence was locked due to prerequisites, the API returned an empty items array ([]). This prevented the frontend from knowing what units were inside the locked sequence, meaning it couldn't construct the URLs correctly for navigation so the next/previous buttons stop working.
This commit is contained in:
@@ -557,7 +557,19 @@ class SequenceBlock(
|
||||
'This section is a prerequisite. You must complete this section in order to unlock additional content.'
|
||||
)
|
||||
|
||||
blocks = self._render_student_view_for_blocks(context, children, fragment, view) if prereq_met else []
|
||||
if prereq_met:
|
||||
blocks = self._render_student_view_for_blocks(context, children, fragment, view)
|
||||
else:
|
||||
blocks = []
|
||||
for child in children:
|
||||
usage_id = child.scope_ids.usage_id
|
||||
blocks.append({
|
||||
'id': str(usage_id),
|
||||
'type': child.scope_ids.block_type,
|
||||
'display_name': child.display_name_with_default,
|
||||
'is_gated': True, # Mark as blocked
|
||||
'content': '', # Real content not included
|
||||
})
|
||||
|
||||
params = {
|
||||
'items': blocks,
|
||||
|
||||
@@ -478,3 +478,97 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
# Replace tuple and un-necessary info from inside string and get the dictionary.
|
||||
cleaned_data = data.replace("(('seq_block.html',\n", '').replace("),\n {})", '').strip()
|
||||
return ast.literal_eval(cleaned_data)
|
||||
|
||||
def test_not_gated_blocks_rendered_normally(self):
|
||||
"""
|
||||
Test that non-gated blocks are rendered with full content when prerequisites are met.
|
||||
"""
|
||||
# Mock child block
|
||||
child = Mock()
|
||||
child.scope_ids.usage_id = "block1"
|
||||
child.scope_ids.block_type = "vertical"
|
||||
child.display_name_with_default = "Test Block"
|
||||
children = [child]
|
||||
|
||||
# Mock context
|
||||
context = {"next_url": "next_url", "prev_url": "prev_url"}
|
||||
fragment = Mock()
|
||||
|
||||
# Mock `_render_student_view_for_blocks`
|
||||
self.sequence_3_1._render_student_view_for_blocks = Mock(return_value="rendered_blocks") # pylint: disable=protected-access
|
||||
|
||||
# Call `_get_render_metadata` with prerequisites met
|
||||
metadata = self.sequence_3_1._get_render_metadata( # pylint: disable=protected-access
|
||||
context, children, prereq_met=True, prereq_meta_info={}, fragment=fragment
|
||||
)
|
||||
|
||||
# Assert that blocks are rendered normally
|
||||
assert metadata["items"] == "rendered_blocks"
|
||||
assert metadata["next_url"] == "next_url"
|
||||
assert metadata["prev_url"] == "prev_url"
|
||||
|
||||
def test_gated_blocks_rendered_with_basic_info(self):
|
||||
"""
|
||||
Test that gated blocks are rendered with minimal metadata when prerequisites are not met.
|
||||
"""
|
||||
# Mock child block
|
||||
child = Mock()
|
||||
child.scope_ids.usage_id = "block1"
|
||||
child.scope_ids.block_type = "vertical"
|
||||
child.display_name_with_default = "Test Block"
|
||||
children = [child]
|
||||
|
||||
# Mock context
|
||||
context = {"next_url": "next_url", "prev_url": "prev_url"}
|
||||
|
||||
# Mock prereq_meta_info with required keys
|
||||
prereq_meta_info = {
|
||||
"url": "http://example.com/prereq",
|
||||
"display_name": "Prerequisite Section",
|
||||
"id": "prereq_block_id",
|
||||
}
|
||||
|
||||
# Call `_get_render_metadata` with prerequisites not met
|
||||
metadata = self.sequence_3_1._get_render_metadata( # pylint: disable=protected-access
|
||||
context, children, prereq_met=False, prereq_meta_info=prereq_meta_info
|
||||
)
|
||||
|
||||
# Assert that gated blocks are rendered with basic info
|
||||
assert len(metadata["items"]) == 1
|
||||
assert metadata["items"][0]["id"] == "block1"
|
||||
assert metadata["items"][0]["type"] == "vertical"
|
||||
assert metadata["items"][0]["display_name"] == "Test Block"
|
||||
assert metadata["items"][0]["is_gated"] is True
|
||||
assert metadata["items"][0]["content"] == ""
|
||||
|
||||
# Assert that next and previous URLs are present
|
||||
assert metadata["next_url"] == "next_url"
|
||||
assert metadata["prev_url"] == "prev_url"
|
||||
|
||||
def test_prereqs_met_content_rendered_normally(self):
|
||||
"""
|
||||
Test that content is rendered normally when prerequisites are met.
|
||||
"""
|
||||
# Mock child block
|
||||
child = Mock()
|
||||
child.scope_ids.usage_id = "block1"
|
||||
child.scope_ids.block_type = "vertical"
|
||||
child.display_name_with_default = "Test Block"
|
||||
children = [child]
|
||||
|
||||
# Mock context
|
||||
context = {"next_url": "next_url", "prev_url": "prev_url"}
|
||||
fragment = Mock()
|
||||
|
||||
# Mock `_render_student_view_for_blocks`
|
||||
self.sequence_3_1._render_student_view_for_blocks = Mock(return_value="rendered_blocks") # pylint: disable=protected-access
|
||||
|
||||
# Call `_get_render_metadata` with prerequisites met
|
||||
metadata = self.sequence_3_1._get_render_metadata( # pylint: disable=protected-access
|
||||
context, children, prereq_met=True, prereq_meta_info={}, fragment=fragment
|
||||
)
|
||||
|
||||
# Assert that content is rendered normally
|
||||
assert metadata["items"] == "rendered_blocks"
|
||||
assert metadata["next_url"] == "next_url"
|
||||
assert metadata["prev_url"] == "prev_url"
|
||||
|
||||
Reference in New Issue
Block a user