MDL-69739 tool_usertours: Add tour-level CSS selector
authorKatie Ransom <katie.ransom@open.ac.uk>
Wed, 30 Sep 2020 13:32:58 +0000 (14:32 +0100)
committerAndrew Nicols <andrew@nicols.co.uk>
Thu, 15 Oct 2020 05:35:32 +0000 (13:35 +0800)
16 files changed:
admin/tool/usertours/amd/build/filter_cssselector.min.js [new file with mode: 0644]
admin/tool/usertours/amd/build/filter_cssselector.min.js.map [new file with mode: 0644]
admin/tool/usertours/amd/build/usertours.min.js
admin/tool/usertours/amd/build/usertours.min.js.map
admin/tool/usertours/amd/src/filter_cssselector.js [new file with mode: 0644]
admin/tool/usertours/amd/src/usertours.js
admin/tool/usertours/classes/external/tour.php
admin/tool/usertours/classes/helper.php
admin/tool/usertours/classes/local/clientside_filter/clientside_filter.php [new file with mode: 0644]
admin/tool/usertours/classes/local/clientside_filter/cssselector.php [new file with mode: 0644]
admin/tool/usertours/classes/manager.php
admin/tool/usertours/classes/tour.php
admin/tool/usertours/lang/en/tool_usertours.php
admin/tool/usertours/tests/behat/tour_filter.feature
admin/tool/usertours/tests/manager_test.php
admin/tool/usertours/version.php

diff --git a/admin/tool/usertours/amd/build/filter_cssselector.min.js b/admin/tool/usertours/amd/build/filter_cssselector.min.js
new file mode 100644 (file)
index 0000000..6dbb873
Binary files /dev/null and b/admin/tool/usertours/amd/build/filter_cssselector.min.js differ
diff --git a/admin/tool/usertours/amd/build/filter_cssselector.min.js.map b/admin/tool/usertours/amd/build/filter_cssselector.min.js.map
new file mode 100644 (file)
index 0000000..9ea27ca
Binary files /dev/null and b/admin/tool/usertours/amd/build/filter_cssselector.min.js.map differ
index 6b16a51..8ebe59f 100644 (file)
Binary files a/admin/tool/usertours/amd/build/usertours.min.js and b/admin/tool/usertours/amd/build/usertours.min.js differ
index 9f614ad..c5cca21 100644 (file)
Binary files a/admin/tool/usertours/amd/build/usertours.min.js.map and b/admin/tool/usertours/amd/build/usertours.min.js.map differ
diff --git a/admin/tool/usertours/amd/src/filter_cssselector.js b/admin/tool/usertours/amd/src/filter_cssselector.js
new file mode 100644 (file)
index 0000000..06e825c
--- /dev/null
@@ -0,0 +1,39 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * CSS selector client side filter.
+ *
+ * @module     tool_usertours/filter_cssselector
+ * @class      filter_cssselector
+ * @package    tool_usertours
+ * @copyright 2020 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Checks whether the configured CSS selector exists on this page.
+ *
+ * @param {array} tourConfig  The tour configuration.
+ * @returns {boolean}
+ */
+export const filterMatches = function(tourConfig) {
+    let filterValues = tourConfig.filtervalues.cssselector;
+    if (filterValues[0]) {
+        return !!document.querySelector(filterValues[0]);
+    }
+    // If there is no CSS selector configured, this page matches.
+    return true;
+};
index 4bb1050..a79f7f2 100644 (file)
@@ -14,36 +14,62 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
 
         currentTour: null,
 
-        context: null,
-
         /**
          * Initialise the user tour for the current page.
          *
          * @method  init
-         * @param   {Number}    tourId      The ID of the tour to start.
-         * @param   {Bool}      startTour   Attempt to start the tour now.
-         * @param   {Number}    context     The context of the current page.
+         * @param   {Array}    tourDetails      The matching tours for this page.
+         * @param   {Array}    filters          The names of all client side filters.
          */
-        init: function(tourId, startTour, context) {
-            // Only one tour per page is allowed.
-            usertours.tourId = tourId;
+        init: function(tourDetails, filters) {
+            let requirements = [];
+            for (var req = 0; req < filters.length; req++) {
+                requirements[req] = 'tool_usertours/filter_' + filters[req];
+            }
+            require(requirements, function() {
+                // Run the client side filters to find the first matching tour.
+                let matchingTour = null;
+                for (let key in tourDetails) {
+                    let tour = tourDetails[key];
+                    for (let i = 0; i < filters.length; i++) {
+                        let filter = arguments[i];
+                        if (filter.filterMatches(tour)) {
+                            matchingTour = tour;
+                        } else {
+                            // If any filter doesn't match, move on to the next tour.
+                            matchingTour = null;
+                            break;
+                        }
+                    }
+                    // If all filters matched then use this tour.
+                    if (matchingTour) {
+                        break;
+                    }
+                }
 
-            usertours.context = context;
+                if (matchingTour === null) {
+                    return;
+                }
 
-            if (typeof startTour === 'undefined') {
-                startTour = true;
-            }
+                // Only one tour per page is allowed.
+                usertours.tourId = matchingTour.tourId;
 
-            if (startTour) {
-                // Fetch the tour configuration.
-                usertours.fetchTour(tourId);
-            }
+                let startTour = matchingTour.startTour;
+                if (typeof startTour === 'undefined') {
+                    startTour = true;
+                }
+
+                if (startTour) {
+                    // Fetch the tour configuration.
+                    usertours.fetchTour(usertours.tourId);
+                }
 
-            usertours.addResetLink();
-            // Watch for the reset link.
-            $('body').on('click', '[data-action="tool_usertours/resetpagetour"]', function(e) {
-                e.preventDefault();
-                usertours.resetTourState(usertours.tourId);
+                usertours.addResetLink();
+                // Watch for the reset link.
+                $('body').on('click', '[data-action="tool_usertours/resetpagetour"]', function(e) {
+                    e.preventDefault();
+                    usertours.resetTourState(usertours.tourId);
+                });
             });
         },
 
@@ -61,7 +87,7 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
                         methodname: 'tool_usertours_fetch_and_start_tour',
                         args: {
                             tourid:     tourId,
-                            context:    usertours.context,
+                            context:    M.cfg.contextid,
                             pageurl:    window.location.href,
                         }
                     }
@@ -186,7 +212,7 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
                         methodname: 'tool_usertours_step_shown',
                         args: {
                             tourid:     usertours.tourId,
-                            context:    usertours.context,
+                            context:    M.cfg.contextid,
                             pageurl:    window.location.href,
                             stepid:     stepConfig.stepid,
                             stepindex:  this.getCurrentStepNumber(),
@@ -209,7 +235,7 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
                         methodname: 'tool_usertours_complete_tour',
                         args: {
                             tourid:     usertours.tourId,
-                            context:    usertours.context,
+                            context:    M.cfg.contextid,
                             pageurl:    window.location.href,
                             stepid:     stepConfig.stepid,
                             stepindex:  this.getCurrentStepNumber(),
@@ -232,7 +258,7 @@ function(ajax, BootstrapTour, $, templates, str, log, notification) {
                         methodname: 'tool_usertours_reset_tour',
                         args: {
                             tourid:     tourId,
-                            context:    usertours.context,
+                            context:    M.cfg.contextid,
                             pageurl:    window.location.href,
                         }
                     }
index c16c5a0..7ec9cb8 100644 (file)
@@ -131,8 +131,9 @@ class tour extends external_api {
 
         $result = [];
 
-        if ($tourinstance = \tool_usertours\manager::get_matching_tours(new \moodle_url($params['pageurl']))) {
-            if ($tour->get_id() === $tourinstance->get_id()) {
+        $matchingtours = \tool_usertours\manager::get_matching_tours(new \moodle_url($params['pageurl']));
+        foreach ($matchingtours as $match) {
+            if ($tour->get_id() === $match->get_id()) {
                 $result['startTour'] = $tour->get_id();
 
                 \tool_usertours\event\tour_reset::create([
@@ -142,7 +143,7 @@ class tour extends external_api {
                         'pageurl'   => $params['pageurl'],
                     ],
                 ])->trigger();
-
+                break;
             }
         }
 
index df04ed9..f1f8e4b 100644 (file)
@@ -24,6 +24,8 @@
 
 namespace tool_usertours;
 
+use tool_usertours\local\clientside_filter\clientside_filter;
+
 defined('MOODLE_INTERNAL') || die();
 
 /**
@@ -523,33 +525,57 @@ class helper {
         }
         self::$bootstrapped = true;
 
-        if ($tour = manager::get_current_tour()) {
+        $tours = manager::get_current_tours();
+
+        if ($tours) {
+            $filters = static::get_all_clientside_filters();
+
+            $tourdetails = array_map(function($tour) use ($filters) {
+                return [
+                        'tourId' => $tour->get_id(),
+                        'startTour' => $tour->should_show_for_user(),
+                        'filtervalues' => $tour->get_client_filter_values($filters),
+                ];
+            }, $tours);
+
+            $filternames = [];
+            foreach ($filters as $filter) {
+                    $filternames[] = $filter::get_filter_name();
+            }
+
             $PAGE->requires->js_call_amd('tool_usertours/usertours', 'init', [
-                    $tour->get_id(),
-                    $tour->should_show_for_user(),
-                    $PAGE->context->id,
-                ]);
+                    $tourdetails,
+                    $filternames,
+            ]);
         }
     }
 
     /**
-     * Add the reset link to the current page.
+     * Get a list of all possible filters.
+     *
+     * @return  array
      */
-    public static function bootstrap_reset() {
-        if (manager::get_current_tour()) {
-            echo \html_writer::link('', get_string('resettouronpage', 'tool_usertours'), [
-                    'data-action'   => 'tool_usertours/resetpagetour',
-                ]);
-        }
+    public static function get_all_filters() {
+        $filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\filter');
+        $filters = array_keys($filters);
+
+        $filters = array_filter($filters, function($filterclass) {
+            $rc = new \ReflectionClass($filterclass);
+            return $rc->isInstantiable();
+        });
+
+        $filters = array_merge($filters, static::get_all_clientside_filters());
+
+        return $filters;
     }
 
     /**
-     * Get a list of all possible filters.
+     * Get a list of all clientside filters.
      *
      * @return  array
      */
-    public static function get_all_filters() {
-        $filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\filter');
+    public static function get_all_clientside_filters() {
+        $filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\clientside_filter');
         $filters = array_keys($filters);
 
         $filters = array_filter($filters, function($filterclass) {
diff --git a/admin/tool/usertours/classes/local/clientside_filter/clientside_filter.php b/admin/tool/usertours/classes/local/clientside_filter/clientside_filter.php
new file mode 100644 (file)
index 0000000..6fa403a
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Clientside filter base.
+ *
+ * @package    tool_usertours
+ * @copyright  2020 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_usertours\local\clientside_filter;
+
+defined('MOODLE_INTERNAL') || die();
+
+use stdClass;
+use tool_usertours\local\filter\base;
+use tool_usertours\tour;
+
+/**
+ * Clientside filter base.
+ *
+ * @copyright  2020 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class clientside_filter extends base {
+    /**
+     * Returns the filter values needed for client side filtering.
+     *
+     * @param   tour            $tour       The tour to find the filter values for
+     * @return  stdClass
+     */
+    public static function get_client_side_values(tour $tour): stdClass {
+        $data = (object) [];
+
+        if (is_a(static::class, clientside_filter::class, true)) {
+            $data->filterdata = $tour->get_filter_values(static::get_filter_name());
+        }
+
+        return $data;
+    }
+}
\ No newline at end of file
diff --git a/admin/tool/usertours/classes/local/clientside_filter/cssselector.php b/admin/tool/usertours/classes/local/clientside_filter/cssselector.php
new file mode 100644 (file)
index 0000000..e6d6c2d
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Selector filter.
+ *
+ * @package    tool_usertours
+ * @copyright  2020 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace tool_usertours\local\clientside_filter;
+
+use stdClass;
+use tool_usertours\tour;
+
+/**
+ * Course filter.
+ *
+ * @copyright  2020 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class cssselector extends clientside_filter {
+    /**
+     * The name of the filter.
+     *
+     * @return  string
+     */
+    public static function get_filter_name() {
+        return 'cssselector';
+    }
+
+    /**
+     * Overrides the base add form element with a selector text box.
+     *
+     * @param \MoodleQuickForm $mform
+     */
+    public static function add_filter_to_form(\MoodleQuickForm &$mform) {
+        $filtername = self::get_filter_name();
+        $key = "filter_{$filtername}";
+
+        $mform->addElement('text', $key, get_string($key, 'tool_usertours'));
+        $mform->setType($key, PARAM_RAW);
+        $mform->addHelpButton($key, $key, 'tool_usertours');
+    }
+
+    /**
+     * Prepare the filter values for the form.
+     *
+     * @param   tour            $tour       The tour to prepare values from
+     * @param   stdClass        $data       The data value
+     * @return  stdClass
+     */
+    public static function prepare_filter_values_for_form(tour $tour, \stdClass $data) {
+        $filtername = static::get_filter_name();
+
+        $key = "filter_{$filtername}";
+        $values = $tour->get_filter_values($filtername);
+        if (empty($values)) {
+            $values = [""];
+        }
+        $data->$key = $values[0];
+
+        return $data;
+    }
+
+    /**
+     * Save the filter values from the form to the tour.
+     *
+     * @param   tour            $tour       The tour to save values to
+     * @param   stdClass        $data       The data submitted in the form
+     */
+    public static function save_filter_values_from_form(tour $tour, \stdClass $data) {
+        $filtername = static::get_filter_name();
+
+        $key = "filter_{$filtername}";
+
+        $newvalue = [$data->$key];
+        if (empty($data->$key)) {
+            $newvalue = [];
+        }
+
+        $tour->set_filter_values($filtername, $newvalue);
+    }
+
+    /**
+     * Returns the filter values needed for client side filtering.
+     *
+     * @param   tour            $tour       The tour to find the filter values for
+     * @return  stdClass
+     */
+    public static function get_client_side_values(tour $tour): stdClass {
+        $filtername = static::get_filter_name();
+        $filtervalues = $tour->get_filter_values($filtername);
+
+        // Filter values might not exist for tours that were created before this filter existed.
+        if (!$filtervalues) {
+            return new stdClass;
+        }
+
+        return (object) $filtervalues;
+    }
+}
index 6741568..437b416 100644 (file)
@@ -608,42 +608,44 @@ class manager {
     }
 
     /**
-     * Get the first tour matching the current page URL.
+     * Get all tours for the current page URL.
      *
-     * @param   bool        $reset      Forcibly update the current tour
-     * @return  tour
+     * @param   bool        $reset      Forcibly update the current tours
+     * @return  array
      */
-    public static function get_current_tour($reset = false) {
+    public static function get_current_tours($reset = false): array {
         global $PAGE;
 
-        static $tour = false;
+        static $tours = false;
 
-        if ($tour === false || $reset) {
-            $tour = self::get_matching_tours($PAGE->url);
+        if ($tours === false || $reset) {
+            $tours = self::get_matching_tours($PAGE->url);
         }
 
-        return $tour;
+        return $tours;
     }
 
     /**
-     * Get the first tour matching the specified URL.
+     * Get all tours matching the specified URL.
      *
      * @param   moodle_url  $pageurl        The URL to match.
-     * @return  tour
+     * @return  array
      */
-    public static function get_matching_tours(\moodle_url $pageurl) {
+    public static function get_matching_tours(\moodle_url $pageurl): array {
         global $PAGE;
 
         $tours = cache::get_matching_tourdata($pageurl);
 
+        $matches = [];
+        $filters = helper::get_all_filters();
         foreach ($tours as $record) {
             $tour = tour::load_from_record($record);
-            if ($tour->is_enabled() && $tour->matches_all_filters($PAGE->context)) {
-                return $tour;
+            if ($tour->is_enabled() && $tour->matches_all_filters($PAGE->context, $filters)) {
+                $matches[] = $tour;
             }
         }
 
-        return null;
+        return $matches;
     }
 
     /**
index 0765ee3..08e8279 100644 (file)
@@ -24,6 +24,8 @@
 
 namespace tool_usertours;
 
+use tool_usertours\local\clientside_filter\clientside_filter;
+
 defined('MOODLE_INTERNAL') || die();
 
 /**
@@ -769,11 +771,14 @@ class tour {
     /**
      * Check whether this tour matches all filters.
      *
-     * @param   context     $context    The context to check
+     * @param   \context     $context    The context to check.
+     * @param   array|null   $filters    Optional array of filters.
      * @return  bool
      */
-    public function matches_all_filters(\context $context) {
-        $filters = helper::get_all_filters();
+    public function matches_all_filters(\context $context, array $filters = null): bool {
+        if (!$filters) {
+            $filters = helper::get_all_filters();
+        }
 
         // All filters must match.
         // If any one filter fails to match, we return false.
@@ -785,4 +790,20 @@ class tour {
 
         return true;
     }
+
+    /**
+     * Gets all filter values for use in client side filters.
+     *
+     * @param   array     $filters    Array of clientside filters.
+     * @return  array
+     */
+    public function get_client_filter_values(array $filters): array {
+        $results = [];
+
+        foreach ($filters as $filter) {
+            $results[$filter::get_filter_name()] = $filter::get_client_side_values($this);
+        }
+
+        return $results;
+    }
 }
index 3d86e56..f142b46 100644 (file)
@@ -63,6 +63,8 @@ $string['filter_course'] = 'Courses';
 $string['filter_course_help'] = 'Show the tour on a page that is associated with the selected course.';
 $string['filter_courseformat'] = 'Course format';
 $string['filter_courseformat_help'] = 'Show the tour on a page that is associated with a course using the selected course format.';
+$string['filter_cssselector'] = 'CSS selector';
+$string['filter_cssselector_help'] = 'Only show the tour when the specified CSS selector is found on the page.';
 $string['filter_header'] = 'Tour filters';
 $string['filter_help'] = 'Select the conditions under which the tour will be shown. All of the filters must match for a tour to be shown to a user.';
 $string['filter_date_account_creation'] = 'User account creation date within';
index ac3a164..0fe72f4 100644 (file)
@@ -142,3 +142,88 @@ Feature: Apply tour filters to a tour
     When I am on "Course 2" course homepage
     And I wait until the page is ready
     Then I should not see "Welcome to your course tour."
+
+  @javascript
+  Scenario: Add tours with CSS selectors
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | student1 | Student   | 1        | student1@example.com |
+    Given the following "courses" exist:
+      | fullname | shortname | format | enablecompletion |
+      | Course 1 | C1        | topics | 1                |
+      | Course 2 | C2        | topics | 1                |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Wiki" to section "1" and I fill the form with:
+      | Wiki name       | Test wiki name        |
+      | Description     | Test wiki description |
+      | First page name | First page            |
+      | Wiki mode       | Collaborative wiki    |
+    And I am on "Course 2" course homepage
+    And I add a "Forum" to section "1" and I fill the form with:
+      | Forum name  | Test forum name                |
+      | Forum type  | Standard forum for general use |
+      | Description | Test forum description         |
+    And I add a new user tour with:
+      | Name               | Wiki tour                |
+      | Description        | A tour with both matches |
+      | Apply to URL match | /course/view.php%        |
+      | Tour is enabled    | 1                        |
+      | CSS selector       | .modtype_wiki            |
+    And I add steps to the "Wiki tour" tour:
+      | targettype                | Title   | Content                  |
+      | Display in middle of page | Welcome | Welcome to the Wiki tour |
+    And I add a new user tour with:
+      | Name               | Forum tour               |
+      | Description        | A tour with both matches |
+      | Apply to URL match | /course/view.php%        |
+      | Tour is enabled    | 1                        |
+      | CSS selector       | .modtype_forum           |
+    And I add steps to the "Forum tour" tour:
+      | targettype                | Title   | Content                   |
+      | Display in middle of page | Welcome | Welcome to the Forum tour |
+    And I am on "Course 1" course homepage
+    Then I should see "Welcome to the Wiki tour"
+    And I am on "Course 2" course homepage
+    Then I should see "Welcome to the Forum tour"
+
+  @javascript
+  Scenario: Check filtering respects the sort order
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | student1 | Student   | 1        | student1@example.com |
+    And I log in as "admin"
+    And I add a new user tour with:
+      | Name               | First tour     |
+      | Description        | The first tour |
+      | Apply to URL match | /my/%          |
+      | Tour is enabled    | 1              |
+      | CSS selector       | #page-my-index |
+    And I add steps to the "First tour" tour:
+      | targettype                | Title   | Content                   |
+      | Display in middle of page | Welcome | Welcome to the First tour |
+    And I add a new user tour with:
+      | Name               | Second tour     |
+      | Description        | The second tour |
+      | Apply to URL match | /my/%           |
+      | Tour is enabled    | 0               |
+      | CSS selector       | #page-my-index  |
+    And I add steps to the "Second tour" tour:
+      | targettype                | Title   | Content                    |
+      | Display in middle of page | Welcome | Welcome to the Second tour |
+    And I add a new user tour with:
+      | Name               | Third tour     |
+      | Description        | The third tour |
+      | Apply to URL match | /my/%           |
+      | Tour is enabled    | 1               |
+      | CSS selector       | #page-my-index  |
+    And I add steps to the "Third tour" tour:
+      | targettype                | Title   | Content                   |
+      | Display in middle of page | Welcome | Welcome to the Third tour |
+    And I am on homepage
+    Then I should see "Welcome to the First tour"
+    And I open the User tour settings page
+    And I click on "Move tour down" "link" in the "The first tour" "table_row"
+    And I click on "Move tour down" "link" in the "The first tour" "table_row"
+    And I am on homepage
+    Then I should see "Welcome to the Third tour"
index 913c3e1..d5e4893 100644 (file)
@@ -222,6 +222,13 @@ class tool_usertours_manager_testcase extends advanced_testcase {
                     'description'   => '',
                     'configdata'    => '',
                 ],
+            [
+                    'pathmatch'     => '/my/%',
+                    'enabled'       => true,
+                    'name'          => 'My tour enabled 2',
+                    'description'   => '',
+                    'configdata'    => '',
+                ],
             [
                     'pathmatch'     => '/my/%',
                     'enabled'       => false,
@@ -277,32 +284,32 @@ class tool_usertours_manager_testcase extends advanced_testcase {
                 'No matches found' => [
                         $alltours,
                         $CFG->wwwroot . '/some/invalid/value',
-                        null,
+                        [],
                     ],
                 'Never return a disabled tour' => [
                         $alltours,
                         $CFG->wwwroot . '/my/index.php',
-                        'My tour enabled',
+                        ['My tour enabled', 'My tour enabled 2'],
                     ],
                 'My not course' => [
                         $alltours,
                         $CFG->wwwroot . '/my/index.php',
-                        'My tour enabled',
+                        ['My tour enabled', 'My tour enabled 2'],
                     ],
                 'My with params' => [
                         $alltours,
                         $CFG->wwwroot . '/my/index.php?id=42',
-                        'My tour enabled',
+                        ['My tour enabled', 'My tour enabled 2'],
                     ],
                 'Course with params' => [
                         $alltours,
                         $CFG->wwwroot . '/course/?id=42',
-                        'course tour enabled',
+                        ['course tour enabled'],
                     ],
                 'Course with params and trailing content' => [
                         $alltours,
                         $CFG->wwwroot . '/course/?id=42&foo=bar',
-                        'course tour with additional params enabled',
+                        ['course tour with additional params enabled', 'course tour enabled'],
                     ],
             ];
     }
@@ -311,11 +318,11 @@ class tool_usertours_manager_testcase extends advanced_testcase {
      * Tests for the get_matching_tours function.
      *
      * @dataProvider get_matching_tours_provider
-     * @param   array   $alltours   The list of tours to insert
-     * @param   string  $url        The URL to test
-     * @param   string  $expected   The name of the expected matching tour
+     * @param   array   $alltours   The list of tours to insert.
+     * @param   string  $url        The URL to test.
+     * @param   array   $expected   List of names of the expected matching tours.
      */
-    public function test_get_matching_tours($alltours, $url, $expected) {
+    public function test_get_matching_tours(array $alltours, string $url, array $expected) {
         $this->resetAfterTest();
 
         foreach ($alltours as $tourconfig) {
@@ -323,12 +330,10 @@ class tool_usertours_manager_testcase extends advanced_testcase {
             $this->helper_create_step((object) ['tourid' => $tour->get_id()]);
         }
 
-        $match = \tool_usertours\manager::get_matching_tours(new moodle_url($url));
-        if ($expected === null) {
-            $this->assertNull($match);
-        } else {
-            $this->assertNotNull($match);
-            $this->assertEquals($expected, $match->get_name());
+        $matches = \tool_usertours\manager::get_matching_tours(new moodle_url($url));
+        $this->assertEquals(count($expected), count($matches));
+        for ($i = 0; $i < count($matches); $i++) {
+            $this->assertEquals($expected[$i], $matches[$i]->get_name());
         }
     }
 }
index e34cc47..d621cef 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2020082700;            // The current module version (Date: YYYYMMDDXX).
+$plugin->version   = 2020082701;            // The current module version (Date: YYYYMMDDXX).
 $plugin->requires  = 2020060900;            // Requires this Moodle version.
 $plugin->component = 'tool_usertours';      // Full name of the plugin (used for diagnostics).