Newer
Older
<?php
// $Id$
/**
* @file
* Unit tests for the Drupal Form API.
*/
class FormsTestCase extends DrupalWebTestCase {
Angie Byron
committed
public static function getInfo() {
return array(
'name' => 'Required field validation',
'description' => 'Carriage returns, tabs, and spaces are not valid content for a required field.',
'group' => 'Form API',
);
}
/**
* Check several empty values for required forms elements.
*
* If the form field is found in form_get_errors() then the test pass.
*/
function testRequiredFields() {
// Originates from http://drupal.org/node/117748
// Sets of empty strings and arrays
$empty_strings = array('""' => "", '"\n"' => "\n", '" "' => " ", '"\t"' => "\t", '" \n\t "' => " \n\t ", '"\n\n\n\n\n"' => "\n\n\n\n\n");
$empty_arrays = array('array()' => array());
$elements['textfield']['element'] = array('#title' => $this->randomName(), '#type' => 'textfield', '#required' => TRUE);
$elements['textfield']['empty_values'] = $empty_strings;
$elements['password']['element'] = array('#title' => $this->randomName(), '#type' => 'password', '#required' => TRUE);
$elements['password']['empty_values'] = $empty_strings;
$elements['password_confirm']['element'] = array('#title' => $this->randomName(), '#type' => 'password_confirm', '#required' => TRUE);
$elements['password_confirm']['empty_values'] = $empty_strings;
$elements['textarea']['element'] = array('#title' => $this->randomName(), '#type' => 'textarea', '#required' => TRUE);
$elements['textarea']['empty_values'] = $empty_strings;
$elements['radios']['element'] = array('#title' => $this->randomName(), '#type' => 'radios', '#required' => TRUE, '#options' => array($this->randomName(), $this->randomName(), $this->randomName()));
$elements['radios']['empty_values'] = $empty_arrays;
$elements['checkboxes']['element'] = array('#title' => $this->randomName(), '#type' => 'checkboxes', '#required' => TRUE, '#options' => array($this->randomName(), $this->randomName(), $this->randomName()));
$elements['checkboxes']['empty_values'] = $empty_arrays;
$elements['select']['element'] = array('#title' => $this->randomName(), '#type' => 'select', '#required' => TRUE, '#options' => array($this->randomName(), $this->randomName(), $this->randomName()));
$elements['select']['empty_values'] = $empty_strings;
$elements['file']['element'] = array('#title' => $this->randomName(), '#type' => 'file', '#required' => TRUE);
$elements['file']['empty_values'] = $empty_strings;
// Go through all the elements and all the empty values for them
foreach ($elements as $type => $data) {
foreach ($data['empty_values'] as $key => $empty) {
$form_id = $this->randomName();
$form = $form_state = array();
$form['op'] = array('#type' => 'submit', '#value' => t('Submit'));
$element = $data['element']['#title'];
$form[$element] = $data['element'];
$form_state['values'][$element] = $empty;
Dries Buytaert
committed
$form_state['input'] = $form_state['values'];
$form_state['input']['form_id'] = $form_id;
$form_state['method'] = 'post';
drupal_prepare_form($form_id, $form, $form_state);
drupal_process_form($form_id, $form, $form_state);
$errors = form_get_errors();
$this->assertTrue(isset($errors[$element]), "Check empty($key) '$type' field '$element'");
}
}
// Clear the expected form error messages so they don't appear as exceptions.
drupal_get_messages();
}
}
/**
* Test form type functions for expected behavior.
*/
Dries Buytaert
committed
class FormsTestTypeCase extends DrupalUnitTestCase {
Angie Byron
committed
public static function getInfo() {
'name' => 'Form type-specific tests',
'description' => 'Test form type functions for expected behavior.',
'group' => 'Form API',
);
}
/**
* Test form_type_checkbox_value() function for expected behavior.
*/
function testFormCheckboxValue() {
$form['#return_value'] = $return_value = $this->randomName();
$form['#default_value'] = $default_value = $this->randomName();
// Element is disabled , and $edit is not empty.
$form['#disabled'] = TRUE;
$edit = array(1);
$this->assertEqual(form_type_checkbox_value($form, $edit), $default_value, t('form_type_checkbox_value() returns the default value when #disabled is set.'));
// Element is not disabled, $edit is not empty.
unset($form['#disabled']);
$this->assertEqual(form_type_checkbox_value($form, $edit), $return_value, t('form_type_checkbox_value() returns the return value when #disabled is not set.'));
// Element is not disabled, $edit is empty.
$edit = array();
$this->assertIdentical(form_type_checkbox_value($form, $edit), 0, t('form_type_checkbox_value() returns 0 when #disabled is not set, and $edit is empty.'));
// $edit is FALSE.
$edit = FALSE;
$this->assertNull(form_type_checkbox_value($form, $edit), t('form_type_checkbox_value() returns NULL when $edit is FALSE'));
}
}
Angie Byron
committed
/**
* Test the tableselect form element for expected behavior.
*/
class FormsElementsTableSelectFunctionalTest extends DrupalWebTestCase {
Angie Byron
committed
public static function getInfo() {
Angie Byron
committed
return array(
'name' => 'Tableselect form element type test',
'description' => 'Test the tableselect element for expected behavior',
'group' => 'Form API',
Angie Byron
committed
);
}
function setUp() {
parent::setUp('form_test');
}
/**
* Test the display of checkboxes when #multiple is TRUE.
*/
function testMultipleTrue() {
$this->drupalGet('form_test/tableselect/multiple-true');
$this->assertNoText(t('Empty text.'), t('Empty text should not be displayed.'));
// Test for the presence of the Select all rows tableheader.
$this->assertFieldByXPath('//th[@class="select-all"]', NULL, t('Presence of the "Select all" checkbox.'));
$rows = array('row1', 'row2', 'row3');
foreach ($rows as $row) {
Angie Byron
committed
$this->assertFieldByXPath('//input[@type="checkbox"]', $row, t('Checkbox for value @row.', array('@row' => $row)));
}
}
/**
* Test the display of radios when #multiple is FALSE.
*/
function testMultipleFalse() {
$this->drupalGet('form_test/tableselect/multiple-false');
$this->assertNoText(t('Empty text.'), t('Empty text should not be displayed.'));
// Test for the absence of the Select all rows tableheader.
$this->assertNoFieldByXPath('//th[@class="select-all"]', '', t('Absence of the "Select all" checkbox.'));
$rows = array('row1', 'row2', 'row3');
foreach ($rows as $row) {
Angie Byron
committed
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
$this->assertFieldByXPath('//input[@type="radio"]', $row, t('Radio button for value @row.', array('@row' => $row)));
}
}
/**
* Test the display of the #empty text when #options is an empty array.
*/
function testEmptyText() {
$this->drupalGet('form_test/tableselect/empty-text');
$this->assertText(t('Empty text.'), t('Empty text should be displayed.'));
}
/**
* Test the submission of single and multiple values when #multiple is TRUE.
*/
function testMultipleTrueSubmit() {
// Test a submission with one checkbox checked.
$edit = array();
$edit['tableselect[row1]'] = TRUE;
$this->drupalPost('form_test/tableselect/multiple-true', $edit, 'Submit');
$this->assertText(t('Submitted: row1 = row1'), t('Checked checkbox row1'));
$this->assertText(t('Submitted: row2 = 0'), t('Unchecked checkbox row2.'));
$this->assertText(t('Submitted: row3 = 0'), t('Unchecked checkbox row3.'));
// Test a submission with multiple checkboxes checked.
$edit['tableselect[row1]'] = TRUE;
$edit['tableselect[row3]'] = TRUE;
$this->drupalPost('form_test/tableselect/multiple-true', $edit, 'Submit');
$this->assertText(t('Submitted: row1 = row1'), t('Checked checkbox row1.'));
$this->assertText(t('Submitted: row2 = 0'), t('Unchecked checkbox row2.'));
$this->assertText(t('Submitted: row3 = row3'), t('Checked checkbox row3.'));
}
/**
* Test submission of values when #multiple is FALSE.
*/
function testMultipleFalseSubmit() {
$edit['tableselect'] = 'row1';
$this->drupalPost('form_test/tableselect/multiple-false', $edit, 'Submit');
$this->assertText(t('Submitted: row1'), t('Selected radio button'));
}
/**
* Test the #js_select property.
*/
function testAdvancedSelect() {
// When #multiple = TRUE a Select all checkbox should be displayed by default.
$this->drupalGet('form_test/tableselect/advanced-select/multiple-true-default');
$this->assertFieldByXPath('//th[@class="select-all"]', NULL, t('Display a "Select all" checkbox by default when #multiple is TRUE.'));
// When #js_select is set to FALSE, a "Select all" checkbox should not be displayed.
$this->drupalGet('form_test/tableselect/advanced-select/multiple-true-no-advanced-select');
$this->assertNoFieldByXPath('//th[@class="select-all"]', NULL, t('Do not display a "Select all" checkbox when #js_select is FALSE.'));
// A "Select all" checkbox never makes sense when #multiple = FALSE, regardless of the value of #js_select.
$this->drupalGet('form_test/tableselect/advanced-select/multiple-false-default');
$this->assertNoFieldByXPath('//th[@class="select-all"]', NULL, t('Do not display a "Select all" checkbox when #multiple is FALSE.'));
$this->drupalGet('form_test/tableselect/advanced-select/multiple-false-advanced-select');
$this->assertNoFieldByXPath('//th[@class="select-all"]', NULL, t('Do not display a "Select all" checkbox when #multiple is FALSE, even when #js_select is TRUE.'));
}
/**
* Test the whether the option checker gives an error on invalid tableselect values for checkboxes.
*/
function testMultipleTrueOptionchecker() {
list($header, $options) = _form_test_tableselect_get_data();
$form['tableselect'] = array(
'#type' => 'tableselect',
'#header' => $header,
'#options' => $options,
);
// Test with a valid value.
list($processed_form, $form_state, $errors) = $this->formSubmitHelper($form, array('tableselect' => 'row1'));
$this->assertFalse(isset($errors['tableselect']), t('Option checker allows valid values for checkboxes.'));
// Test with an invalid value.
list($processed_form, $form_state, $errors) = $this->formSubmitHelper($form, array('tableselect' => 'non_existing_value'));
$this->assertTrue(isset($errors['tableselect']), t('Option checker disallows invalid values for checkboxes.'));
}
/**
* Test the whether the option checker gives an error on invalid tableselect values for radios.
*/
function testMultipleFalseOptionchecker() {
list($header, $options) = _form_test_tableselect_get_data();
$form['tableselect'] = array(
'#type' => 'tableselect',
'#header' => $header,
'#options' => $options,
'#multiple' => FALSE,
);
// Test with a valid value.
list($processed_form, $form_state, $errors) = $this->formSubmitHelper($form, array('tableselect' => 'row1'));
$this->assertFalse(isset($errors['tableselect']), t('Option checker allows valid values for radio buttons.'));
// Test with an invalid value.
list($processed_form, $form_state, $errors) = $this->formSubmitHelper($form, array('tableselect' => 'non_existing_value'));
$this->assertTrue(isset($errors['tableselect']), t('Option checker disallows invalid values for radio buttons.'));
}
/**
* Helper function for the option check test to submit a form while collecting errors.
*
* @param $form_element
* A form element to test.
* @param $edit
* An array containing post data.
*
* @return
* An array containing the processed form, the form_state and any errors.
*/
private function formSubmitHelper($form_element, $edit) {
$form_id = $this->randomName();
Dries Buytaert
committed
$form_state = form_state_defaults();
$form = array();
Angie Byron
committed
$form = array_merge($form, $form_element);
$form['op'] = array('#type' => 'submit', '#value' => t('Submit'));
Dries Buytaert
committed
$form_state['input'] = $edit;
$form_state['input']['form_id'] = $form_id;
Angie Byron
committed
drupal_prepare_form($form_id, $form, $form_state);
drupal_process_form($form_id, $form, $form_state);
$errors = form_get_errors();
// Clear errors and messages.
drupal_get_messages();
Dries Buytaert
committed
form_clear_error();
Angie Byron
committed
// Return the processed form together with form_state and errors
// to allow the caller lowlevel access to the form.
return array($form, $form_state, $errors);
}
}
Angie Byron
committed
/**
* Test the form_clean_id() for expected behavior.
*/
class FormsFormCleanIdFunctionalTest extends DrupalWebTestCase {
Angie Byron
committed
public static function getInfo() {
Angie Byron
committed
return array(
'name' => 'form_clean_id() test',
'description' => 'Test the function form_clean_id() for expected behavior',
'group' => 'Form API',
Angie Byron
committed
);
}
function setUp() {
parent::setUp('form_test');
}
/**
* Test the uniqueness of the form_clean_id() function.
*/
function testFormCleanId() {
$this->drupalGet('form_test/form_clean_id');
$this->assertNoUniqueText('form-test-form-clean-id-presence');
$this->assertUniqueText('form-test-form-clean-id-presence-1');
$this->assertUniqueText('form-test-form-clean-id-presence-2');
$this->assertNoUniqueText('Test Textfield');
}
}
Angie Byron
committed
/**
Dries Buytaert
committed
* Test using drupal_form_submit in a batch.
Angie Byron
committed
*/
class FormAPITestCase extends DrupalWebTestCase {
Angie Byron
committed
public static function getInfo() {
Angie Byron
committed
return array(
'name' => 'Drupal Execute and Batch API',
'description' => 'Tests the compatibility of drupal_form_submit and the Batch API',
'group' => 'Form API',
Angie Byron
committed
);
}
/**
Dries Buytaert
committed
* Check that we can run drupal_form_submit during a batch.
Angie Byron
committed
*/
Dries Buytaert
committed
function testDrupalFormSubmitInBatch() {
Angie Byron
committed
// Our test is going to modify the following variable.
variable_set('form_test_mock_submit', 'initial_state');
Dries Buytaert
committed
// This is a page that sets a batch, which calls drupal_form_submit, which
Angie Byron
committed
// modifies the variable we set up above.
Dries Buytaert
committed
$this->drupalGet('form_test/drupal_form_submit_batch_api');
Angie Byron
committed
Dries Buytaert
committed
// If the drupal_form_submit call executed correctly our test variable will be
Angie Byron
committed
// set to 'form_submitted'.
Dries Buytaert
committed
$this->assertEqual('form_submitted', variable_get('form_test_mock_submit', 'initial_state'), t('Check drupal_form_submit called submit handlers when running in a batch'));
Angie Byron
committed
// Clean our variable up.
variable_del('form_test_mock_submit');
}
function setUp() {
parent::setUp('form_test');
}
}
Dries Buytaert
committed
/**
* Test the form storage on a multistep form.
*
* The tested form puts data into the storage during the initial form
* construction. These tests verify that there are no duplicate form
* constructions, with and without manual form caching activiated. Furthermore
* when a validation error occurs, it makes sure that changed form element
* values aren't lost due to a wrong form rebuild.
*/
class FormsFormStorageTestCase extends DrupalWebTestCase {
public static function getInfo() {
Dries Buytaert
committed
return array(
'name' => 'Multistep form using form storage',
'description' => 'Tests a multistep form using form storage and makes sure validation and caching works right.',
'group' => 'Form API',
Dries Buytaert
committed
);
}
function setUp() {
parent::setUp('form_test');
}
/**
* Tests using the form in a usual way.
*/
function testForm() {
Dries Buytaert
committed
$user = $this->drupalCreateUser(array('access content'));
$this->drupalLogin($user);
$this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue');
$this->assertText('Form constructions: 2', t('The form has been constructed two times till now.'));
$this->drupalPost(NULL, array(), 'Save');
$this->assertText('Form constructions: 3', t('The form has been constructed three times till now.'));
$this->assertText('Title: new', t('The form storage has stored the values.'));
}
/**
* Tests using the form with an activated #cache property.
*/
function testFormCached() {
$user = $this->drupalCreateUser(array('access content'));
$this->drupalLogin($user);
$this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue', array('query' => 'cache=1'));
$this->assertText('Form constructions: 1', t('The form has been constructed one time till now.'));
Dries Buytaert
committed
$this->drupalPost(NULL, array(), 'Save', array('query' => 'cache=1'));
$this->assertText('Form constructions: 2', t('The form has been constructed two times till now.'));
$this->assertText('Title: new', t('The form storage has stored the values.'));
}
/**
* Tests validation when form storage is used.
*/
function testValidation() {
$user = $this->drupalCreateUser(array('access content'));
$this->drupalLogin($user);
$this->drupalPost('form_test/form-storage', array('title' => '', 'value' => 'value_is_set'), 'Continue');
$this->assertPattern('/value_is_set/', t("The input values have been kept."));
}
}
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
/**
* Test wrapper form callbacks.
*/
class FormsFormWrapperTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Form wrapper callback',
'description' => 'Tests form wrapper callbacks to pass a prebuilt form to form builder functions.',
'group' => 'Form API',
);
}
function setUp() {
parent::setUp('form_test');
}
/**
* Tests using the form in a usual way.
*/
function testWrapperCallback() {
$this->drupalGet('form_test/wrapper-callback');
$this->assertText('Form wrapper callback element output.', t('The form contains form wrapper elements.'));
$this->assertText('Form builder element output.', t('The form contains form builder elements.'));
}
}