summaryrefslogtreecommitdiff
path: root/modules/simpletest
diff options
context:
space:
mode:
Diffstat (limited to 'modules/simpletest')
-rw-r--r--modules/simpletest/drupal_web_test_case.php32
-rw-r--r--modules/simpletest/tests/ajax.test58
-rw-r--r--modules/simpletest/tests/ajax_forms_test.module62
-rw-r--r--modules/simpletest/tests/form.test71
-rw-r--r--modules/simpletest/tests/form_test.module86
5 files changed, 288 insertions, 21 deletions
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index f2622444d..42ac83058 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -1576,11 +1576,18 @@ class DrupalWebTestCase extends DrupalTestCase {
* which is likely different than the $path parameter used for retrieving
* the initial form. Defaults to 'system/ajax'.
* - triggering_element: If the value for the 'path' key is 'system/ajax' or
- * another generic AJAX processing path, this needs to be set to the '/'
- * separated path to the element within the server's cached $form array.
- * The callback for the generic AJAX processing path uses this to find
- * the #ajax information for the element, including which specific
- * callback to use for processing the request.
+ * another generic AJAX processing path, this needs to be set to the name
+ * of the element. If the name doesn't identify the element uniquely, then
+ * this should instead be an array with a single key/value pair,
+ * corresponding to the element name and value. The callback for the
+ * generic AJAX processing path uses this to find the #ajax information
+ * for the element, including which specific callback to use for
+ * processing the request.
+ *
+ * This can also be set to NULL in order to emulate an Internet Explorer
+ * submission of a form with a single text field, and pressing ENTER in that
+ * textfield: under these conditions, no button information is added to the
+ * POST data.
* @param $options
* Options to be forwarded to url().
* @param $headers
@@ -1622,7 +1629,7 @@ class DrupalWebTestCase extends DrupalTestCase {
// We post only if we managed to handle every field in edit and the
// submit button matches.
- if (!$edit && $submit_matches) {
+ if (!$edit && ($submit_matches || !isset($submit))) {
$post_array = $post;
if ($upload) {
// TODO: cURL handles file uploads for us, but the implementation
@@ -1643,7 +1650,14 @@ class DrupalWebTestCase extends DrupalTestCase {
$post[$key] = urlencode($key) . '=' . urlencode($value);
}
if ($ajax && isset($submit['triggering_element'])) {
- $post['ajax_triggering_element'] = 'ajax_triggering_element=' . urlencode($submit['triggering_element']);
+ if (is_array($submit['triggering_element'])) {
+ // Get the first key/value pair in the array.
+ $post['_triggering_element_value'] = '_triggering_element_value=' . urlencode(reset($submit['triggering_element']));
+ $post['_triggering_element_name'] = '_triggering_element_name=' . urlencode(key($submit['triggering_element']));
+ }
+ else {
+ $post['_triggering_element_name'] = '_triggering_element_name=' . urlencode($submit['triggering_element']);
+ }
}
$post = implode('&', $post);
}
@@ -1666,7 +1680,7 @@ class DrupalWebTestCase extends DrupalTestCase {
foreach ($edit as $name => $value) {
$this->fail(t('Failed to set field @name to @value', array('@name' => $name, '@value' => $value)));
}
- if (!$ajax) {
+ if (!$ajax && isset($submit)) {
$this->assertTrue($submit_matches, t('Found the @submit button', array('@submit' => $submit)));
}
$this->fail(t('Found the requested form fields at @path', array('@path' => $path)));
@@ -1856,7 +1870,7 @@ class DrupalWebTestCase extends DrupalTestCase {
break;
case 'submit':
case 'image':
- if ($submit == $value) {
+ if (isset($submit) && $submit == $value) {
$post[$name] = $value;
$submit_matches = TRUE;
}
diff --git a/modules/simpletest/tests/ajax.test b/modules/simpletest/tests/ajax.test
index d959a4def..ca6f718dd 100644
--- a/modules/simpletest/tests/ajax.test
+++ b/modules/simpletest/tests/ajax.test
@@ -98,62 +98,62 @@ class AJAXCommandsTestCase extends AJAXTestCase {
$edit = array();
// Tests the 'after' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'after_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'After': Click to put something after the div"))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'insert' && $command['method'] == 'after' && $command['data'] == 'This will be placed after', "'after' AJAX command issued with correct data");
// Tests the 'alert' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'alert_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'Alert': Click to alert"))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'alert' && $command['text'] == 'Alert', "'alert' AJAX Command issued with correct text");
// Tests the 'append' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'append_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'Append': Click to append something"))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'insert' && $command['method'] == 'append' && $command['data'] == 'Appended text', "'append' AJAX command issued with correct data");
// Tests the 'before' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'before_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'before': Click to put something before the div"))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'insert' && $command['method'] == 'before' && $command['data'] == 'Before text', "'before' AJAX command issued with correct data");
// Tests the 'changed' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'changed_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX changed: Click to mark div changed."))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'changed' && $command['selector'] == '#changed_div', "'changed' AJAX command issued with correct selector");
// Tests the 'changed' command using the second argument.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'changed_command_asterisk_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX changed: Click to mark div changed with asterisk."))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'changed' && $command['selector'] == '#changed_div' && $command['asterisk'] == '#changed_div_mark_this', "'changed' AJAX command (with asterisk) issued with correct selector");
// Tests the 'css' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'css_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("Set the the '#box' div to be blue."))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'css' && $command['selector'] == '#css_div' && $command['argument']['background-color'] == 'blue', "'css' AJAX command issued with correct selector");
// Tests the 'data' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'data_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX data command: Issue command."))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'data' && $command['name'] == 'testkey' && $command['value'] == 'testvalue', "'data' AJAX command issued with correct key and value");
// Tests the 'html' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'html_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX html: Replace the HTML in a selector."))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'insert' && $command['method'] == 'html' && $command['data'] == 'replacement text', "'html' AJAX command issued with correct data");
// Tests the 'prepend' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'prepend_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'prepend': Click to prepend something"))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'insert' && $command['method'] == 'prepend' && $command['data'] == 'prepended text', "'prepend' AJAX command issued with correct data");
// Tests the 'remove' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'remove_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'remove': Click to remove text"))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'remove' && $command['selector'] == '#remove_text', "'remove' AJAX command issued with correct command and selector");
// Tests the 'restripe' command.
- $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, 'restripe_command_example'));
+ $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'restripe' command"))));
$command = $commands[0];
$this->assertTrue($command['command'] == 'restripe' && $command['selector'] == '#restripe_table', "'restripe' AJAX command issued with correct selector");
}
@@ -203,3 +203,37 @@ class AJAXFormValuesTestCase extends AJAXTestCase {
}
}
}
+
+
+/**
+ * Miscellaneous AJAX tests using ajax_test module.
+ */
+class AJAXElementValidation extends AJAXTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Miscellaneous AJAX tests',
+ 'description' => 'Various tests of AJAX behavior',
+ 'group' => 'AJAX',
+ );
+ }
+
+ /**
+ * Try to post an AJAX change to a form that has a validated element.
+ *
+ * The drivertext field is AJAX-enabled. An additional field is not, but
+ * is set to be a required field. In this test the required field is not
+ * filled in, and we want to see if the activation of the "drivertext"
+ * AJAX-enabled field fails due to the required field being empty.
+ */
+ function testAJAXElementValidation() {
+ $web_user = $this->drupalCreateUser();
+ $edit = array('drivertext' => t('some dumb text'));
+
+ // Post with 'drivertext' as the triggering element.
+ $post_result = $this->drupalPostAJAX('ajax_validation_test', $edit, 'drivertext');
+ // Look for a validation failure in the resultant JSON.
+ $this->assertNoText(t('Error message'), t("No error message in resultant JSON"));
+ $this->assertText('ajax_forms_test_validation_form_callback invoked', t('The correct callback was invoked'));
+ }
+}
+
diff --git a/modules/simpletest/tests/ajax_forms_test.module b/modules/simpletest/tests/ajax_forms_test.module
index 040a1d9b8..5de2b842c 100644
--- a/modules/simpletest/tests/ajax_forms_test.module
+++ b/modules/simpletest/tests/ajax_forms_test.module
@@ -24,6 +24,12 @@ function ajax_forms_test_menu() {
'page arguments' => array('ajax_forms_test_ajax_commands_form'),
'access callback' => TRUE,
);
+ $items['ajax_validation_test'] = array(
+ 'title' => 'AJAX Validation Test',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ajax_forms_test_validation_form'),
+ 'access callback' => TRUE,
+ );
return $items;
}
@@ -340,3 +346,59 @@ function ajax_forms_test_advanced_commands_restripe_callback($form, $form_state)
$commands[] = ajax_command_restripe('#restripe_table');
return array('#type' => 'ajax', '#commands' => $commands);
}
+
+
+
+/**
+ * This form and its related submit and callback functions demonstrate
+ * not validating another form element when a single AJAX element is triggered.
+ *
+ * The "drivertext" element is an AJAX-enabled textfield, free-form.
+ * The "required_field" element is a textfield marked required.
+ *
+ * The correct behavior is that the AJAX-enabled drivertext element should
+ * be able to trigger without causing validation of the "required_field".
+ */
+function ajax_forms_test_validation_form($form, &$form_state) {
+
+ $form['drivertext'] = array(
+ '#title' => t('AJAX-enabled textfield.'),
+ '#description' => t("When this one AJAX-triggers and the spare required field is empty, you should not get an error."),
+ '#type' => 'textfield',
+ '#default_value' => !empty($form_state['values']['drivertext']) ? $form_state['values']['drivertext'] : "",
+ '#ajax' => array(
+ 'callback' => 'ajax_forms_test_validation_form_callback',
+ 'wrapper' => 'message_area',
+ 'method' => 'replace',
+ ),
+ '#suffix' => '<div id="message_area"></div>',
+ );
+
+ $form['spare_required_field'] = array(
+ '#title' => t("Spare Required Field"),
+ '#type' => 'textfield',
+ '#required' => TRUE,
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Submit'),
+ );
+
+ return $form;
+}
+/**
+ * Submit handler for the validation form.
+ */
+function ajax_forms_test_validation_form_submit($form, $form_state) {
+ drupal_set_message(t("Validation form submitted"));
+}
+
+/**
+ * AJAX callback for the 'drivertext' element of the validation form.
+ */
+function ajax_forms_test_validation_form_callback($form, $form_state) {
+ drupal_set_message("ajax_forms_test_validation_form_callback invoked");
+ drupal_set_message(t("Callback: drivertext=%drivertext, spare_required_field=%spare_required_field", array('%drivertext' => $form_state['values']['drivertext'], '%spare_required_field' => $form_state['values']['spare_required_field'])));
+ return '<div id="message_area">ajax_forms_test_validation_form_callback at ' . date('c') . '</div>';
+}
diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test
index 3c447d14d..4683fb8d4 100644
--- a/modules/simpletest/tests/form.test
+++ b/modules/simpletest/tests/form.test
@@ -850,6 +850,77 @@ class FormsProgrammaticTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Test that FAPI correctly determines $form_state['clicked_button'].
+ */
+class FormsClickedButtonTestCase extends DrupalWebTestCase {
+
+ function getInfo() {
+ return array(
+ 'name' => 'Form clicked button determination',
+ 'description' => 'Test the determination of $form_state[\'clicked_button\'].',
+ 'group' => 'Form API',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('form_test');
+ }
+
+ /**
+ * Test the determination of $form_state['clicked_button'] when no button
+ * information is included in the POST data, as is sometimes the case when
+ * the ENTER key is pressed in a textfield in Internet Explorer.
+ */
+ function testNoButtonInfoInPost() {
+ $path = 'form-test/clicked-button';
+ $edit = array();
+ $form_id = 'form-test-clicked-button';
+
+ // Ensure submitting a form with no buttons results in no
+ // $form_state['clicked_button'] and the form submit handler not running.
+ drupal_static_reset('drupal_html_id');
+ $this->drupalPost($path, $edit, NULL, array(), array(), $form_id);
+ $this->assertText('There is no clicked button.', t('$form_state[\'clicked_button\'] set to NULL.'));
+ $this->assertNoText('Submit handler for form_test_clicked_button executed.', t('Form submit handler did not execute.'));
+
+ // Ensure submitting a form with one or more submit buttons results in
+ // $form_state['clicked_button'] being set to the first one the user has
+ // access to. An argument with 'r' in it indicates a restricted
+ // (#access=FALSE) button.
+ drupal_static_reset('drupal_html_id');
+ $this->drupalPost($path . '/s', $edit, NULL, array(), array(), $form_id);
+ $this->assertText('The clicked button is button1.', t('$form_state[\'clicked_button\'] set to only button.'));
+ $this->assertText('Submit handler for form_test_clicked_button executed.', t('Form submit handler executed.'));
+ drupal_static_reset('drupal_html_id');
+ $this->drupalPost($path . '/s/s', $edit, NULL, array(), array(), $form_id);
+ $this->assertText('The clicked button is button1.', t('$form_state[\'clicked_button\'] set to first button.'));
+ $this->assertText('Submit handler for form_test_clicked_button executed.', t('Form submit handler executed.'));
+ drupal_static_reset('drupal_html_id');
+ $this->drupalPost($path . '/rs/s', $edit, NULL, array(), array(), $form_id);
+ $this->assertText('The clicked button is button2.', t('$form_state[\'clicked_button\'] set to first available button.'));
+ $this->assertText('Submit handler for form_test_clicked_button executed.', t('Form submit handler executed.'));
+
+ // Ensure submitting a form with buttons of different types results in
+ // $form_state['clicked_button'] being set to the first button, regardless
+ // of type. For the FAPI 'button' type, this should result in the submit
+ // handler not executing. The types are 's'(ubmit), 'b'(utton), and
+ // 'i'(mage_button).
+ drupal_static_reset('drupal_html_id');
+ $this->drupalPost($path . '/s/b/i', $edit, NULL, array(), array(), $form_id);
+ $this->assertText('The clicked button is button1.', t('$form_state[\'clicked_button\'] set to first button.'));
+ $this->assertText('Submit handler for form_test_clicked_button executed.', t('Form submit handler executed.'));
+ drupal_static_reset('drupal_html_id');
+ $this->drupalPost($path . '/b/s/i', $edit, NULL, array(), array(), $form_id);
+ $this->assertText('The clicked button is button1.', t('$form_state[\'clicked_button\'] set to first button.'));
+ $this->assertNoText('Submit handler for form_test_clicked_button executed.', t('Form submit handler did not execute.'));
+ drupal_static_reset('drupal_html_id');
+ $this->drupalPost($path . '/i/s/b', $edit, NULL, array(), array(), $form_id);
+ $this->assertText('The clicked button is button1.', t('$form_state[\'clicked_button\'] set to first button.'));
+ $this->assertText('Submit handler for form_test_clicked_button executed.', t('Form submit handler executed.'));
+ }
+}
+
/**
* Tests rebuilding of arbitrary forms by altering them.
diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module
index ad9be7032..b35e43251 100644
--- a/modules/simpletest/tests/form_test.module
+++ b/modules/simpletest/tests/form_test.module
@@ -118,6 +118,14 @@ function form_test_menu() {
'type' => MENU_CALLBACK,
);
+ $items['form-test/clicked-button'] = array(
+ 'title' => 'Clicked button test',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('form_test_clicked_button'),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+
return $items;
}
@@ -923,6 +931,84 @@ function form_test_programmatic_form_submit($form, &$form_state) {
$form_state['storage']['programmatic_form_submit'] = $form_state['values']['submitted_field'];
}
+/**
+ * Form builder to test button click detection.
+ */
+function form_test_clicked_button($form, &$form_state) {
+ // A single text field. In IE, when a form has only one non-button input field
+ // and the ENTER key is pressed while that field has focus, the form is
+ // submitted without any information identifying the button responsible for
+ // the submission. In other browsers, the form is submitted as though the
+ // first button were clicked.
+ $form['text'] = array(
+ '#title' => 'Text',
+ '#type' => 'textfield',
+ );
+
+ // Loop through each path argument, addding buttons based on the information
+ // in the argument. For example, if the path is
+ // form-test/clicked-button/s/i/rb, then 3 buttons are added: a 'submit', an
+ // 'image_button', and a 'button' with #access=FALSE. This enables form.test
+ // to test a variety of combinations.
+ $i=0;
+ $args = array_slice(arg(), 2);
+ foreach ($args as $arg) {
+ $name = 'button' . ++$i;
+ // 's', 'b', or 'i' in the argument define the button type wanted.
+ if (strpos($arg, 's') !== FALSE) {
+ $type = 'submit';
+ }
+ elseif (strpos($arg, 'b') !== FALSE) {
+ $type = 'button';
+ }
+ elseif (strpos($arg, 'i') !== FALSE) {
+ $type = 'image_button';
+ }
+ else {
+ $type = NULL;
+ }
+ if (isset($type)) {
+ $form[$name] = array(
+ '#type' => $type,
+ '#name' => $name,
+ );
+ // Image buttons need a #src; the others need a #value.
+ if ($type == 'image_button') {
+ $form[$name]['#src'] = 'misc/druplicon.png';
+ }
+ else {
+ $form[$name]['#value'] = $name;
+ }
+ // 'r' for restricted, so we can test that button click detection code
+ // correctly takes #access security into account.
+ if (strpos($arg, 'r') !== FALSE) {
+ $form[$name]['#access'] = FALSE;
+ }
+ }
+ }
+
+ return $form;
+}
+
+/**
+ * Form validation handler for the form_test_clicked_button() form.
+ */
+function form_test_clicked_button_validate($form, &$form_state) {
+ if (isset($form_state['clicked_button'])) {
+ drupal_set_message(t('The clicked button is %name.', array('%name' => $form_state['clicked_button']['#name'])));
+ }
+ else {
+ drupal_set_message('There is no clicked button.');
+ }
+}
+
+/**
+ * Form submit handler for the form_test_clicked_button() form.
+ */
+function form_test_clicked_button_submit($form, &$form_state) {
+ drupal_set_message('Submit handler for form_test_clicked_button executed.');
+}
+
/**
* Implements hook_form_FORM_ID_alter() for the registration form.