diff --git a/blocks/section_links/renderer.php b/blocks/section_links/renderer.php index a1ebe8756bb..ac47accb753 100644 --- a/blocks/section_links/renderer.php +++ b/blocks/section_links/renderer.php @@ -57,7 +57,11 @@ class block_section_links_renderer extends plugin_renderer_base { if ($section->highlight) { $sectiontext = html_writer::tag('strong', $sectiontext); } - $html .= html_writer::link(course_get_url($course, $section->section), $sectiontext, $attributes); + $html .= html_writer::link( + course_get_url($course, $section->section, ['navigation' => true]), + $sectiontext, + $attributes + ); $html .= html_writer::end_tag('li').' '; } $html .= html_writer::end_tag('ol'); @@ -78,4 +82,4 @@ class block_section_links_renderer extends plugin_renderer_base { return $html; } -} \ No newline at end of file +} diff --git a/course/format/classes/base.php b/course/format/classes/base.php index f95acd80905..3faf702a909 100644 --- a/course/format/classes/base.php +++ b/course/format/classes/base.php @@ -711,15 +711,14 @@ abstract class base { * @param int|stdClass $section Section object from database or just field course_sections.section * if null the course view page is returned * @param array $options options for view URL. At the moment core uses: - * 'navigation' (bool) if true and section has no separate page, the function returns null - * 'sr' (int) used by multipage formats to specify to which section to return + * 'navigation' (bool) if true and section not empty, the function returns section page; otherwise, it returns course page. + * 'sr' (int) used by course formats to specify to which section to return * 'expanded' (bool) if true the section will be shown expanded, true by default * @return null|moodle_url */ public function get_view_url($section, $options = array()) { - global $CFG; $course = $this->get_course(); - $url = new moodle_url('/course/view.php', array('id' => $course->id)); + $url = new moodle_url('/course/view.php', ['id' => $course->id]); if (array_key_exists('sr', $options)) { $sectionno = $options['sr']; @@ -728,9 +727,10 @@ abstract class base { } else { $sectionno = $section; } - if (empty($CFG->linkcoursesections) && !empty($options['navigation']) && $sectionno !== null) { - // By default assume that sections are never displayed on separate pages. - return null; + if ((!empty($options['navigation']) || array_key_exists('sr', $options)) && $sectionno !== null) { + // Display section on separate page. + $sectioninfo = $this->get_section($sectionno); + return new moodle_url('/course/section.php', ['id' => $sectioninfo->id]); } if ($this->uses_sections() && $sectionno !== null) { // The url includes the parameter to expand the section by default. @@ -743,6 +743,7 @@ abstract class base { } $url->set_anchor('section-'.$sectionno); } + return $url; } @@ -1915,4 +1916,13 @@ abstract class base { return get_fast_modinfo($course)->get_section_info_by_id($newsection->id); } + + /** + * Get the required javascript files for the course format. + * + * @return array The list of javascript files required by the course format. + */ + public function get_required_jsfiles(): array { + return []; + } } diff --git a/course/format/classes/output/local/content.php b/course/format/classes/output/local/content.php index e7d1ec4bf6f..225f9037ff8 100644 --- a/course/format/classes/output/local/content.php +++ b/course/format/classes/output/local/content.php @@ -86,12 +86,8 @@ class content implements named_templatable, renderable { global $PAGE; $format = $this->format; - // Most formats uses section 0 as a separate section so we remove from the list. $sections = $this->export_sections($output); $initialsection = ''; - if (!empty($sections)) { - $initialsection = array_shift($sections); - } $data = (object)[ 'title' => $format->page_title(), // This method should be in the course_format class. @@ -188,7 +184,6 @@ class content implements named_templatable, renderable { $singlesection = $this->format->get_section_number(); if ($singlesection) { return [ - $modinfo->get_section_info(0), $modinfo->get_section_info($singlesection), ]; } diff --git a/course/format/classes/output/local/content/section.php b/course/format/classes/output/local/content/section.php index 29402de5394..63b39372df5 100644 --- a/course/format/classes/output/local/content/section.php +++ b/course/format/classes/output/local/content/section.php @@ -147,7 +147,8 @@ class section implements named_templatable, renderable { 'summary' => $summary->export_for_template($output), 'highlightedlabel' => $format->get_section_highlighted_name(), 'sitehome' => $course->id == SITEID, - 'editing' => $PAGE->user_is_editing() + 'editing' => $PAGE->user_is_editing(), + 'displayonesection' => ($course->id != SITEID && $format->get_section_number() !== 0), ]; $haspartials = []; diff --git a/course/format/classes/output/local/content/section/controlmenu.php b/course/format/classes/output/local/content/section/controlmenu.php index 595b7411084..7c22c048a08 100644 --- a/course/format/classes/output/local/content/section/controlmenu.php +++ b/course/format/classes/output/local/content/section/controlmenu.php @@ -297,9 +297,8 @@ class controlmenu implements named_templatable, renderable { ], $coursecontext) ) { $sectionlink = new moodle_url( - '/course/view.php', - ['id' => $course->id], - "sectionid-{$section->id}-title" + '/course/section.php', + ['id' => $section->id] ); $controls['permalink'] = [ 'url' => $sectionlink, diff --git a/course/format/classes/output/local/content/section/header.php b/course/format/classes/output/local/content/section/header.php index 5bccdbf82ce..0e2cb03eda9 100644 --- a/course/format/classes/output/local/content/section/header.php +++ b/course/format/classes/output/local/content/section/header.php @@ -76,14 +76,28 @@ class header implements named_templatable, renderable { 'id' => $section->id, ]; - $data->title = $output->section_title_without_link($section, $course); + $data->editing = $format->show_editor(); + + if ($course->id == SITEID) { + $data->title = $output->section_title_without_link($section, $course); + $data->sitehome = true; + } else { + if ($format->get_section_number() === 0) { + // All sections are displayed. + if (!$data->editing) { + $data->title = $output->section_title($section, $course); + } else { + $data->title = $output->section_title_without_link($section, $course); + } + } else { + // Only one section is displayed. + $data->displayonesection = true; + $data->title = $output->section_title_without_link($section, $course); + } + } $coursedisplay = $format->get_course_display(); - $data->headerdisplaymultipage = false; - if ($coursedisplay == COURSE_DISPLAY_MULTIPAGE) { - $data->headerdisplaymultipage = true; - $data->title = $output->section_title($section, $course); - } + $data->headerdisplaymultipage = ($coursedisplay == COURSE_DISPLAY_MULTIPAGE); if ($section->section > $format->get_last_section_number()) { // Stealth sections (orphaned) has special title. @@ -94,16 +108,8 @@ class header implements named_templatable, renderable { $data->ishidden = true; } - if ($course->id == SITEID) { - $data->sitehome = true; - } - - $data->editing = $format->show_editor(); - - if (!$format->show_editor() && $coursedisplay == COURSE_DISPLAY_MULTIPAGE && empty($data->issinglesection)) { - if ($section->uservisible) { - $data->url = course_get_url($course, $section->section); - } + if (!$data->editing && $section->uservisible) { + $data->url = course_get_url($course, $section->section, ['navigation' => true]); } $data->name = get_section_name($course, $section); $data->selecttext = $format->get_format_string('selectsection', $data->name); diff --git a/course/format/classes/output/local/content/sectionnavigation.php b/course/format/classes/output/local/content/sectionnavigation.php index ac3770f4dd5..ddf8295cf6f 100644 --- a/course/format/classes/output/local/content/sectionnavigation.php +++ b/course/format/classes/output/local/content/sectionnavigation.php @@ -100,7 +100,7 @@ class sectionnavigation implements named_templatable, renderable { $data->previoushidden = true; } $data->previousname = get_section_name($course, $sections[$back]); - $data->previousurl = course_get_url($course, $back); + $data->previousurl = course_get_url($course, $back, ['navigation' => true]); $data->hasprevious = true; } $back--; @@ -114,7 +114,7 @@ class sectionnavigation implements named_templatable, renderable { $data->nexthidden = true; } $data->nextname = get_section_name($course, $sections[$forward]); - $data->nexturl = course_get_url($course, $forward); + $data->nexturl = course_get_url($course, $forward, ['navigation' => true]); $data->hasnext = true; } $forward++; diff --git a/course/format/classes/output/local/state/section.php b/course/format/classes/output/local/state/section.php index a9e32f95640..74dbae531cd 100644 --- a/course/format/classes/output/local/state/section.php +++ b/course/format/classes/output/local/state/section.php @@ -83,7 +83,7 @@ class section implements renderable { 'rawtitle' => $section->name, 'cmlist' => [], 'visible' => !empty($section->visible), - 'sectionurl' => course_get_url($course, $section->section)->out(), + 'sectionurl' => course_get_url($course, $section->section, ['navigation' => true])->out(), 'current' => $format->is_section_current($section), 'indexcollapsed' => $indexcollapsed, 'contentcollapsed' => $contentcollapsed, diff --git a/course/format/singleactivity/lib.php b/course/format/singleactivity/lib.php index 6a2dd522006..283052c2913 100644 --- a/course/format/singleactivity/lib.php +++ b/course/format/singleactivity/lib.php @@ -45,22 +45,12 @@ class format_singleactivity extends core_courseformat\base { * @param int|stdClass $section Section object from database or just field course_sections.section * if null the course view page is returned * @param array $options options for view URL. At the moment core uses: - * 'navigation' (bool) if true and section has no separate page, the function returns null - * 'sr' (int) used by multipage formats to specify to which section to return + * 'navigation' (bool) ignored by this format + * 'sr' (int) ignored by this format * @return null|moodle_url */ public function get_view_url($section, $options = array()) { - $sectionnum = $section; - if (is_object($sectionnum)) { - $sectionnum = $section->section; - } - if ($sectionnum == 1) { - return new moodle_url('/course/view.php', array('id' => $this->courseid, 'section' => 1)); - } - if (!empty($options['navigation']) && $section !== null) { - return null; - } - return new moodle_url('/course/view.php', array('id' => $this->courseid)); + return new moodle_url('/course/view.php', ['id' => $this->courseid]); } /** diff --git a/course/format/singleactivity/tests/format_singleactivity_test.php b/course/format/singleactivity/tests/format_singleactivity_test.php new file mode 100644 index 00000000000..d2ce3158a23 --- /dev/null +++ b/course/format/singleactivity/tests/format_singleactivity_test.php @@ -0,0 +1,77 @@ +. + +namespace format_singleactivity; + +/** + * Single activity course format related unit tests. + * + * @package format_singleactivity + * @copyright 2023 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \format_singleactivity + */ +class format_singleactivity_test extends \advanced_testcase { + + /** + * Test for get_view_url(). + * + * @covers ::get_view_url + */ + public function test_get_view_url(): void { + global $CFG; + $this->resetAfterTest(); + + // Generate a course with two sections (0 and 1) and two modules. + $generator = $this->getDataGenerator(); + $course1 = $generator->create_course(['format' => 'singleactivity']); + course_create_sections_if_missing($course1, [0, 1]); + + $data = (object)['id' => $course1->id]; + $format = course_get_format($course1); + $format->update_course_format_options($data); + + // In page. + $this->assertNotEmpty($format->get_view_url(null)); + $this->assertNotEmpty($format->get_view_url(0)); + $this->assertNotEmpty($format->get_view_url(1)); + + // Navigation. + $this->assertStringContainsString('course/view.php', $format->get_view_url(0)); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1)); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0, ['navigation' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1, ['navigation' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0, ['sr' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1, ['sr' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0, ['sr' => 0])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1, ['sr' => 0])); + } + + /** + * Test get_required_jsfiles(). + * + * @covers ::get_required_jsfiles + */ + public function test_get_required_jsfiles(): void { + $this->resetAfterTest(); + + $generator = $this->getDataGenerator(); + + $course = $generator->create_course(['format' => 'singleactivity']); + $format = course_get_format($course); + $this->assertEmpty($format->get_required_jsfiles()); + } +} diff --git a/course/format/social/lib.php b/course/format/social/lib.php index 24c4ac3d44b..79c21bb0a98 100644 --- a/course/format/social/lib.php +++ b/course/format/social/lib.php @@ -41,15 +41,12 @@ class format_social extends core_courseformat\base { * @param int|stdClass $section Section object from database or just field course_sections.section * if null the course view page is returned * @param array $options options for view URL. At the moment core uses: - * 'navigation' (bool) if true and section has no separate page, the function returns null - * 'sr' (int) used by multipage formats to specify to which section to return + * 'navigation' (bool) ignored by this format + * 'sr' (int) ignored by this format * @return null|moodle_url */ public function get_view_url($section, $options = array()) { - if (!empty($options['navigation']) && $section !== null) { - return null; - } - return new moodle_url('/course/view.php', array('id' => $this->courseid)); + return new moodle_url('/course/view.php', ['id' => $this->courseid]); } /** diff --git a/course/format/social/tests/format_social_test.php b/course/format/social/tests/format_social_test.php new file mode 100644 index 00000000000..6868cef5cbc --- /dev/null +++ b/course/format/social/tests/format_social_test.php @@ -0,0 +1,77 @@ +. + +namespace format_social; + +/** + * Social course format related unit tests. + * + * @package format_social + * @copyright 2023 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \format_social + */ +class format_social_test extends \advanced_testcase { + + /** + * Test for get_view_url(). + * + * @covers ::get_view_url + */ + public function test_get_view_url(): void { + global $CFG; + $this->resetAfterTest(); + + // Generate a course with two sections (0 and 1) and two modules. + $generator = $this->getDataGenerator(); + $course1 = $generator->create_course(['format' => 'social']); + course_create_sections_if_missing($course1, [0, 1]); + + $data = (object)['id' => $course1->id]; + $format = course_get_format($course1); + $format->update_course_format_options($data); + + // In page. + $this->assertNotEmpty($format->get_view_url(null)); + $this->assertNotEmpty($format->get_view_url(0)); + $this->assertNotEmpty($format->get_view_url(1)); + + // Navigation. + $this->assertStringContainsString('course/view.php', $format->get_view_url(0)); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1)); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0, ['navigation' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1, ['navigation' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0, ['sr' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1, ['sr' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0, ['sr' => 0])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1, ['sr' => 0])); + } + + /** + * Test get_required_jsfiles(). + * + * @covers ::get_required_jsfiles + */ + public function test_get_required_jsfiles(): void { + $this->resetAfterTest(); + + $generator = $this->getDataGenerator(); + + $course = $generator->create_course(['format' => 'social']); + $format = course_get_format($course); + $this->assertEmpty($format->get_required_jsfiles()); + } +} diff --git a/course/format/templates/local/content/section/content.mustache b/course/format/templates/local/content/section/content.mustache index c9ede9023f8..832b1b508fd 100644 --- a/course/format/templates/local/content/section/content.mustache +++ b/course/format/templates/local/content/section/content.mustache @@ -148,7 +148,7 @@ {{/header}}
+ class="content {{^iscoursedisplaymultipage}}{{^sitehome}}{{^displayonesection}}course-content-item-content collapse {{^contentcollapsed}}show{{/contentcollapsed}}{{/displayonesection}}{{/sitehome}}{{/iscoursedisplaymultipage}}">
{{#summary}} {{$ core_courseformat/local/content/section/summary }} diff --git a/course/format/templates/local/content/section/header.mustache b/course/format/templates/local/content/section/header.mustache index 4bae5645de9..d5afc551a38 100644 --- a/course/format/templates/local/content/section/header.mustache +++ b/course/format/templates/local/content/section/header.mustache @@ -47,30 +47,36 @@ {{/sitehome}} {{^sitehome}} - + {{/displayonesection}} + {{^displayonesection}} + + {{/displayonesection}} {{/sitehome}} {{/headerdisplaymultipage}} diff --git a/course/format/tests/base_test.php b/course/format/tests/base_test.php index 6517f8935fa..6852286d097 100644 --- a/course/format/tests/base_test.php +++ b/course/format/tests/base_test.php @@ -20,6 +20,7 @@ * @package core_course * @copyright 2014 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \core_courseformat\base * @coversDefaultClass \core_courseformat\base */ class base_test extends advanced_testcase { @@ -199,14 +200,14 @@ class base_test extends advanced_testcase { } /** - * Test for get_view_url() to ensure that the url is only given for the correct cases + * Test for get_view_url(). + * + * @covers ::get_view_url */ - public function test_get_view_url() { + public function test_get_view_url(): void { global $CFG; $this->resetAfterTest(); - $linkcoursesections = $CFG->linkcoursesections; - // Generate a course with two sections (0 and 1) and two modules. Course format is set to 'testformat'. // This will allow us to test the default implementation of get_view_url. $generator = $this->getDataGenerator(); @@ -218,22 +219,20 @@ class base_test extends advanced_testcase { $format->update_course_format_options($data); // In page. - $CFG->linkcoursesections = 0; - $this->assertNotEmpty($format->get_view_url(null)); - $this->assertNotEmpty($format->get_view_url(0)); - $this->assertNotEmpty($format->get_view_url(1)); - $CFG->linkcoursesections = 1; $this->assertNotEmpty($format->get_view_url(null)); $this->assertNotEmpty($format->get_view_url(0)); $this->assertNotEmpty($format->get_view_url(1)); // Navigation. - $CFG->linkcoursesections = 0; - $this->assertNull($format->get_view_url(1, ['navigation' => 1])); - $this->assertNull($format->get_view_url(0, ['navigation' => 1])); - $CFG->linkcoursesections = 1; - $this->assertNotEmpty($format->get_view_url(1, ['navigation' => 1])); - $this->assertNotEmpty($format->get_view_url(0, ['navigation' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0)); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1)); + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['navigation' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['navigation' => 1])); + // When sr parameter is defined, the section.php page should be returned. + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['sr' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['sr' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['sr' => 0])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['sr' => 0])); // Expand section. // The current course format $format uses the format 'testformat' which does not use sections. @@ -756,6 +755,21 @@ class base_test extends advanced_testcase { ], ]; } + + /** + * Test get_required_jsfiles(). + * + * @covers ::get_required_jsfiles + */ + public function test_get_required_jsfiles(): void { + $this->resetAfterTest(); + + $generator = $this->getDataGenerator(); + + $course = $generator->create_course(['format' => 'testformat']); + $format = course_get_format($course); + $this->assertEmpty($format->get_required_jsfiles()); + } } /** diff --git a/course/format/tests/behat/bulk_show_one_section_actions.feature b/course/format/tests/behat/bulk_show_one_section_actions.feature index 1fe665a21f2..ad9facee5c7 100644 --- a/course/format/tests/behat/bulk_show_one_section_actions.feature +++ b/course/format/tests/behat/bulk_show_one_section_actions.feature @@ -1,5 +1,5 @@ @core @core_courseformat @core_course @show_editor @javascript -Feature: Bulk course section actions one section per page. +Feature: Bulk course section actions one section per page In order to edit the course section in one section per page setting As a teacher I need to be able to edit sections in bulk in both display modes. @@ -33,8 +33,10 @@ Feature: Bulk course section actions one section per page. Scenario: Bulk section edit is only available when multiple sections are displayed Given I click on "Select topic Topic 1" "checkbox" And I should see "1 selected" in the "sticky-footer" "region" + And I click on "Close bulk actions" "button" in the "sticky-footer" "region" # Move to single topic page. - When I click on "Topic 1" "link" in the "region-main" "region" + And I open section "1" edit menu + When I click on "View" "link" in the "Topic 1" "section" And I click on "Bulk actions" "button" Then "Select topic Topic 1" "checkbox" should not exist diff --git a/course/format/tests/behat/course_manageactivities.feature b/course/format/tests/behat/course_manageactivities.feature index d9245a9c844..1833a123e1f 100644 --- a/course/format/tests/behat/course_manageactivities.feature +++ b/course/format/tests/behat/course_manageactivities.feature @@ -1,5 +1,5 @@ @core @core_courseformat @show_editor -Feature: Verify edit utils availability. +Feature: Verify edit utils availability In order to edit the course activities As a student with capability 'moodle/course:manageactivities' I need to be able to use the edit utils. @@ -49,16 +49,17 @@ Feature: Verify edit utils availability. Then I should not see "Edit mode" @javascript - Scenario: Edit tools should be available to students with the capability 'moodle/course:manageactivities', - but should not be allowed to add and edit sections without having 'moodle/course:update' + Scenario: Edit tools should be available to students with manageactivities capability but not allowed to add sections without course:update Given I log in as "author1" When I am on "Course 1" course homepage And I turn editing mode on Then I should see "Add an activity or resource" - And I should not see "Add topic" + But I should not see "Add topic" And I open "Activity sample 1" actions menu And I should see "Edit settings" - And ".section_action_menu" "css_element" should not exist in the "Topic 1" "section" + And I open section "1" edit menu + And I should not see "Edit settings" + And I should see "View" @javascript Scenario: Section adding should be available to students if they also have the capability 'moodle/course:update'. diff --git a/course/format/tests/behat/section_page.feature b/course/format/tests/behat/section_page.feature new file mode 100644 index 00000000000..366bec94d72 --- /dev/null +++ b/course/format/tests/behat/section_page.feature @@ -0,0 +1,82 @@ +@core @core_courseformat +Feature: Single section course page + In order to improve the course page + As a user + I need to be able to see a section in a single page + + Background: + Given the following "course" exists: + | fullname | Course 1 | + | shortname | C1 | + | category | 0 | + | numsections | 3 | + And the following "activities" exist: + | activity | name | course | idnumber | section | + | assign | Activity sample 0.1 | C1 | sample1 | 0 | + | assign | Activity sample 1.1 | C1 | sample1 | 1 | + | assign | Activity sample 1.2 | C1 | sample2 | 1 | + | assign | Activity sample 1.3 | C1 | sample3 | 1 | + | assign | Activity sample 2.1 | C1 | sample3 | 2 | + | assign | Activity sample 2.2 | C1 | sample3 | 2 | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@example.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + Given I am on the "C1" "Course" page logged in as "teacher1" + + @javascript + Scenario: Collapsed sections are always expanded in the single section page + Given I press "Collapse all" + And I should not see "Activity sample 1.1" in the "region-main" "region" + When I click on "Topic 1" "link" in the "region-main" "region" + Then I should see "Activity sample 1.1" + And I should see "Activity sample 1.2" + And I should see "Activity sample 1.3" + And I should not see "Activity sample 2.1" in the "region-main" "region" + And I should not see "Activity sample 2.1" in the "region-main" "region" + + Scenario: General section is not displayed in the single section page + When I click on "Topic 1" "link" in the "region-main" "region" + Then I should not see "General" in the "region-main" "region" + And I should not see "Activity sample 0.1" in the "region-main" "region" + And I should see "Activity sample 1.1" + And I should see "Activity sample 1.2" + And I should see "Activity sample 1.3" + And I should not see "Activity sample 2.1" in the "region-main" "region" + And I should not see "Activity sample 2.1" in the "region-main" "region" + + @javascript + Scenario: The view action for sections displays the single section page + Given I turn editing mode on + And I open section "1" edit menu + When I click on "View" "link" in the "Topic 1" "section" + Then I should not see "General" in the "region-main" "region" + And I should not see "Activity sample 0.1" in the "region-main" "region" + And I should see "Activity sample 1.1" + And I should see "Activity sample 1.2" + And I should see "Activity sample 1.3" + And I should not see "Activity sample 2.1" in the "region-main" "region" + And I should not see "Activity sample 2.1" in the "region-main" "region" + And I am on "Course 1" course homepage + And I open section "2" edit menu + And I click on "View" "link" in the "Topic 2" "section" + And I should not see "General" in the "region-main" "region" + And I should not see "Activity sample 0.1" in the "region-main" "region" + And I should not see "Activity sample 1.1" + And I should not see "Activity sample 1.2" + And I should not see "Activity sample 1.3" + And I should see "Activity sample 2.1" in the "region-main" "region" + And I should see "Activity sample 2.1" in the "region-main" "region" + # The following steps will need to be changed in MDL-80248, when the General section will be displayed in isolation. + But I am on "Course 1" course homepage + And I open section "0" edit menu + And I click on "View" "link" in the "General" "section" + And I should see "General" in the "region-main" "region" + And I should see "Activity sample 0.1" in the "region-main" "region" + And I should see "Activity sample 1.1" + And I should see "Activity sample 1.2" + And I should see "Activity sample 1.3" + And I should see "Activity sample 2.1" in the "region-main" "region" + And I should see "Activity sample 2.1" in the "region-main" "region" diff --git a/course/format/topics/lib.php b/course/format/topics/lib.php index b745164ca0d..c3a6181751c 100644 --- a/course/format/topics/lib.php +++ b/course/format/topics/lib.php @@ -108,45 +108,26 @@ class format_topics extends core_courseformat\base { * @param int|stdClass $section Section object from database or just field course_sections.section * if omitted the course view page is returned * @param array $options options for view URL. At the moment core uses: - * 'navigation' (bool) if true and section has no separate page, the function returns null - * 'sr' (int) used by multipage formats to specify to which section to return + * 'navigation' (bool) if true and section not empty, the function returns section page; otherwise, it returns course page. + * 'sr' (int) used by course formats to specify to which section to return * @return null|moodle_url */ public function get_view_url($section, $options = []) { - global $CFG; $course = $this->get_course(); - $url = new moodle_url('/course/view.php', ['id' => $course->id]); - - $sr = null; if (array_key_exists('sr', $options)) { - $sr = $options['sr']; - } - if (is_object($section)) { + $sectionno = $options['sr']; + } else if (is_object($section)) { $sectionno = $section->section; } else { $sectionno = $section; } - if ($sectionno !== null) { - if ($sr !== null) { - if ($sr) { - $usercoursedisplay = COURSE_DISPLAY_MULTIPAGE; - $sectionno = $sr; - } else { - $usercoursedisplay = COURSE_DISPLAY_SINGLEPAGE; - } - } else { - $usercoursedisplay = $course->coursedisplay ?? COURSE_DISPLAY_SINGLEPAGE; - } - if ($sectionno != 0 && $usercoursedisplay == COURSE_DISPLAY_MULTIPAGE) { - $url->param('section', $sectionno); - } else { - if (empty($CFG->linkcoursesections) && !empty($options['navigation'])) { - return null; - } - $url->set_anchor('section-'.$sectionno); - } + if ((!empty($options['navigation']) || array_key_exists('sr', $options)) && $sectionno !== null) { + // Display section on separate page. + $sectioninfo = $this->get_section($sectionno); + return new moodle_url('/course/section.php', ['id' => $sectioninfo->id]); } - return $url; + + return new moodle_url('/course/view.php', ['id' => $course->id]); } /** @@ -457,6 +438,15 @@ class format_topics extends core_courseformat\base { $formatoptions['indentation'] = get_config('format_topics', 'indentation'); return $formatoptions; } + + /** + * Get the required javascript files for the course format. + * + * @return array The list of javascript files required by the course format. + */ + public function get_required_jsfiles(): array { + return ['/course/format/topics/format.js']; + } } /** diff --git a/course/format/topics/tests/format_topics_test.php b/course/format/topics/tests/format_topics_test.php index eca87a7f7cc..8581f9083ef 100644 --- a/course/format/topics/tests/format_topics_test.php +++ b/course/format/topics/tests/format_topics_test.php @@ -29,6 +29,7 @@ require_once($CFG->dirroot . '/course/lib.php'); * @package format_topics * @copyright 2015 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \format_topics */ class format_topics_test extends \advanced_testcase { @@ -232,16 +233,14 @@ class format_topics_test extends \advanced_testcase { } /** - * Test for get_view_url() to ensure that the url is only given for the correct cases. + * Test for get_view_url(). * - * @return void + * @covers ::get_view_url */ - public function test_get_view_url() { + public function test_get_view_url(): void { global $CFG; $this->resetAfterTest(); - $linkcoursesections = $CFG->linkcoursesections; - // Generate a course with two sections (0 and 1) and two modules. $generator = $this->getDataGenerator(); $course1 = $generator->create_course(['format' => 'topics']); @@ -252,21 +251,34 @@ class format_topics_test extends \advanced_testcase { $format->update_course_format_options($data); // In page. - $CFG->linkcoursesections = 0; - $this->assertNotEmpty($format->get_view_url(null)); - $this->assertNotEmpty($format->get_view_url(0)); - $this->assertNotEmpty($format->get_view_url(1)); - $CFG->linkcoursesections = 1; $this->assertNotEmpty($format->get_view_url(null)); $this->assertNotEmpty($format->get_view_url(0)); $this->assertNotEmpty($format->get_view_url(1)); // Navigation. - $CFG->linkcoursesections = 0; - $this->assertNull($format->get_view_url(1, ['navigation' => 1])); - $this->assertNull($format->get_view_url(0, ['navigation' => 1])); - $CFG->linkcoursesections = 1; - $this->assertNotEmpty($format->get_view_url(1, ['navigation' => 1])); - $this->assertNotEmpty($format->get_view_url(0, ['navigation' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0)); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1)); + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['navigation' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['navigation' => 1])); + // When sr parameter is defined, the section.php page should be returned. + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['sr' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['sr' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['sr' => 0])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['sr' => 0])); + } + + /** + * Test get_required_jsfiles(). + * + * @covers ::get_required_jsfiles + */ + public function test_get_required_jsfiles(): void { + $this->resetAfterTest(); + + $generator = $this->getDataGenerator(); + + $course = $generator->create_course(['format' => 'topics']); + $format = course_get_format($course); + $this->assertNotEmpty($format->get_required_jsfiles()); } } diff --git a/course/format/weeks/lib.php b/course/format/weeks/lib.php index d0eb7436997..89529917993 100644 --- a/course/format/weeks/lib.php +++ b/course/format/weeks/lib.php @@ -118,45 +118,26 @@ class format_weeks extends core_courseformat\base { * @param int|stdClass $section Section object from database or just field course_sections.section * if omitted the course view page is returned * @param array $options options for view URL. At the moment core uses: - * 'navigation' (bool) if true and section has no separate page, the function returns null - * 'sr' (int) used by multipage formats to specify to which section to return + * 'navigation' (bool) if true and section not empty, the function returns section page; otherwise, it returns course page. + * 'sr' (int) used by course formats to specify to which section to return * @return null|moodle_url */ public function get_view_url($section, $options = array()) { - global $CFG; $course = $this->get_course(); - $url = new moodle_url('/course/view.php', array('id' => $course->id)); - - $sr = null; if (array_key_exists('sr', $options)) { - $sr = $options['sr']; - } - if (is_object($section)) { + $sectionno = $options['sr']; + } else if (is_object($section)) { $sectionno = $section->section; } else { $sectionno = $section; } - if ($sectionno !== null) { - if ($sr !== null) { - if ($sr) { - $usercoursedisplay = COURSE_DISPLAY_MULTIPAGE; - $sectionno = $sr; - } else { - $usercoursedisplay = COURSE_DISPLAY_SINGLEPAGE; - } - } else { - $usercoursedisplay = $course->coursedisplay ?? COURSE_DISPLAY_SINGLEPAGE; - } - if ($sectionno != 0 && $usercoursedisplay == COURSE_DISPLAY_MULTIPAGE) { - $url->param('section', $sectionno); - } else { - if (empty($CFG->linkcoursesections) && !empty($options['navigation'])) { - return null; - } - $url->set_anchor('section-'.$sectionno); - } + if ((!empty($options['navigation']) || array_key_exists('sr', $options)) && $sectionno !== null) { + // Display section on separate page. + $sectioninfo = $this->get_section($sectionno); + return new moodle_url('/course/section.php', ['id' => $sectioninfo->id]); } - return $url; + + return new moodle_url('/course/view.php', ['id' => $course->id]); } /** @@ -631,6 +612,15 @@ class format_weeks extends core_courseformat\base { $formatoptions['indentation'] = get_config('format_weeks', 'indentation'); return $formatoptions; } + + /** + * Get the required javascript files for the course format. + * + * @return array The list of javascript files required by the course format. + */ + public function get_required_jsfiles(): array { + return ['/course/format/weeks/format.js']; + } } /** diff --git a/course/format/weeks/tests/format_weeks_test.php b/course/format/weeks/tests/format_weeks_test.php index 82f82ced5a2..9daaacff752 100644 --- a/course/format/weeks/tests/format_weeks_test.php +++ b/course/format/weeks/tests/format_weeks_test.php @@ -29,6 +29,7 @@ require_once($CFG->dirroot . '/course/lib.php'); * @package format_weeks * @copyright 2015 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \format_weeks */ class format_weeks_test extends \advanced_testcase { @@ -229,14 +230,14 @@ class format_weeks_test extends \advanced_testcase { } /** - * Test for get_view_url() to ensure that the url is only given for the correct cases + * Test for get_view_url(). + * + * @covers ::get_view_url */ - public function test_get_view_url() { + public function test_get_view_url(): void { global $CFG; $this->resetAfterTest(); - $linkcoursesections = $CFG->linkcoursesections; - // Generate a course with two sections (0 and 1) and two modules. $generator = $this->getDataGenerator(); $course1 = $generator->create_course(array('format' => 'weeks')); @@ -247,22 +248,34 @@ class format_weeks_test extends \advanced_testcase { $format->update_course_format_options($data); // In page. - $CFG->linkcoursesections = 0; - $this->assertNotEmpty($format->get_view_url(null)); - $this->assertNotEmpty($format->get_view_url(0)); - $this->assertNotEmpty($format->get_view_url(1)); - $CFG->linkcoursesections = 1; $this->assertNotEmpty($format->get_view_url(null)); $this->assertNotEmpty($format->get_view_url(0)); $this->assertNotEmpty($format->get_view_url(1)); // Navigation. - $CFG->linkcoursesections = 0; - $this->assertNull($format->get_view_url(1, ['navigation' => 1])); - $this->assertNull($format->get_view_url(0, ['navigation' => 1])); - $CFG->linkcoursesections = 1; - $this->assertNotEmpty($format->get_view_url(1, ['navigation' => 1])); - $this->assertNotEmpty($format->get_view_url(0, ['navigation' => 1])); + $this->assertStringContainsString('course/view.php', $format->get_view_url(0)); + $this->assertStringContainsString('course/view.php', $format->get_view_url(1)); + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['navigation' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['navigation' => 1])); + // When sr parameter is defined, the section.php page should be returned. + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['sr' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['sr' => 1])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(0, ['sr' => 0])); + $this->assertStringContainsString('course/section.php', $format->get_view_url(1, ['sr' => 0])); } + /** + * Test get_required_jsfiles(). + * + * @covers ::get_required_jsfiles + */ + public function test_get_required_jsfiles(): void { + $this->resetAfterTest(); + + $generator = $this->getDataGenerator(); + + $course = $generator->create_course(['format' => 'weeks']); + $format = course_get_format($course); + $this->assertNotEmpty($format->get_required_jsfiles()); + } } diff --git a/course/section.php b/course/section.php new file mode 100644 index 00000000000..01e1aba09ea --- /dev/null +++ b/course/section.php @@ -0,0 +1,193 @@ +. + +/** + * Display a course section. + * + * @package core_course + * @copyright 2023 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once('../config.php'); +require_once('lib.php'); +require_once($CFG->libdir.'/completionlib.php'); + +redirect_if_major_upgrade_required(); + +$sectionid = required_param('id', PARAM_INT); +// This parameter is used by the classic theme to force editing on. +$edit = optional_param('edit', -1, PARAM_BOOL); + +$section = $DB->get_record('course_sections', ['id' => $sectionid], '*', MUST_EXIST); + +// Defined here to avoid notices on errors. +$PAGE->set_url('/course/section.php', ['id' => $sectionid]); + +if ($section->course == SITEID) { + // The home page is not a real course. + redirect($CFG->wwwroot .'/?redirect=0'); +} + +$course = get_course($section->course); +// Fix course format if it is no longer installed. +$format = course_get_format($course); +$course->format = $format->get_format(); + +// When the course format doesn't support sections, redirect to course page. +if (!course_format_uses_sections($course->format)) { + redirect(new moodle_url('/course/view.php', ['id' => $course->id])); +} + +// Prevent caching of this page to stop confusion when changing page after making AJAX changes. +$PAGE->set_cacheable(false); + +context_helper::preload_course($course->id); +$context = context_course::instance($course->id, MUST_EXIST); + +require_login($course); + +// Must set layout before getting section info. See MDL-47555. +$PAGE->set_pagelayout('course'); +$PAGE->add_body_class('limitedwidth'); + +// Get section details and check it exists. +$modinfo = get_fast_modinfo($course); +$coursesections = $modinfo->get_section_info($section->section, MUST_EXIST); + +// Check user is allowed to see it. +if (!$coursesections->uservisible) { + // Check if coursesection has conditions affecting availability and if + // so, output availability info. + if ($coursesections->visible && $coursesections->availableinfo) { + $sectionname = get_section_name($course, $coursesections); + $message = get_string('notavailablecourse', '', $sectionname); + redirect(course_get_url($course), $message, null, \core\output\notification::NOTIFY_ERROR); + } else { + // Note: We actually already know they don't have this capability + // or uservisible would have been true; this is just to get the + // correct error message shown. + require_capability('moodle/course:viewhiddensections', $context); + } +} + +$PAGE->set_pagetype('course-view-' . $course->format); +$PAGE->set_other_editing_capability('moodle/course:update'); +$PAGE->set_other_editing_capability('moodle/course:manageactivities'); +$PAGE->set_other_editing_capability('moodle/course:activityvisibility'); +$PAGE->set_other_editing_capability('moodle/course:sectionvisibility'); +$PAGE->set_other_editing_capability('moodle/course:movesections'); + +$renderer = $PAGE->get_renderer('format_' . $course->format); + +// This is used by the Classic theme to change the editing mode based on the 'edit' parameter value. +if (!isset($USER->editing)) { + $USER->editing = 0; +} +if ($PAGE->user_allowed_editing()) { + if (($edit == 1) && confirm_sesskey()) { + $USER->editing = 1; + $url = new moodle_url($PAGE->url, ['notifyeditingon' => 1]); + redirect($url); + } else if (($edit == 0) && confirm_sesskey()) { + $USER->editing = 0; + if (!empty($USER->activitycopy) && $USER->activitycopycourse == $course->id) { + $USER->activitycopy = false; + $USER->activitycopycourse = null; + } + redirect($PAGE->url); + } +} + +// This is used by the Classic theme, to display the Turn editing on/off button. +// We are currently keeping the button here from 1.x to help new teachers figure out what to do, even though the link also appears +// in the course admin block. It also means you can back out of a situation where you removed the admin block. +if ($PAGE->user_allowed_editing()) { + $buttons = $OUTPUT->edit_button($PAGE->url); + $PAGE->set_button($buttons); +} + +// Make the title more specific when editing, for accessibility reasons. +$editingtitle = ''; +if ($PAGE->user_is_editing()) { + $editingtitle = 'editing'; +} +$sectionname = get_string('sectionname', "format_$course->format"); +$sectiontitle = get_section_name($course, $section); +$PAGE->set_title( + get_string( + 'coursesectiontitle' . $editingtitle, + 'moodle', + ['course' => $course->fullname, 'sectiontitle' => $sectiontitle, 'sectionname' => $sectionname] + ) +); + +// Add bulk editing control. +$bulkbutton = $renderer->bulk_editing_button($format); +if (!empty($bulkbutton)) { + $PAGE->add_header_action($bulkbutton); +} + +$PAGE->set_heading($course->fullname); +echo $OUTPUT->header(); + +// Show communication room status notification. +if (core_communication\api::is_available() && has_capability('moodle/course:update', $context)) { + $communication = \core_communication\api::load_by_instance( + $context, + 'core_course', + 'coursecommunication', + $course->id + ); + $communication->show_communication_room_status_notification(); +} + +// Display a warning if asynchronous backups are pending for this course. +if ($PAGE->user_is_editing()) { + require_once($CFG->dirroot . '/backup/util/helper/async_helper.class.php'); + if (async_helper::is_async_pending($course->id, 'course', 'backup')) { + echo $OUTPUT->notification(get_string('pendingasyncedit', 'backup'), 'warning'); + } +} + +echo $renderer->container_start('course-content'); + +// Include course AJAX. +include_course_ajax($course, $modinfo->get_used_module_names()); + +$format->set_section_number($section->section); +$outputclass = $format->get_output_classname('content'); +$widget = new $outputclass($format); +echo $renderer->render($widget); + +// Include course format javascript files. +$jsfiles = $format->get_required_jsfiles(); +foreach ($jsfiles as $jsfile) { + $PAGE->requires->js($jsfile); +} + +echo $renderer->container_end(); + +// Trigger course viewed event. +course_view($context, $section->section); + +// Load the view JS module if completion tracking is enabled for this course. +$completion = new completion_info($course); +if ($completion->is_enabled()) { + $PAGE->requires->js_call_amd('core_course/view', 'init'); +} + +echo $OUTPUT->footer(); diff --git a/course/tests/behat/activity_resource_delete.feature b/course/tests/behat/activity_resource_delete.feature index 7ccea2de327..874d0528dba 100644 --- a/course/tests/behat/activity_resource_delete.feature +++ b/course/tests/behat/activity_resource_delete.feature @@ -31,7 +31,7 @@ Feature: Delete activity and resource works correctly And I open "Glossary 1" actions menu And I click on "Delete" "link" in the "Glossary 1" activity And I click on "Delete" "button" in the "Delete activity?" "dialogue" - # Confirm that glossary is successfully deleted + # Confirm that glossary is successfully deleted. And I should not see "Glossary 1" # Reload the page and confirm that both the label and glossary are really deleted And I reload the page diff --git a/course/tests/behat/course_controls.feature b/course/tests/behat/course_controls.feature index 8963446847d..38270953cb6 100644 --- a/course/tests/behat/course_controls.feature +++ b/course/tests/behat/course_controls.feature @@ -16,7 +16,7 @@ Feature: Course activity controls works as expected # * Course controls with paged mode in a section's page @javascript @_cross_browser - Scenario Outline: General activities course controls using topics and weeks formats, and paged mode and not paged mode works as expected + Scenario Outline: Check activities using topics and weeks formats, and paged mode and not paged mode Given the following "users" exist: | username | firstname | lastname | email | | teacher1 | Teacher | 1 | teacher1@example.com | @@ -30,15 +30,14 @@ Feature: Course activity controls works as expected | activity | course | section | name | | forum | C1 | 1 | Test forum name 1 | | forum | C1 | 1 | Test forum name 2 | - And I log in as "teacher1" - And I am on "Course 1" course homepage with editing mode on + And I am on the "Course 1" course page logged in as "teacher1" When I click on "link" in the "region-main" "region" + And I turn editing mode on And I add the "Recent activity" block And I open the action menu in "Recent activity" "block" And I click on "Delete Recent activity block" "link" And I click on "Delete" "button" in the "Delete block?" "dialogue" And "section" exist - And "section" exist And I open "Test forum name 1" actions menu And I click on "Edit settings" "link" in the "Test forum name 1" activity And I should see "Updating Forum" @@ -76,14 +75,16 @@ Feature: Course activity controls works as expected Examples: | courseformat | coursedisplay | targetpage | should_see_other_sections | should_see_other_sections_following_block_sections_links | belowpage | - | topics | 0 | "General" | should | should | "Topic 2" | - | topics | 1 | "Topic 1" | should not | should not | "Topic 2" | + | topics | 0 | "General" | should | should not | "Topic 2" | | topics | 1 | "General" | should | should not | "Topic 2" | - | weeks | 0 | "General" | should | should | "8 January - 14 January" | - | weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" | + | topics | 0 | "Topic 1" | should not | should not | "Topic 2" | + | topics | 1 | "Topic 1" | should not | should not | "Topic 2" | + | weeks | 0 | "General" | should | should not | "8 January - 14 January" | | weeks | 1 | "General" | should | should not | "8 January - 14 January" | + | weeks | 0 | "1 January - 7 January" | should not | should not | "8 January - 14 January" | + | weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" | - Scenario Outline: General activities course controls using topics and weeks formats, and paged mode and not paged mode works as expected without javascript + Scenario Outline: Check, without javascript, activities using topics and weeks formats, and paged mode and not paged mode Given the following "users" exist: | username | firstname | lastname | email | | teacher1 | Teacher | 1 | teacher1@example.com | @@ -97,9 +98,9 @@ Feature: Course activity controls works as expected | activity | name | course | idnumber | section | | forum | Test forum name 1 | C1 | 0001 | 1 | | forum | Test forum name 2 | C1 | 0002 | 1 | - And I log in as "teacher1" - And I am on "Course 1" course homepage with editing mode on + And I am on the "Course 1" course page logged in as "teacher1" When I click on "link" in the "region-main" "region" + And I turn editing mode on And I add the "Recent activity" block And I open the action menu in "Recent activity" "block" And I click on "Delete Recent activity block" "link" @@ -121,28 +122,27 @@ Feature: Course activity controls works as expected And I should see "Test forum name 2" And I should see "Edited test forum name 2" And I hide section "1" - And "section" exist And section "1" should be hidden And all activities in section "1" should be hidden And I show section "1" - And "section" exist And section "1" should be visible And the following config values are set as admin: | unaddableblocks | | theme_boost| And I add the "Section links" block - And "section" exist And I should see "1 2 3 4 5" in the "Section links" "block" And I click on "2" "link" in the "Section links" "block" And I see "Test forum name 2" Examples: | courseformat | coursedisplay | targetpage | should_see_other_sections | should_see_other_sections_following_block_sections_links | belowpage | - | topics | 0 | "General" | should | should | "Topic 2" | - | topics | 1 | "Topic 1" | should not | should not | "Topic 2" | + | topics | 0 | "General" | should | should not | "Topic 2" | | topics | 1 | "General" | should | should not | "Topic 2" | - | weeks | 0 | "General" | should | should | "8 January - 14 January" | - | weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" | + | topics | 0 | "Topic 1" | should not | should not | "Topic 2" | + | topics | 1 | "Topic 1" | should not | should not | "Topic 2" | + | weeks | 0 | "General" | should | should not | "8 January - 14 January" | | weeks | 1 | "General" | should | should not | "8 January - 14 January" | + | weeks | 0 | "1 January - 7 January" | should not | should not | "8 January - 14 January" | + | weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" | @javascript Scenario Outline: Indentation should allow one level only diff --git a/course/tests/behat/move_sections.feature b/course/tests/behat/move_sections.feature index b8c5164788c..feb64c8ab3b 100644 --- a/course/tests/behat/move_sections.feature +++ b/course/tests/behat/move_sections.feature @@ -17,17 +17,19 @@ Feature: Sections can be moved And the following "activities" exist: | activity | name | course | idnumber | section | | forum | Test forum name | C1 | forum1 | 1 | - And I log in as "teacher1" - And I am on "Course 1" course homepage with editing mode on Scenario: Move up and down a section with Javascript disabled in a single page course + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I move down section "1" Then I should see "Test forum name" in the "Topic 2" "section" And I move up section "2" And I should see "Test forum name" in the "Topic 1" "section" Scenario: Move up and down a section with Javascript disabled in the course home of a course using paged mode - Given I navigate to "Settings" in current page administration + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I navigate to "Settings" in current page administration And I set the following fields to these values: | Course layout | Show one section per page | And I press "Save and display" @@ -37,11 +39,13 @@ Feature: Sections can be moved And I should see "Test forum name" in the "Topic 1" "section" Scenario: Sections can not be moved with Javascript disabled in a section page of a course using paged mode - Given I navigate to "Settings" in current page administration + Given I am on the "Course 1" course page logged in as "teacher1" + And I navigate to "Settings" in current page administration And I set the following fields to these values: | Course layout | Show one section per page | And I press "Save and display" - When I follow "Topic 2" + When I click on "Topic 2" "link" in the "region-main" "region" + And I turn editing mode on Then "Topic 1" "section" should not exist And "Topic 3" "section" should not exist And "Move down" "link" should not exist @@ -49,6 +53,8 @@ Feature: Sections can be moved @javascript Scenario: Move section with javascript + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on When I open section "1" edit menu And I click on "Move" "link" in the "Topic 1" "section" And I click on "Topic 3" "link" in the ".modal-body" "css_element" diff --git a/course/tests/behat/paged_course_navigation.feature b/course/tests/behat/paged_course_navigation.feature index ce6523ce746..fefa309bed1 100644 --- a/course/tests/behat/paged_course_navigation.feature +++ b/course/tests/behat/paged_course_navigation.feature @@ -48,7 +48,8 @@ Feature: Course paged mode | chat | C1 | Chat room | When I log in as "admin" And I am on "Course 1" course homepage with editing mode on - And I click on "link" in the "section" + And I open section edit menu + And I click on "View" "link" in the "section" And I should see in the "div.single-section" "css_element" And I should see in the ".single-section div.nextsection" "css_element" And I should not see in the ".single-section" "css_element" @@ -57,9 +58,9 @@ Feature: Course paged mode And I should not see in the ".single-section" "css_element" Examples: - | courseformat | section1 | section2 | prevunexistingsection | - | topics | "Topic 1" | "Topic 2" | "Topic 0" | - | weeks | "1 January - 7 January" | "8 January - 14 January" | "25 December - 31 December" | + | courseformat | section1 | sectionnumber1 | section2 | prevunexistingsection | + | topics | "Topic 1" | "1" | "Topic 2" | "Topic 0" | + | weeks | "1 January - 7 January" | "1" | "8 January - 14 January" | "25 December - 31 December" | Scenario Outline: Weekly and topics course formats with Javascript disabled Given the following "courses" exist: