Merge branch 'MDL-67657-master' of git://github.com/andrewnicols/moodle
authorAdrian Greeve <abgreeve@gmail.com>
Tue, 21 Jul 2020 06:47:14 +0000 (14:47 +0800)
committerAdrian Greeve <abgreeve@gmail.com>
Tue, 21 Jul 2020 06:47:14 +0000 (14:47 +0800)
lib/behat/behat_base.php
lib/behat/form_field/behat_form_editor.php
lib/behat/form_field/behat_form_passwordunmask.php
lib/tests/behat/behat_app.php
lib/tests/behat/behat_general.php
lib/tests/behat/behat_navigation.php
mod/assign/feedback/editpdf/tests/behat/behat_assignfeedback_editpdf.php
question/type/ddmarker/tests/behat/behat_qtype_ddmarker.php
search/tests/behat/behat_search.php

index c97f492..b36272b 100644 (file)
@@ -482,12 +482,45 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
     }
 
     /**
-     * Returns whether the scenario is running in a browser that can run Javascript or not.
+     * Whether Javascript is available in the current Session.
      *
      * @return boolean
      */
     protected function running_javascript() {
-        return get_class($this->getSession()->getDriver()) !== 'Behat\Mink\Driver\GoutteDriver';
+        return self::running_javascript_in_session($this->getSession());
+    }
+
+    /**
+     * Require that javascript be available in the current Session.
+     *
+     * @throws DriverException
+     */
+    protected function require_javascript() {
+        return self::require_javascript_in_session($this->getSession());
+    }
+
+    /**
+     * Whether Javascript is available in the specified Session.
+     *
+     * @param Session $session
+     * @return boolean
+     */
+    protected static function running_javascript_in_session(Session $session): bool {
+        return get_class($session->getDriver()) !== 'Behat\Mink\Driver\GoutteDriver';
+    }
+
+    /**
+     * Require that javascript be available for the specified Session.
+     *
+     * @param Session $session
+     * @throws DriverException
+     */
+    protected static function require_javascript_in_session(Session $session): void {
+        if (self::running_javascript_in_session($session)) {
+            return;
+        }
+
+        throw new DriverException('Javascript is required');
     }
 
     /**
@@ -502,7 +535,7 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
         }
 
         // Check on page to see if it's an app page. Safest way is to look for added JavaScript.
-        return $this->getSession()->evaluateScript('typeof window.behat') === 'object';
+        return $this->evaluate_script('return typeof window.behat') === 'object';
     }
 
     /**
@@ -738,14 +771,18 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
             // The window inner height will be as specified, which means the available viewport will
             // actually be smaller if there is a horizontal scrollbar. We assume that horizontal
             // scrollbars are rare so this doesn't matter.
-            $offset = $this->getSession()->getDriver()->evaluateScript(
-                    'return (function() { var before = document.body.style.overflowY;' .
-                    'document.body.style.overflowY = "scroll";' .
-                    'var result = {};' .
-                    'result.x = window.outerWidth - document.body.offsetWidth;' .
-                    'result.y = window.outerHeight - window.innerHeight;' .
-                    'document.body.style.overflowY = before;' .
-                    'return result; })();');
+            $js = <<<EOF
+return (function() {
+    var before = document.body.style.overflowY;
+    document.body.style.overflowY = "scroll";
+    var result = {};
+    result.x = window.outerWidth - document.body.offsetWidth;
+    result.y = window.outerHeight - window.innerHeight;
+    document.body.style.overflowY = before;
+    return result;
+})();
+EOF;
+            $offset = $this->evaluate_script($js);
             $width += $offset['x'];
             $height += $offset['y'];
         }
@@ -794,8 +831,8 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
                         } else {
                             return "incomplete"
                         }
-                    }());'));
-                $pending = $session->evaluateScript($jscode);
+                    })()'));
+                $pending = self::evaluate_script_in_session($session, $jscode);
             } catch (NoSuchWindow $nsw) {
                 // We catch an exception here, in case we just closed the window we were interacting with.
                 // No javascript is running if there is no window right?
@@ -1206,4 +1243,70 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
     public static function get_named_replacements(): array {
         return [];
     }
+
+    /**
+     * Evaluate the supplied script in the current session, returning the result.
+     *
+     * @param string $script
+     * @return mixed
+     */
+    public function evaluate_script(string $script) {
+        return self::evaluate_script_in_session($this->getSession(), $script);
+    }
+
+    /**
+     * Evaluate the supplied script in the specified session, returning the result.
+     *
+     * @param Session $session
+     * @param string $script
+     * @return mixed
+     */
+    public static function evaluate_script_in_session(Session $session, string $script) {
+        self::require_javascript_in_session($session);
+
+        return $session->evaluateScript($script);
+    }
+
+    /**
+     * Execute the supplied script in the current session.
+     *
+     * No result will be returned.
+     *
+     * @param string $script
+     */
+    public function execute_script(string $script): void {
+        self::execute_script_in_session($this->getSession(), $script);
+    }
+
+    /**
+     * Excecute the supplied script in the specified session.
+     *
+     * No result will be returned.
+     *
+     * @param Session $session
+     * @param string $script
+     */
+    public static function execute_script_in_session(Session $session, string $script): void {
+        self::require_javascript_in_session($session);
+
+        $session->executeScript($script);
+    }
+
+    /**
+     * Get the session key for the current session via Javascript.
+     *
+     * @return string
+     */
+    public function get_sesskey(): string {
+        $script = <<<EOF
+return (function() {
+if (M && M.cfg && M.cfg.sesskey) {
+    return M.cfg.sesskey;
+}
+return '';
+})()
+EOF;
+
+        return $this->evaluate_script($script);
+    }
 }
