You are here

SelectOrOtherTestBase.test in Select (or other) 7.3

Contains SelectOrOtherTestBase.

File

tests/SelectOrOtherTestBase.test
View source
<?php

/**
 * @file
 *  Contains SelectOrOtherTestBase.
 */

/**
 * Class SelectOrOtherTestBase
 *   Base class for select_or_other testing.
 */
class SelectOrOtherTestBase extends DrupalWebTestCase {
  protected $defaultPermissions;

  /**
   * @var array $fields
   *   associated array keyed by field_name with the following information:
   *   - Widget (machine name of the widget used)
   *   - Cardinality (1, -1)
   *   - field_settings @see field_info_field().
   *   - instance_settings @see field_info_instance().
   *
   */
  protected $fields;
  public function setUp() {

    // Also enable any modules required by the tests overriding this base class.
    $modules = func_get_args();
    if (isset($modules[0]) && is_array($modules[0])) {
      $modules = $modules[0];
    }

    // At the very least enable the select_or_other module.
    parent::setUp(array_merge(array(
      'select_or_other',
    ), $modules));

    // Clear the array of fields to test.
    $this->fields = array();
  }

  /**
   * Check to see if a label is visible only once.
   * @param string $label
   *   The label to look for.
   * @param string $element_name
   *   The element the label should be for.
   */
  protected function assertLabelVisibleOnce($label, $element_name) {
    $xpath = "//label[@for[starts-with(., :element-name)] and starts-with(., :label)]";
    $arguments = array(
      ':label' => $label,
      ':element-name' => $element_name,
    );
    $message_arguments = array(
      '%label' => $label,
      '%element-name' => $element_name,
    );
    $elements = $this
      ->xpath($xpath, $arguments);
    $this
      ->assertEqual(count($elements), 1, t('%label is visible once for element %element', $message_arguments));
  }

  /**
   * Make sure the field label is visible only once.
   */
  function testFieldLabelVisibleOnce() {
    foreach ($this->fields as $field_name => $field) {
      $this
        ->drupalGet('node/add/' . $this
        ->getFieldContentType($field_name));
      $this
        ->assertLabelVisibleOnce($field_name, "edit-{$field_name}-und-select");
    }
  }

  /**
   * Make sure field cardinality is checked.
   */
  function testCardinalityValidation() {
    $tested_types = array();
    foreach ($this->fields as $field_name => $field) {
      $widget_type = $field['instance_settings']['widget']['type'];
      if (!isset($tested_types[$widget_type])) {
        $field_info = field_info_field($field_name);
        $field_info['cardinality'] = $this->fields[$field_name]['cardinality'] = 2;
        field_update_field($field_info);
        $this
          ->selectAllOptions($field_name);
        $this
          ->assertText('cannot hold more than 2 values');
        $tested_types[$widget_type] = TRUE;
      }
    }
  }

  /**
   * Make sure an empty option is present when relevant.
   */
  function testEmptyOption($other_option = '') {
    foreach ($this->fields as $field_name => $field) {
      $this
        ->drupalGet('node/add/' . $this
        ->getFieldContentType($field_name));
      $type = $this
        ->getWidgetType($field_name);
      $multiple = $field['cardinality'] !== 1;
      $required = $field['instance_settings']['required'];

      // First test empty behaviour. Only single select boxes should always have
      // an empty value.
      if ($type === 'select' && !$multiple) {
        if ($required) {
          $this
            ->assertText(t('- Select -'));
        }
        else {
          $this
            ->assertText(t('- None -'));
        }
      }
      else {
        $this
          ->assertNoText(t('- Select -'));
        $this
          ->assertNoText(t('- None -'));
      }

      // Test non-empty behaviour. Once again only single cardinality elements
      // should have empty options to allow for the removal of values if the
      // field is not required.
      if ($other_option !== '') {

        // We set the other option, because we can set that in the same way
        // always.
        $this
          ->setFieldValue($field_name, 'select_or_other', $other_option);
        $this
          ->clickLink(t('Edit'));
        if (!$multiple && !$required) {
          $this
            ->assertText(t('- None -'));
        }
        else {
          $this
            ->assertNoText(t('- Select -'));
          $this
            ->assertNoText(t('- None -'));
        }
      }
      else {
        $this
          ->fail('No $other_option provided, this test should be overridden and calling itself from individual test classes.');
      }
    }
  }

