Esempio n. 1
0
 /**
  * Internal step definition to find exceptions, debugging() messages and PHP debug messages.
  *
  * Part of behat_hooks class as is part of the testing framework, is auto-executed
  * after each step so no features will splicitly use it.
  *
  * @throws Exception Unknown type, depending on what we caught in the hook or basic \Exception.
  * @see Moodle\BehatExtension\Tester\MoodleStepTester
  */
 public function look_for_exceptions()
 {
     // Wrap in try in case we were interacting with a closed window.
     try {
         // Exceptions.
         $exceptionsxpath = "//div[@data-rel='fatalerror']";
         // Debugging messages.
         $debuggingxpath = "//div[@data-rel='debugging']";
         // PHP debug messages.
         $phperrorxpath = "//div[@data-rel='phpdebugmessage']";
         // Any other backtrace.
         $othersxpath = "(//*[contains(., ': call to ')])[1]";
         $xpaths = array($exceptionsxpath, $debuggingxpath, $phperrorxpath, $othersxpath);
         $joinedxpath = implode(' | ', $xpaths);
         // Joined xpath expression. Most of the time there will be no exceptions, so this pre-check
         // is faster than to send the 4 xpath queries for each step.
         if (!$this->getSession()->getDriver()->find($joinedxpath)) {
             // Check if we have recorded any errors in driver process.
             $phperrors = behat_get_shutdown_process_errors();
             if (!empty($phperrors)) {
                 foreach ($phperrors as $error) {
                     $errnostring = behat_get_error_string($error['type']);
                     $msgs[] = $errnostring . ": " . $error['message'] . " at " . $error['file'] . ": " . $error['line'];
                 }
                 $msg = "PHP errors found:\n" . implode("\n", $msgs);
                 throw new \Exception(htmlentities($msg));
             }
             return;
         }
         // Exceptions.
         if ($errormsg = $this->getSession()->getPage()->find('xpath', $exceptionsxpath)) {
             // Getting the debugging info and the backtrace.
             $errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.alert-error');
             // If errorinfoboxes is empty, try find alert-danger (bootstrap4) class.
             if (empty($errorinfoboxes)) {
                 $errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.alert-danger');
             }
             // If errorinfoboxes is empty, try find notifytiny (original) class.
             if (empty($errorinfoboxes)) {
                 $errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.notifytiny');
             }
             // If errorinfoboxes is empty, try find ajax/JS exception in dialogue.
             if (empty($errorinfoboxes)) {
                 $errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.moodle-exception-message');
                 // If ajax/JS exception.
                 if ($errorinfoboxes) {
                     $errorinfo = $this->get_debug_text($errorinfoboxes[0]->getHtml());
                 }
             } else {
                 $errorinfo = $this->get_debug_text($errorinfoboxes[0]->getHtml()) . "\n" . $this->get_debug_text($errorinfoboxes[1]->getHtml());
             }
             $msg = "Moodle exception: " . $errormsg->getText() . "\n" . $errorinfo;
             throw new \Exception(html_entity_decode($msg));
         }
         // Debugging messages.
         if ($debuggingmessages = $this->getSession()->getPage()->findAll('xpath', $debuggingxpath)) {
             $msgs = array();
             foreach ($debuggingmessages as $debuggingmessage) {
                 $msgs[] = $this->get_debug_text($debuggingmessage->getHtml());
             }
             $msg = "debugging() message/s found:\n" . implode("\n", $msgs);
             throw new \Exception(html_entity_decode($msg));
         }
         // PHP debug messages.
         if ($phpmessages = $this->getSession()->getPage()->findAll('xpath', $phperrorxpath)) {
             $msgs = array();
             foreach ($phpmessages as $phpmessage) {
                 $msgs[] = $this->get_debug_text($phpmessage->getHtml());
             }
             $msg = "PHP debug message/s found:\n" . implode("\n", $msgs);
             throw new \Exception(html_entity_decode($msg));
         }
         // Any other backtrace.
         // First looking through xpath as it is faster than get and parse the whole page contents,
         // we get the contents and look for matches once we found something to suspect that there is a backtrace.
         if ($this->getSession()->getDriver()->find($othersxpath)) {
             $backtracespattern = '/(line [0-9]* of [^:]*: call to [\\->&;:a-zA-Z_\\x7f-\\xff][\\->&;:a-zA-Z0-9_\\x7f-\\xff]*)/';
             if (preg_match_all($backtracespattern, $this->getSession()->getPage()->getContent(), $backtraces)) {
                 $msgs = array();
                 foreach ($backtraces[0] as $backtrace) {
                     $msgs[] = $backtrace . '()';
                 }
                 $msg = "Other backtraces found:\n" . implode("\n", $msgs);
                 throw new \Exception(htmlentities($msg));
             }
         }
     } catch (NoSuchWindow $e) {
         // If we were interacting with a popup window it will not exists after closing it.
     }
 }
Esempio n. 2
0
/**
 * PHP errors handler to use when running behat tests.
 *
 * Adds specific CSS classes to identify
 * the messages.
 *
 * @param int $errno
 * @param string $errstr
 * @param string $errfile
 * @param int $errline
 * @param array $errcontext
 * @return bool
 */
function behat_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {

    // If is preceded by an @ we don't show it.
    if (!error_reporting()) {
        return true;
    }

    // This error handler receives E_ALL | E_STRICT, running the behat test site the debug level is
    // set to DEVELOPER and will always include E_NOTICE,E_USER_NOTICE... as part of E_ALL, if the current
    // error_reporting() value does not include one of those levels is because it has been forced through
    // the moodle code (see fix_utf8() for example) in that cases we respect the forced error level value.
    $respect = array(E_NOTICE, E_USER_NOTICE, E_STRICT, E_WARNING, E_USER_WARNING);
    foreach ($respect as $respectable) {

        // If the current value does not include this kind of errors and the reported error is
        // at that level don't print anything.
        if ($errno == $respectable && !(error_reporting() & $respectable)) {
            return true;
        }
    }

    // Using the default one in case there is a fatal catchable error.
    default_error_handler($errno, $errstr, $errfile, $errline, $errcontext);

    $errnostr = behat_get_error_string($errno);

    // If ajax script then throw exception, so the calling api catch it and show it on web page.
    if (defined('AJAX_SCRIPT')) {
        throw new Exception("$errnostr: $errstr in $errfile on line $errline");
    } else {
        // Wrapping the output.
        echo '<div class="phpdebugmessage" data-rel="phpdebugmessage">' . PHP_EOL;
        echo "$errnostr: $errstr in $errfile on line $errline" . PHP_EOL;
        echo '</div>';
    }

    // Also use the internal error handler so we keep the usual behaviour.
    return false;
}