reference_option_limit.test in Reference field option limit 7
Contains tests for the Reference option limit module.
File
tests/reference_option_limit.testView source
<?php
/**
* @file
* Contains tests for the Reference option limit module.
*/
/**
* Test use of the module with term reference fields.
*/
class ReferenceOptionLimitTaxonomyTestCase extends DrupalWebTestCase {
/**
* Implements getInfo().
*/
public static function getInfo() {
return array(
'name' => t('Reference Option Limit taxonomy term'),
'description' => t('Tests behaviour with taxonomy term reference fields.'),
'group' => t('Reference Option Limit'),
);
}
/**
* Implements setUp().
*/
function setUp() {
parent::setUp(array(
'reference_option_limit',
'reference_option_limit_test_taxonomy',
));
// Create our creator user.
$this->user = $this
->drupalCreateUser(array(
'administer nodes',
'create test_rol_node_taxo content',
'edit any test_rol_node_taxo content',
));
$this
->drupalLogin($this->user);
}
/**
* Test the module's functionality.
*/
function testNodeCreateForm() {
$this
->drupalGet('node/add/test-rol-node-taxo');
// Get a country term.
$terms = taxonomy_get_term_by_name('France', 'countries');
$country_term = array_pop($terms);
$edit = array(
'test_rol_country[und]' => $country_term->tid,
);
$this
->drupalPostAJAX(NULL, $edit, 'test_rol_country[und]');
// The AJAX post updates the content our assertions test against.
// Check each term: all the cities in France should be present; all the
// others should not.
foreach (reference_option_limit_test_taxonomy_cities() as $city_name => $country_name) {
if ($country_name == 'France') {
$this
->assertText($city_name, "The {$city_name} term was found in the form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} term was not found in the form.");
}
}
// Get a country term.
$terms = taxonomy_get_term_by_name('Italy', 'countries');
$country_term = array_pop($terms);
$edit = array(
'test_rol_country[und]' => $country_term->tid,
);
// Change the country we have selected.
$this
->drupalPostAJAX(NULL, $edit, 'test_rol_country[und]');
foreach (reference_option_limit_test_taxonomy_cities() as $city_name => $country_name) {
if ($country_name == 'Italy') {
$this
->assertText($city_name, "The {$city_name} term was found in the form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} term was not found in the form.");
}
}
// Save the node.
$terms = taxonomy_get_term_by_name('Firenze', 'cities');
$city_term = array_pop($terms);
$edit = array(
'title' => $this
->randomName(),
// Use the most recent country term.
'test_rol_country[und]' => $country_term->tid,
"test_rol_city[und][{$city_term->tid}]" => 1,
);
$this
->drupalPost(NULL, $edit, t('Save'));
// The URL is of the form http://example.com/node/NID.
$url = $this
->getUrl();
$pieces = explode('/', $url);
$nid = array_pop($pieces);
$node = node_load($nid);
$this
->assertEqual($node->test_rol_country[LANGUAGE_NONE][0]['tid'], $country_term->tid, "The node has its country field value set.");
$this
->assertEqual($node->test_rol_city[LANGUAGE_NONE][0]['tid'], $city_term->tid, "The node has its city field value set.");
}
/**
* Test the node edit form.
*/
function testNodeEditForm() {
// Get country and city terms.
$terms = taxonomy_get_term_by_name('Italy', 'countries');
$country_term = array_pop($terms);
$terms = taxonomy_get_term_by_name('Firenze', 'cities');
$city_term = array_pop($terms);
// Create a node: Italy, Firenze.
$edit = array(
'uid' => $this->user->uid,
'name' => $this->user->name,
'type' => 'test_rol_node_taxo',
'language' => LANGUAGE_NONE,
'title' => $this
->randomName(),
);
$edit['test_rol_country'][LANGUAGE_NONE][0]['tid'] = $country_term->tid;
$edit['test_rol_city'][LANGUAGE_NONE][0]['tid'] = $city_term->tid;
$node = (object) $edit;
node_save($node);
// Edit the node.
$this
->drupalGet("node/{$node->nid}/edit");
foreach (reference_option_limit_test_taxonomy_cities() as $city_name => $country_name) {
if ($country_name == 'Italy') {
$this
->assertText($city_name, "The {$city_name} term was found in the form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} term was not found in the form.");
}
}
// Get a country term.
$terms = taxonomy_get_term_by_name('France', 'countries');
$country_term = array_pop($terms);
$edit = array(
'test_rol_country[und]' => $country_term->tid,
);
// Change the country we have selected in the form: France.
$this
->drupalPostAJAX(NULL, $edit, 'test_rol_country[und]');
foreach (reference_option_limit_test_taxonomy_cities() as $city_name => $country_name) {
if ($country_name == 'France') {
$this
->assertText($city_name, "The {$city_name} term was found in the form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} term was not found in the form.");
}
}
$terms = taxonomy_get_term_by_name('Paris', 'cities');
$city_term = array_pop($terms);
// Save the form with France, Paris.
$edit = array(
'test_rol_country[und]' => $country_term->tid,
"test_rol_city[und][{$city_term->tid}]" => 1,
);
$this
->drupalPost(NULL, $edit, t('Save'));
entity_get_controller('node')
->resetCache();
$node = node_load($node->nid);
$this
->assertEqual($node->test_rol_country[LANGUAGE_NONE][0]['tid'], $country_term->tid, "The node's country was updated.");
$this
->assertEqual($node->test_rol_city[LANGUAGE_NONE][0]['tid'], $city_term->tid, "The node's city was updated.");
}
}
/**
* Common base class for test cases that use entityreference fields.
*/
abstract class ReferenceOptionLimitEntityreferenceTestCaseBase extends DrupalWebTestCase {
/**
* Helper for getting a node by title.
*
* This works for retrieving both country and city nodes.
*
* @param $node_title
* The title of the node to get.
*
* @return
* A node entity.
*/
protected function getNodeByTitle($title) {
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node');
$query
->propertyCondition('title', $title);
$result = $query
->execute();
// We expect only one node to satisfy this query.
$nids = array_keys($result['node']);
$node = node_load(array_pop($nids));
$this
->assertTrue($node, format_string("Node id !nid with the given title %title was found.", array(
'!nid' => $node->nid,
'%title' => $title,
)));
return $node;
}
}
/**
* Test use of the module with entityreference fields.
*/
class ReferenceOptionLimitEntityreferenceTestCase extends ReferenceOptionLimitEntityreferenceTestCaseBase {
/**
* Implements getInfo().
*/
public static function getInfo() {
return array(
'name' => t('Reference Option Limit entityreference'),
'description' => t('Tests behaviour with entityreference fields.'),
'group' => t('Reference Option Limit'),
);
}
/**
* Implements setUp().
*/
function setUp() {
parent::setUp(array(
'reference_option_limit',
'reference_option_limit_test_entityreference',
));
// Create our creator user.
$this->user = $this
->drupalCreateUser(array(
'administer nodes',
'create test_rol_node_article content',
'edit any test_rol_node_article content',
));
$this
->drupalLogin($this->user);
}
/**
* Test the functionality on a node create form.
*/
function testNodeCreateForm() {
// In order to test every combination of settings, we define the different
// orthogonal settings and their ranges.
$ranges = array(
// The field cardinality for the matching field.
'cardinality' => array(
1,
FIELD_CARDINALITY_UNLIMITED,
),
// The field widget for the matching field.
'widget' => array(
'options_buttons',
'options_select',
),
// The default value for the matching field, as an entity label.
'default' => array(
array(),
array(
'Britain',
),
),
// If TRUE, a limited field shows no options if the matching field is
// initially empty.
'empty_behaviour' => array(
FALSE,
TRUE,
),
);
// Work over all the combinations of settings.
foreach ($ranges['cardinality'] as $cardinality) {
foreach ($ranges['widget'] as $widget) {
foreach ($ranges['default'] as $default) {
foreach ($ranges['empty_behaviour'] as $empty_behaviour) {
// Make the settings changes to the field and instance.
$this
->changeFieldSettings(array(
'cardinality' => $cardinality,
'widget' => $widget,
'default' => $default,
'empty_behaviour' => $empty_behaviour,
));
// Test the functionality.
$this
->helperTestNodeCreateForm(array(
'cardinality' => $cardinality,
'widget' => $widget,
'default' => $default,
'empty_behaviour' => $empty_behaviour,
));
}
}
}
}
}
/**
* Helper to change the field settings.
*
* @param $settings
* An array of settings to apply, with the following properties:
* - 'widget': The widget type to set on the matching field instance.
* - 'cardinality': The cardinality to set on the matching field.
* - 'default': The default value to set on the matching field instance.
* - 'empty_behaviour': Whether the limited field shows all options or none
* when the matching field is initially empty.
*/
function changeFieldSettings($settings) {
$country_field_info = field_info_field('test_rol_er_country');
$country_instance_info = field_info_instance('node', 'test_rol_er_country', 'test_rol_node_article');
$city_instance_info = field_info_instance('node', 'test_rol_er_city', 'test_rol_node_article');
// Set the cardinality on the field.
$country_field_info['cardinality'] = $settings['cardinality'];
// Set the widget type on the instance.
$country_instance_info['widget']['type'] = $settings['widget'];
// Set the empty default behaviour on the instance of the limited field,
// i.e., the city.
$city_instance_info['options_limit_empty_behaviour'] = $settings['empty_behaviour'];
// Set the default value on the instance.
if (empty($settings['default'])) {
$default = NULL;
}
else {
$default = array();
foreach ($settings['default'] as $entity_label) {
$node = $this
->getNodeByTitle($entity_label);
$default[]['target_id'] = $node->nid;
}
}
$country_instance_info['default_value'] = $default;
field_update_field($country_field_info);
field_update_instance($country_instance_info);
field_update_instance($city_instance_info);
}
/**
* Helper to run tests.
*
* This allows us to run the same tests with different field settings.
*
* @param $settings
* An array of key settings for the field and instance, with the following
* properties:
* - 'widget': The widget type used by the the field instance. One of
* either 'options_select' or 'options_buttons'.
* - 'cardinality': The cardinality on the field. One of either 1 or
* FIELD_CARDINALITY_UNLIMITED.
* - 'default': The default value on the field instance. An array of values
* (without the FieldAPI nesting for language and delta). For no default
* value, an empty array.
* - 'empty_behaviour': Whether the limited field shows all options (FALSE)
* or none (TRUE) when the matching field is initially empty.
*/
function helperTestNodeCreateForm($settings) {
// Sanity check that the field settings are what we expect then to be.
// This also helps make the test result more readable, as it marks the start
// of a new round.
$country_field_info = field_info_field('test_rol_er_country');
$country_instance_info = field_info_instance('node', 'test_rol_er_country', 'test_rol_node_article');
$city_instance_info = field_info_instance('node', 'test_rol_er_city', 'test_rol_node_article');
$this
->assertTrue($country_instance_info['widget']['type'] == $settings['widget'] && $country_field_info['cardinality'] == $settings['cardinality'] && $city_instance_info['options_limit_empty_behaviour'] == $settings['empty_behaviour'], format_string("The field settings are correctly set: widget type !widget, cardinality !card, default value !default, default value behaviour: !empty-default.", array(
'!widget' => $settings['widget'],
'!card' => $settings['cardinality'] == FIELD_CARDINALITY_UNLIMITED ? 'unlimited' : $settings['cardinality'],
'!default' => empty($settings['default']) ? 'none' : implode(', ', $settings['default']),
'!empty-default' => $settings['empty_behaviour'] ? 'hide options for an empty default' : "don't hide options for an empty default",
)));
$this
->drupalGet('node/add/test-rol-node-article');
// Check that the city field is limited by the default value of the country
// field. (We can assume that FieldAPI works properly and that the default
// value is set!)
// The the empty behaviour determines what should happen to the city field
// when the country field default is empty:
// - empty_behaviour TRUE: no city options shown.
// - empty_behaviour FALSE: all city options shown.
$expect_no_cities = $expect_all_cities = FALSE;
if (empty($settings['default'])) {
if ($settings['empty_behaviour']) {
$expect_no_cities = TRUE;
}
else {
$expect_all_cities = TRUE;
}
}
foreach (reference_option_limit_test_entityreference_cities() as $city_name => $country_name) {
// We expect to find the city listed if one of the following holds:
// - its country is in the default
// - the default is empty, and the empty behaviour is not to limit
// options.
if ($expect_no_cities) {
$this
->assertNoText($city_name, "The {$city_name} node was not found in the initial node add form.");
continue;
}
if ($expect_all_cities) {
$this
->assertText($city_name, "The {$city_name} node was found in the initial node add form.");
continue;
}
$country_of_city_in_default = in_array($country_name, $settings['default']);
if ($country_of_city_in_default) {
$this
->assertText($city_name, "The {$city_name} node was found in the initial node add form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} node was not found in the initial node add form.");
}
}
// Change the country we have selected.
$this
->rolPostAJAXCountryField('France', $settings);
// The AJAX post updates the content our assertions test against.
// Check each term: all the cities in France should be present; all the
// others should not.
foreach (reference_option_limit_test_entityreference_cities() as $city_name => $country_name) {
if ($country_name == 'France') {
$this
->assertText($city_name, "The {$city_name} node was found in the form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} node was not found in the form.");
}
}
// Change the country we have selected.
$this
->rolPostAJAXCountryField('Italy', $settings);
foreach (reference_option_limit_test_entityreference_cities() as $city_name => $country_name) {
if ($country_name == 'Italy') {
$this
->assertText($city_name, "The {$city_name} node was found in the form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} node was not found in the form.");
}
}
// Save the node.
$city_node = $this
->getNodeByTitle('Firenze');
$country_node = $this
->getNodeByTitle('Italy');
$post_data = $this
->getEditArray('Italy', $settings);
$post_data['edit']['title'] = $this
->randomName();
$post_data['edit']["test_rol_er_city[und][{$city_node->nid}]"] = 1;
$this
->drupalPost(NULL, $post_data['edit'], t('Save'));
// The URL is of the form http://example.com/node/NID.
$url = $this
->getUrl();
$pieces = explode('/', $url);
$nid = array_pop($pieces);
$node = node_load($nid);
$this
->assertEqual($node->test_rol_er_country[LANGUAGE_NONE][0]['target_id'], $country_node->nid, "The node has its country field value set.");
$this
->assertEqual($node->test_rol_er_city[LANGUAGE_NONE][0]['target_id'], $city_node->nid, "The node has its city field value set.");
}
/**
* Wrapper around drupalPostAJAX() for updating the country field.
*
* This allows for the differing structures required in the POST data array
* for different form elements.
*
* @param $country_node_title
* The title of the country node to set on the country field.
* @param $settings
* The array of field settings passed to helperTestNodeCreateForm().
*/
function rolPostAJAXCountryField($country_node_title, $settings) {
if ($settings['widget'] . '-' . $settings['cardinality'] == 'options_buttons-' . FIELD_CARDINALITY_UNLIMITED) {
// Special case for checkboxes: because each checkbox is a separate form
// element, we have to unselect all the other values first.
$cities = reference_option_limit_test_entityreference_cities();
foreach (array_unique($cities) as $country_name) {
if ($country_name != $country_node_title) {
$excluded_node = $this
->getNodeByTitle($country_name);
$edit = array();
// Checkboxes must use FALSE -- see handleForm().
$edit["test_rol_er_country[und][{$excluded_node->nid}]"] = FALSE;
$this
->drupalPostAJAX(NULL, $edit, "test_rol_er_country[und][{$excluded_node->nid}]");
}
}
}
$post_data = $this
->getEditArray($country_node_title, $settings);
$this
->drupalPostAJAX(NULL, $post_data['edit'], $post_data['triggering_element']);
}
/**
* Helper to get the values for POST and AJAX operations.
*
* The structure of this varies according to the widgets in use.
*
* @param $country_node_title
* The title of the country node that should be present in the POST array.
* @param $settings
* The array of field settings passed to helperTestNodeCreateForm().
*
* @return
* An array containing the following properties:
* - 'edit': The $edit array suitable for drupalPostAJAX() or drupalPost().
* - 'triggering_element': The name of the triggering element suitable for
* drupalPostAJAX().
*/
function getEditArray($country_node_title, $settings) {
$node = $this
->getNodeByTitle($country_node_title);
$return = array();
// The structure of the $edit array we pass to to a post depends on the
// form element, and thus on the field widget and cardinality. Set the key
// to use in the $edit array accordingly.
switch ($settings['widget'] . '-' . $settings['cardinality']) {
case 'options_select-1':
// Single select list.
$return['edit'] = array(
'test_rol_er_country[und]' => $node->nid,
);
$return['triggering_element'] = 'test_rol_er_country[und]';
break;
case 'options_select-' . FIELD_CARDINALITY_UNLIMITED:
// Multi-select.
$return['edit'] = array(
'test_rol_er_country[und][]' => $node->nid,
);
$return['triggering_element'] = 'test_rol_er_country[und][]';
break;
case 'options_buttons-1':
// Radios.
$return['edit'] = array(
'test_rol_er_country[und]' => $node->nid,
);
$return['triggering_element'] = 'test_rol_er_country[und]';
break;
case 'options_buttons-' . FIELD_CARDINALITY_UNLIMITED:
// Checkboxes.
$return['edit'] = array(
"test_rol_er_country[und][{$node->nid}]" => $node->nid,
);
// Checkboxes have a special problem when there is a default value on
// one of them. Because they are all separate elements, drupalPost()
// tries to preserve their individual values when it fills out the $edit
// array. And because drupalPostAJAX() doesn't update the internal
// browser's HTML with the change (i.e., it doesn't change the
// checkbox's state), a checkbox that is checked by default will keep
// getting added to the $edit array as being checked in drupalPost().
// So we have to explicitly uncheck it here every time.
// This is (I believe) a bug in Drupal core: see
// https://www.drupal.org/node/2423159
foreach ($settings['default'] as $default_node_title) {
if ($country_node_title == $default_node_title) {
// Obviously if it happens that the default checkbox is one we now
// want to set, leave it.
continue;
}
$default_node = $this
->getNodeByTitle($default_node_title);
$return['edit']["test_rol_er_country[und][{$default_node->nid}]"] = FALSE;
}
$return['triggering_element'] = "test_rol_er_country[und][{$node->nid}]";
break;
}
return $return;
}
}
/**
* Test use of the module on a Profile2 entity.
*/
class ReferenceOptionLimitProfile2TestCase extends ReferenceOptionLimitEntityreferenceTestCaseBase {
/**
* Implements getInfo().
*/
public static function getInfo() {
return array(
'name' => t('Profile2 entity form'),
'description' => t('Tests behaviour on Profile2 entities with entityreference fields.'),
'group' => t('Reference Option Limit'),
);
}
/**
* Implements setUp().
*/
function setUp() {
parent::setUp(array(
'reference_option_limit',
'reference_option_limit_test_entityreference',
'profile2',
'reference_option_limit_test_profile2',
));
// Create our creator user.
$this->user = $this
->drupalCreateUser(array(
'edit own test_rol profile',
));
$this
->drupalLogin($this->user);
}
/**
* Test the functionality of Profile2 fields on a user edit form.
*/
function testProfile2Form() {
$user_id = $this->user->uid;
$this
->drupalGet("user/{$user_id}/edit/test_rol");
// Get a country node.
$country_node = $this
->getNodeByTitle('France');
$edit = array(
'profile_test_rol[test_rol_er_country][und]' => $country_node->nid,
);
$this
->drupalPostAJAX(NULL, $edit, 'profile_test_rol[test_rol_er_country][und]');
// The AJAX post updates the content our assertions test against.
// Check each term: all the cities in France should be present; all the
// others should not.
foreach (reference_option_limit_test_entityreference_cities() as $city_name => $country_name) {
if ($country_name == 'France') {
$this
->assertText($city_name, "The {$city_name} node was found in the form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} node was not found in the form.");
}
}
// Get a country node.
$country_node = $this
->getNodeByTitle('Italy');
$edit = array(
'profile_test_rol[test_rol_er_country][und]' => $country_node->nid,
);
// Change the country we have selected.
$this
->drupalPostAJAX(NULL, $edit, 'profile_test_rol[test_rol_er_country][und]');
foreach (reference_option_limit_test_entityreference_cities() as $city_name => $country_name) {
if ($country_name == 'Italy') {
$this
->assertText($city_name, "The {$city_name} node was found in the form.");
}
else {
$this
->assertNoText($city_name, "The {$city_name} node was not found in the form.");
}
}
// Pick a city and save the entity.
$city_node = $this
->getNodeByTitle('Firenze');
$edit = array(
// Use the most recent country node.
'profile_test_rol[test_rol_er_country][und]' => $country_node->nid,
"profile_test_rol[test_rol_er_city][und][{$city_node->nid}]" => 1,
);
$this
->drupalPost(NULL, $edit, t('Save'));
// Load the profile.
$profile = profile2_load_by_user($this->user, 'test_rol');
$this
->assertEqual($profile->test_rol_er_country[LANGUAGE_NONE][0]['target_id'], $country_node->nid, "The node has its country field value set.");
$this
->assertEqual($profile->test_rol_er_city[LANGUAGE_NONE][0]['target_id'], $city_node->nid, "The node has its city field value set.");
}
}
Classes
Name | Description |
---|---|
ReferenceOptionLimitEntityreferenceTestCase | Test use of the module with entityreference fields. |
ReferenceOptionLimitEntityreferenceTestCaseBase | Common base class for test cases that use entityreference fields. |
ReferenceOptionLimitProfile2TestCase | Test use of the module on a Profile2 entity. |
ReferenceOptionLimitTaxonomyTestCase | Test use of the module with term reference fields. |