If during a test you post to a form, and an error occurs in the form it should by default assert an error within the test.

However there if the test is checking for the existence of an error then it should have a different command from $this->drupalPost() that will ignore any errors that produced and maybe even a method of asserting based on the content of the error messages.

The second case is not really the norm, so by default the tests should check the for errors and allow the test author to code around any "known" errors.

I am marking this as critical as this maybe a larger issue where errors maybe being produced during tests but being ignored. I actually found this during testing of some issues in e-Commerce.

Comments

gordon’s picture

Here is some code that I wrote which would add the drupal messages to the headers so that they could be past back to $this->drupalPost() so that they can be asserted.

This is a class that I wrote which extended and added this functionality.

class eCommerceWebTestCase extends DrupalWebTestCase {
  /**
   * An array of all the messages that have been returned from a post.
   *
   * var Array();
   */
  protected $messages;
  
  protected function curlHeaderCallback($curlHandler, $header) {
    parent::curlHeaderCallback($curlHandler, $header);
      
    if (preg_match('/^X-Drupal-Message-(.*)-[0-9]+: (.*)$/', $header, $matches)) {
      $this->messages[$matches[1]][] = $matches[2];
    }
    
    // This is required by cURL.
    return strlen($header);
  }
  
  protected function drupalPost($path, $edit, $submit, array $options = array(), array $headers = array()) {
    $return = parent::drupalPost($path, $edit, $submit, $options, $headers);
    
    if (isset($this->messages['error'])) {
      foreach ($this->messages['error'] as $message) {
        $this->fail($message, 'Error messages');
      }
    }
    
    return $return;
  }
}

And code to allow the passing back of the error messages.

/**
 * Implementation of hook_theme_registry_alter().
 */
function ec_common_theme_registry_alter(&$registry) {
  array_unshift($registry['page']['preprocess functions'], '_ec_common_preprocess_page');
}

function _ec_common_preprocess_page(&$variables) {
  if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^simpletest\d+;/", $_SERVER['HTTP_USER_AGENT']) && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) {
    if ($messages = drupal_set_message()) {
      static $numbers = array();
      $type = isset($variables['display']) ? $variables['display'] : NULL;
      if ($type && !isset($messages[$type])) {
        $messages = array();
      }
      else if ($type) {
        $messages = array($type => $messages[$type]);
      }
      foreach ($messages as $type => $message) {
        if (!isset($numbers[$type])) {
          $numbers[$type] = 0;
        }
        foreach ($messages[$type] as $message) {
          header('X-Drupal-Message-' . $type . '-' . $numbers[$type] . ':' . $message);
          $numbers[$type]++;
        }
      }
    }
  }
}

I don't think this is the best method of doing this as I will not able to find the best way to have it disabled when you are not running simpletest, but maybe it will give someone some ideas.

Gordon.

dave reid’s picture

Category: bug » feature
Priority: Critical » Normal

This is a feature request, not a bug report.