@@ -54,4 +54,65 @@ public function test_module_extends_navigation(): void {
5454 $ this ->assertTrue ($ node ->exposed_module_extends_navigation ('data ' ));
5555 $ this ->assertFalse ($ node ->exposed_module_extends_navigation ('test1 ' ));
5656 }
57+
58+ /**
59+ * Test that subsections with hidden restrictions (eye closed) are not shown in the navigation
60+ * block, and that subsections with visible restrictions (eye open) still appear.
61+ */
62+ public function test_load_section_activities_navigation_hidden_subsection_visibility (): void {
63+ global $ PAGE , $ CFG ;
64+ require_once ($ CFG ->dirroot . '/course/lib.php ' );
65+
66+ $ this ->resetAfterTest ();
67+ $ this ->setAdminUser ();
68+ set_config ('enableavailability ' , 1 );
69+
70+ $ generator = $ this ->getDataGenerator ();
71+ $ course = $ generator ->create_course (['numsections ' => 1 ]);
72+
73+ $ student = $ generator ->create_user ();
74+ $ generator ->enrol_user ($ student ->id , $ course ->id , 'student ' );
75+
76+ // Profile condition that can never be met: no test user is assigned this reserved address.
77+ $ nevermatchemail = '{"type":"profile","sf":"email","op":"isequalto","v":"nomail@moodle.invalid"} ' ;
78+ // showc:[false] = eye closed (restriction hidden from students).
79+ $ eyeclosed = '{"op":"&","c":[ ' . $ nevermatchemail . '],"showc":[false]} ' ;
80+ // showc:[true] = eye open (restriction visible to students, MDL-87671 scenario).
81+ $ eyeopen = '{"op":"&","c":[ ' . $ nevermatchemail . '],"showc":[true]} ' ;
82+
83+ $ hiddensubsection = $ generator ->create_module ('subsection ' , [
84+ 'course ' => $ course ->id ,
85+ 'section ' => 1 ,
86+ 'availability ' => $ eyeclosed ,
87+ ]);
88+ $ visiblesubsection = $ generator ->create_module ('subsection ' , [
89+ 'course ' => $ course ->id ,
90+ 'section ' => 1 ,
91+ 'availability ' => $ eyeopen ,
92+ ]);
93+
94+ rebuild_course_cache ($ course ->id , true );
95+ $ this ->setUser ($ student );
96+ $ PAGE ->set_url ('/course/view.php ' , ['id ' => $ course ->id ]);
97+ $ PAGE ->set_course ($ course );
98+ $ PAGE ->set_context (\core \context \course::instance ($ course ->id ));
99+
100+ $ modinfo = get_fast_modinfo ($ course );
101+ $ section1 = $ modinfo ->get_section_info (1 );
102+ $ hiddeninfo = $ modinfo ->get_section_info_by_component ('mod_subsection ' , $ hiddensubsection ->id );
103+ $ visibleinfo = $ modinfo ->get_section_info_by_component ('mod_subsection ' , $ visiblesubsection ->id );
104+
105+ $ nav = new exposed_global_navigation ($ PAGE );
106+ $ nav ->set_initialised ();
107+
108+ [, $ activities ] = $ nav ->exposed_generate_sections_and_activities ($ course );
109+
110+ $ sectionnode = $ nav ->add ('Section 1 ' , null , navigation_node::TYPE_SECTION , null , $ section1 ->id );
111+ $ nav ->exposed_load_section_activities_navigation ($ sectionnode , $ section1 , $ activities );
112+
113+ // Eye-closed restricted subsection must NOT appear in the navigation block.
114+ $ this ->assertFalse ($ sectionnode ->find ($ hiddeninfo ->id , navigation_node::TYPE_SECTION ));
115+ // Eye-open restricted subsection MUST appear in navigation (MDL-87671 behaviour).
116+ $ this ->assertNotFalse ($ sectionnode ->find ($ visibleinfo ->id , navigation_node::TYPE_SECTION ));
117+ }
57118}
0 commit comments