index 8f3ff72..3d5df09 100644 (file)
@@ -52,14 +52,16 @@ class behat_form_editor extends behat_form_textarea {
         if ($this->running_javascript()) {
             $value = addslashes($value);
             $js = '
-var editor = Y.one(document.getElementById("'.$editorid.'editable"));
-if (editor) {
-    editor.setHTML("' . $value . '");
-}
-editor = Y.one(document.getElementById("'.$editorid.'"));
-editor.set("value", "' . $value . '");
+(function() {
+    var editor = Y.one(document.getElementById("'.$editorid.'editable"));
+    if (editor) {
+        editor.setHTML("' . $value . '");
+    }
+    editor = Y.one(document.getElementById("'.$editorid.'"));
+    editor.set("value", "' . $value . '");
+})();
 ';
-            $this->session->executeScript($js);
+            behat_base::execute_script_in_session($this->session, $js);
         } else {
             parent::set_value($value);
         }
@@ -88,7 +90,7 @@ editor.set("value", "' . $value . '");
     r.selectNodeContents(e);
     s.setSingleRange(r);
 }()); ';
-        $this->session->executeScript($js);
+        behat_base::execute_script_in_session($this->session, $js);
     }
 
     /**
index 43cf372..cfc48c2 100644 (file)
@@ -51,12 +51,14 @@ class behat_form_passwordunmask extends behat_form_text {
         if ($this->running_javascript()) {
             $id = $this->field->getAttribute('id');
             $js = <<<JS
-require(["jquery"], function($) {
-    var wrapper = $(document.getElementById("{$id}")).closest('[data-passwordunmask="wrapper"]');
-        wrapper.find('[data-passwordunmask="edit"]').trigger("click");
-});
+(function() {
+    require(["jquery"], function($) {
+        var wrapper = $(document.getElementById("{$id}")).closest('[data-passwordunmask="wrapper"]');
+            wrapper.find('[data-passwordunmask="edit"]').trigger("click");
+    });
+})();
 JS;
-            $this->session->executeScript($js);
+            behat_base::execute_script_in_session($this->session, $js);
         }
 
         $this->field->setValue($value);
index af82844..e474ffc 100644 (file)
@@ -297,8 +297,7 @@ class behat_app extends behat_base {
                 }, false, 60);
 
         // Run the scripts to install Moodle 'pending' checks.
-        $this->getSession()->executeScript(
-                file_get_contents(__DIR__ . '/app_behat_runtime.js'));
+        $this->execute_script(file_get_contents(__DIR__ . '/app_behat_runtime.js'));
 
         // Wait until the site login field appears OR the main page.
         $situation = $this->spin(
@@ -373,8 +372,7 @@ class behat_app extends behat_base {
      */
     public function i_press_the_standard_button_in_the_app(string $button) {
         $this->spin(function($context, $args) use ($button) {
-            $result = $this->getSession()->evaluateScript('return window.behat.pressStandard("' .
-                    $button . '");');
+            $result = $this->evaluate_script("return window.behat.pressStandard('{$button}');");
             if ($result !== 'OK') {
                 throw new DriverException('Error pressing standard button - ' . $result);
             }
@@ -391,7 +389,7 @@ class behat_app extends behat_base {
      */
     public function i_close_the_popup_in_the_app() {
         $this->spin(function($context, $args)  {
-            $result = $this->getSession()->evaluateScript('return window.behat.closePopup();');
+            $result = $this->evaluate_script("return window.behat.closePopup();");
             if ($result !== 'OK') {
                 throw new DriverException('Error closing popup - ' . $result);
             }
@@ -449,7 +447,7 @@ class behat_app extends behat_base {
             } else {
                 $nearbit = '';
             }
-            $result = $context->getSession()->evaluateScript('return window.behat.press("' .
+            $result = $this->evaluate_script('return window.behat.press("' .
                     addslashes_js($text) . '"' . $nearbit .');');
             if ($result !== 'OK') {
                 throw new DriverException('Error pressing item - ' . $result);
@@ -472,7 +470,7 @@ class behat_app extends behat_base {
      */
     public function i_set_the_field_in_the_app(string $field, string $value) {
         $this->spin(function($context, $args) use ($field, $value) {
-            $result = $this->getSession()->evaluateScript('return window.behat.setField("' .
+            $result = $this->evaluate_script('return window.behat.setField("' .
                     addslashes_js($field) . '", "' . addslashes_js($value) . '");');
             if ($result !== 'OK') {
                 throw new DriverException('Error setting field - ' . $result);
@@ -494,7 +492,7 @@ class behat_app extends behat_base {
      */
     public function the_header_should_be_in_the_app(string $text) {
         $result = $this->spin(function($context, $args) {
-            $result = $this->getSession()->evaluateScript('return window.behat.getHeader();');
+            $result = $this->evaluate_script('return window.behat.getHeader();');
             if (substr($result, 0, 3) !== 'OK:') {
                 throw new DriverException('Error getting header - ' . $result);
             }
@@ -536,7 +534,7 @@ class behat_app extends behat_base {
         if (count($names) !== 2) {
             throw new DriverException('Expected to see 2 tabs open, not ' . count($names));
         }
-        $this->getSession()->getDriver()->executeScript('window.close()');
+        $this->execute_script('window.close()');
         $this->getSession()->switchToWindow($names[0]);
     }
 
@@ -548,6 +546,6 @@ class behat_app extends behat_base {
      * @throws DriverException If the navigator.online mode is not available
      */
     public function i_switch_offline_mode(string $offline) {
-        $this->getSession()->evaluateScript('appProvider.setForceOffline(' . $offline . ');');
+        $this->execute_script('appProvider.setForceOffline(' . $offline . ');');
     }
 }
index ee6175a..d01ada7 100644 (file)
@@ -228,8 +228,7 @@ class behat_general extends behat_base {
         // unnamed window (presumably the main window) to some other named
         // window, then we first set the main window name to a conventional
         // value that we can later use this name to switch back.
-        $this->getSession()->executeScript(
-                'if (window.name == "") window.name = "' . self::MAIN_WINDOW_NAME . '"');
+        $this->execute_script('if (window.name == "") window.name = "' . self::MAIN_WINDOW_NAME . '"');
 
         $this->getSession()->switchToWindow($windowname);
     }
@@ -258,7 +257,7 @@ class behat_general extends behat_base {
         $names = $this->getSession()->getWindowNames();
         for ($index = 1; $index < count($names); $index ++) {
             $this->getSession()->switchToWindow($names[$index]);
-            $this->getSession()->executeScript("window.open('', '_self').close();");
+            $this->execute_script("window.open('', '_self').close();");
         }
         $names = $this->getSession()->getWindowNames();
         if (count($names) !== 1) {
@@ -924,7 +923,7 @@ class behat_general extends behat_base {
     return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING;
 })()
 EOF;
-            $ok = $this->getSession()->getDriver()->evaluateScript($js);
+            $ok = $this->evaluate_script($js);
         } else {
 
             // Using following xpath axe to find it.
@@ -1609,11 +1608,12 @@ EOF;
 
         $this->pageloaddetectionrunning = true;
 
-        $session->executeScript(
-                'var span = document.createElement("span");
-                span.setAttribute("data-rel", "' . self::PAGE_LOAD_DETECTION_STRING . '");
-                span.setAttribute("style", "display: none;");
-                document.body.appendChild(span);');
+        $this->execute_script(
+            'var span = document.createElement("span");
+            span.setAttribute("data-rel", "' . self::PAGE_LOAD_DETECTION_STRING . '");
+            span.setAttribute("style", "display: none;");
+            document.body.appendChild(span);'
+        );
     }
 
     /**
@@ -1811,7 +1811,7 @@ EOF;
         $xpath = addslashes_js($element->getXpath());
         $script = 'return (function() { return document.activeElement === document.evaluate("' . $xpath . '",
                 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; })(); ';
-        $targetisfocused = $this->getSession()->evaluateScript($script);
+        $targetisfocused = $this->evaluate_script($script);
         if ($not == ' not') {
             if ($targetisfocused) {
                 throw new ExpectationException("$nodeelement $nodeselectortype is focused", $this->getSession());
@@ -1843,7 +1843,7 @@ EOF;
         $xpath = addslashes_js($element->getXpath());
         $script = 'return (function() { return document.activeElement === document.evaluate("' . $xpath . '",
                 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; })(); ';
-        $targetisfocused = $this->getSession()->evaluateScript($script);
+        $targetisfocused = $this->evaluate_script($script);
         if ($not == ' not') {
             if ($targetisfocused) {
                 throw new ExpectationException("$nodeelement $nodeselectortype is focused", $this->getSession());
index 052fe30..a2309e4 100644 (file)
@@ -391,7 +391,7 @@ class behat_navigation extends behat_base {
         )";
 
         // Adding an extra click we need to show the 'Log in' link.
-        if (!$this->getSession()->getDriver()->evaluateScript($navbuttonjs)) {
+        if (!$this->evaluate_script($navbuttonjs)) {
             return false;
         }
 
@@ -757,7 +757,7 @@ class behat_navigation extends behat_base {
     }
 
     /**
-     * Opens the course homepage with editing mode on.
+     * Open the course homepage with editing mode enabled.
      *
      * @Given /^I am on "(?P<coursefullname_string>(?:[^"]|\\")*)" course homepage with editing mode on$/
      * @throws coding_exception
@@ -766,9 +766,22 @@ class behat_navigation extends behat_base {
      */
     public function i_am_on_course_homepage_with_editing_mode_on($coursefullname) {
         global $DB;
+
         $course = $DB->get_record("course", array("fullname" => $coursefullname), 'id', MUST_EXIST);
         $url = new moodle_url('/course/view.php', ['id' => $course->id]);
+
+        if ($this->running_javascript() && $sesskey = $this->get_sesskey()) {
+            // Javascript is running so it is possible to grab the session ket and jump straight to editing mode.
+            $url->param('edit', 1);
+            $url->param('sesskey', $sesskey);
+            $this->getSession()->visit($this->locate_path($url->out_as_local_url(false)));
+
+            return;
+        }
+
+        // Visit the course page.
         $this->getSession()->visit($this->locate_path($url->out_as_local_url(false)));
+
         try {
             $this->execute("behat_forms::press_button", get_string('turneditingon'));
         } catch (Exception $e) {
index fb9f4b2..c6c69d6 100644 (file)
@@ -61,21 +61,21 @@ class behat_assignfeedback_editpdf extends behat_base {
     var event = { clientX: 100, clientY: 250, preventDefault: function() {} };
     instance.edit_start(event);
 }()); ';
-        $this->getSession()->executeScript($js);
+        $this->execute_script($js);
         sleep(1);
         $js = ' (function() {
     var instance = M.assignfeedback_editpdf.instance;
     var event = { clientX: 150, clientY: 275, preventDefault: function() {} };
     instance.edit_move(event);
 }()); ';
-        $this->getSession()->executeScript($js);
+        $this->execute_script($js);
         sleep(1);
         $js = ' (function() {
     var instance = M.assignfeedback_editpdf.instance;
     var event = { clientX: 200, clientY: 300, preventDefault: function() {} };
     instance.edit_end(event);
 }()); ';
-        $this->getSession()->executeScript($js);
+        $this->execute_script($js);
         sleep(1);
     }
 
index 04cabba..9a74a13 100644 (file)
@@ -68,8 +68,7 @@ class behat_qtype_ddmarker extends behat_base {
         // DOM node so that its centre is over the centre of anothe DOM node.
         // Therefore to make it drag to the specified place, we have to add
         // a target div.
-        $session = $this->getSession();
-        $session->executeScript("
+        $this->execute_script("
                 (function() {
                     if (document.getElementById('target-{$x}-{$y}')) {
                         return;
@@ -86,7 +85,8 @@ class behat_qtype_ddmarker extends behat_base {
                     target.style.setProperty('top', yadjusted + 'px');
                     target.style.setProperty('width', '1px');
                     target.style.setProperty('height', '1px');
-                }())");
+                }())"
+        );
 
         $generalcontext = behat_context_helper::get('behat_general');
         $generalcontext->i_drag_and_i_drop_it_in($this->marker_xpath($marker),
index c7ca947..ac11c88 100644 (file)
@@ -51,7 +51,7 @@ class behat_search extends behat_base {
         $this->execute('behat_forms::i_set_the_field_to', ['q', $query]);
 
         // Submit the form.
-        $this->getSession()->executeScript('document.querySelector(".search-input-form.expanded").submit();');
+        $this->execute_script('return document.querySelector(".search-input-form.expanded").submit();');
     }
 
     /**