  /**
   * Generate content types and fields for testing.
   * @param string $field_type
   *   The type of field to create.
   * @param array $widgets
   *   The types of widgets to use.
   * @param array $widget_settings
   *   The widget settings.
   * @param $field_formatter
   *   Machine name of the field formatter to use for display.
   * @throws \Exception
   * @throws \FieldException
   */
  protected function prepareTestFields($field_type, $field_settings, $widgets, $widget_settings, $field_formatter) {

    // Configure fields.
    foreach ($widgets as $widget) {
      foreach (array(
        1,
        -1,
      ) as $cardinality) {
        foreach (array(
          TRUE,
          FALSE,
        ) as $required) {
          $content_type = $this
            ->drupalCreateContentType();
          $field_info = array(
            'content_type' => $content_type,
            'widget' => $widget,
            'cardinality' => $cardinality,
          );

          // Create the field.
          $field = array(
            'type' => $field_type,
            'field_name' => strtolower($this
              ->randomName()),
            'cardinality' => $cardinality,
            'settings' => $field_settings,
          );
          field_create_field($field);
          $field_info['field_settings'] = $field;
          $instance_settings = array(
            'entity_type' => 'node',
            'required' => $required,
            'bundle' => $field_info['content_type']->name,
            'field_name' => $field['field_name'],
            'widget' => array(
              'type' => $widget,
              'settings' => $widget_settings,
            ),
            'display' => array(
              'full' => array(
                'type' => $field_formatter,
              ),
            ),
          );
          $field_info['instance_settings'] = field_create_instance($instance_settings);
          $this->fields[$field['field_name']] = $field_info;
        }
      }
    }

    // Determine required permissions.
    $this->defaultPermissions = array(
      'bypass node access',
    );
  }

  /**
   * Submit the add node form with the selected values.
   * @param $field_name
   * @param $select
   * @param $other
   */
  protected function setFieldValue($field_name, $select, $other = '') {
    $edit = array();

    // A node requires a title.
    $edit["title"] = $this
      ->randomName(8);
    $this
      ->drupalGet('node/add/' . $this
      ->getFieldContentType($field_name));

    // Set the select value.
    if ($this->fields[$field_name]['cardinality'] == 1) {
      $edit["{$field_name}[und][select]"] = $select;
    }
    else {

      // We have to treat multiple selection elements differently.
      if ($this
        ->getWidgetType($field_name) === 'select') {

        // We're dealing with a multiple select.
        $edit["{$field_name}[und][select][]"] = $select;
      }
      else {

        // We're dealing with checkboxes.
        $edit["{$field_name}[und][select][{$select}]"] = $select;
      }
    }

    // Set the other value.
    $edit["{$field_name}[und][other]"] = $other;

    // Create the node.
    $this
      ->drupalPost(NULL, $edit, t('Save'));
  }

  /**
   * Submit the add node form with all options selected for the specified field.
   *
   * @param string $field_name
   *   Name of the field to select all options for.
   * @param string $other_option
   *   Optionally provide a value for the other field. Will default to 999
   */
  protected function selectAllOptions($field_name, $other_option = '') {
    $edit = array();

    // A node requires a title.
    $edit["title"] = $this
      ->randomName(8);
    $this
      ->drupalGet('node/add/' . $this
      ->getFieldContentType($field_name));

    // Set the select value.
    if ($this->fields[$field_name]['cardinality'] == 1) {
      $this
        ->fail('Unable to select multiple options because the cardinality is 1');
    }
    else {

      // We have to treat multiple selection elements differently.
      if ($this
        ->getWidgetType($field_name) === 'select') {

        // Select all options for this select box.
        $xpath = "//select[@id = :id]/option";
        $arguments = array(
          ':id' => "edit-{$field_name}-und-select",
        );
        $options = $this
          ->xpath($xpath, $arguments);

        // Prepare array of values.
        $select = array();
        foreach ($options as $option) {
          $select[] = $option['value'];
        }
        $edit["{$field_name}[und][select][]"] = $select;
      }
      else {

        // Find all checkboxes.
        $xpath = "//input[@id[starts-with(., :id)]]";
        $arguments = array(
          ':id' => "edit-{$field_name}-und-select",
        );
        $options = $this
          ->xpath($xpath, $arguments);
        foreach ($options as $option) {
          $id = reset($option['id']);
          $label = $this
            ->xpath('//label[@for = :id]', array(
            ':id' => $id,
          ));
          $key = reset($option['name']);
          $value = (string) reset($label);
          $edit[$key] = trim($value);
        }
      }
    }

    // Unless the other option is overridden, set a numeric other value because
    // each widget will accept one.
    $edit["{$field_name}[und][other]"] = $other_option == '' ? 999 : $other_option;

    // Create the node.
    $this
      ->drupalPost(NULL, $edit, t('Save'));
  }

  /**
   * Determines the type of widget used on the page.
   *
   * @param string $field_name
   *   The field name to determine widget type for.
   * @return string
   *   'select' or 'buttons' depending on the widget type.
   */
  protected function getWidgetType($field_name) {
    $xpath = "//select[@id = :id]";
    $arguments = array(
      ':id' => "edit-{$field_name}-und-select",
    );
    $elements = $this
      ->xpath($xpath, $arguments);

    // we are dealing with a select widget.
    if (count($elements)) {
      return 'select';
    }
    else {
      return 'buttons';
    }
  }

  /**
   * Returns the machine name of the content type a field is configured on.
   *
   * @param $field_name
   *   The field machine name of which to retrieve the content type.
   * @return string|null
   *   The content type machine name or NULL if not found.
   */
  protected function getFieldContentType($field_name) {
    return $this->fields[$field_name]['content_type']->name;
  }

}

Classes

Namesort descending Description
SelectOrOtherTestBase Class SelectOrOtherTestBase Base class for select_or_other testing.