Newer
Older
<?php
class AJAXTestCase extends DrupalWebTestCase {
Dries Buytaert
committed
function setUp() {
$modules = func_get_args();
if (isset($modules[0]) && is_array($modules[0])) {
$modules = $modules[0];
}
Dries Buytaert
committed
parent::setUp(array_unique(array_merge(array('ajax_test', 'ajax_forms_test'), $modules)));
Dries Buytaert
committed
/**
* Assert that a command with the required properties exists within the array of Ajax commands returned by the server.
Dries Buytaert
committed
*
* The Ajax framework, via the ajax_deliver() and ajax_render() functions,
Dries Buytaert
committed
* returns an array of commands. This array sometimes includes commands
* automatically provided by the framework in addition to commands returned by
* a particular page callback. During testing, we're usually interested that a
* particular command is present, and don't care whether other commands
* precede or follow the one we're interested in. Additionally, the command
* we're interested in may include additional data that we're not interested
* in. Therefore, this function simply asserts that one of the commands in
* $haystack contains all of the keys and values in $needle. Furthermore, if
* $needle contains a 'settings' key with an array value, we simply assert
* that all keys and values within that array are present in the command we're
* checking, and do not consider it a failure if the actual command contains
* additional settings that aren't part of $needle.
*
* @param $haystack
* An array of Ajax commands returned by the server.
Dries Buytaert
committed
* @param $needle
* Array of info we're expecting in one of those commands.
* @param $message
* An assertion message.
Dries Buytaert
committed
*/
Dries Buytaert
committed
protected function assertCommand($haystack, $needle, $message) {
$found = FALSE;
foreach ($haystack as $command) {
// If the command has additional settings that we're not testing for, do
// not consider that a failure.
if (isset($command['settings']) && is_array($command['settings']) && isset($needle['settings']) && is_array($needle['settings'])) {
$command['settings'] = array_intersect_key($command['settings'], $needle['settings']);
}
// If the command has additional data that we're not testing for, do not
// consider that a failure. Also, == instead of ===, because we don't
// require the key/value pairs to be in any particular order
// (http://www.php.net/manual/en/language.operators.array.php).
if (array_intersect_key($command, $needle) == $needle) {
$found = TRUE;
break;
}
Dries Buytaert
committed
}
Dries Buytaert
committed
$this->assertTrue($found, $message);
Dries Buytaert
committed
}
* Tests primary Ajax framework functions.
*/
class AJAXFrameworkTestCase extends AJAXTestCase {
Dries Buytaert
committed
protected $profile = 'testing';
Dries Buytaert
committed
public static function getInfo() {
return array(
'name' => 'AJAX framework',
'description' => 'Performs tests on AJAX framework functions.',
'group' => 'AJAX',
);
}
/**
Dries Buytaert
committed
* Test that ajax_render() returns JavaScript settings generated during the page request.
*
* @todo Add tests to ensure that ajax_render() returns commands for new CSS
* and JavaScript files to be loaded by the page. See
* http://drupal.org/node/561858.
*/
function testAJAXRender() {
Dries Buytaert
committed
$commands = $this->drupalGetAJAX('ajax-test/render');
// Verify that there is a command to load settings added with
// drupal_add_js().
$expected = array(
'command' => 'settings',
'settings' => array('basePath' => base_path(), 'ajax' => 'test'),
);
$this->assertCommand($commands, $expected, t('ajax_render() loads settings added with drupal_add_js().'));
Dries Buytaert
committed
// Verify that Ajax settings are loaded for #type 'link'.
Dries Buytaert
committed
$this->drupalGet('ajax-test/link');
$settings = $this->drupalGetSettings();
$this->assertEqual($settings['ajax']['ajax-link']['url'], url('filter/tips'));
$this->assertEqual($settings['ajax']['ajax-link']['wrapper'], 'block-system-main');
}
/**
* Test behavior of ajax_render_error().
*/
function testAJAXRenderError() {
// Verify default error message.
Dries Buytaert
committed
$commands = $this->drupalGetAJAX('ajax-test/render-error');
$expected = array(
'command' => 'alert',
'text' => t('An error occurred while handling the request: The server received invalid input.'),
);
$this->assertCommand($commands, $expected, t('ajax_render_error() invokes alert command.'));
// Verify custom error message.
$edit = array(
'message' => 'Custom error message.',
);
Dries Buytaert
committed
$commands = $this->drupalGetAJAX('ajax-test/render-error', array('query' => $edit));
$expected = array(
'command' => 'alert',
'text' => $edit['message'],
);
$this->assertCommand($commands, $expected, t('Custom error message is output.'));
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/**
* Test that new JavaScript and CSS files added during an AJAX request are returned.
*/
function testLazyLoad() {
$expected = array(
'setting_name' => 'ajax_forms_test_lazy_load_form_submit',
'setting_value' => 'executed',
'css' => drupal_get_path('module', 'system') . '/system.admin.css',
'js' => drupal_get_path('module', 'system') . '/system.js',
);
// Get the base page.
$this->drupalGet('ajax_forms_test_lazy_load_form');
$original_settings = $this->drupalGetSettings();
$original_css = $original_settings['ajaxPageState']['css'];
$original_js = $original_settings['ajaxPageState']['js'];
// Verify that the base page doesn't have the settings and files that are to
// be lazy loaded as part of the next request.
$this->assertTrue(!isset($original_settings[$expected['setting_name']]), t('Page originally lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
$this->assertTrue(!isset($original_settings[$expected['css']]), t('Page originally lacks the %css file, as expected.', array('%css' => $expected['css'])));
$this->assertTrue(!isset($original_settings[$expected['js']]), t('Page originally lacks the %js file, as expected.', array('%js' => $expected['js'])));
// Submit the AJAX request.
$commands = $this->drupalPostAJAX(NULL, array(), array('op' => t('Submit')));
$new_settings = $this->drupalGetSettings();
$new_css = $new_settings['ajaxPageState']['css'];
$new_js = $new_settings['ajaxPageState']['js'];
// Verify the expected setting was added.
$this->assertIdentical($new_settings[$expected['setting_name']], $expected['setting_value'], t('Page now has the %setting.', array('%setting' => $expected['setting_name'])));
// Verify the expected CSS file was added, both to Drupal.settings, and as
// an AJAX command for inclusion into the HTML.
// @todo A drupal_css_defaults() function in Drupal 8 would be nice.
$expected_css_html = drupal_get_css(array($expected['css'] => array(
'type' => 'file',
'group' => CSS_DEFAULT,
'weight' => 0,
'every_page' => FALSE,
'media' => 'all',
'preprocess' => TRUE,
'data' => $expected['css'],
'browsers' => array('IE' => TRUE, '!IE' => TRUE),
)), TRUE);
$this->assertEqual($new_css, $original_css + array($expected['css'] => 1), t('Page state now has the %css file.', array('%css' => $expected['css'])));
$this->assertCommand($commands, array('data' => $expected_css_html), t('Page now has the %css file.', array('%css' => $expected['css'])));
// Verify the expected JS file was added, both to Drupal.settings, and as
// an AJAX command for inclusion into the HTML. By testing for an exact HTML
// string containing the SCRIPT tag, we also ensure that unexpected
// JavaScript code, such as a jQuery.extend() that would potentially clobber
// rather than properly merge settings, didn't accidentally get added.
$expected_js_html = drupal_get_js('header', array($expected['js'] => drupal_js_defaults($expected['js'])), TRUE);
$this->assertEqual($new_js, $original_js + array($expected['js'] => 1), t('Page state now has the %js file.', array('%js' => $expected['js'])));
$this->assertCommand($commands, array('data' => $expected_js_html), t('Page now has the %js file.', array('%js' => $expected['js'])));
}
* Tests Ajax framework commands.
*/
class AJAXCommandsTestCase extends AJAXTestCase {
Dries Buytaert
committed
public static function getInfo() {
return array(
'name' => 'AJAX commands',
'description' => 'Performs tests on AJAX framework commands.',
'group' => 'AJAX',
);
}
Angie Byron
committed
/**
* Test the various Ajax Commands.
Angie Byron
committed
*/
function testAJAXCommands() {
$form_path = 'ajax_forms_test_ajax_commands_form';
$web_user = $this->drupalCreateUser(array('access content'));
$this->drupalLogin($web_user);
$edit = array();
// Tests the 'after' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'After': Click to put something after the div")));
$expected = array(
'command' => 'insert',
'method' => 'after',
'data' => 'This will be placed after',
);
$this->assertCommand($commands, $expected, "'after' AJAX command issued with correct data");
Angie Byron
committed
// Tests the 'alert' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'Alert': Click to alert")));
$expected = array(
'command' => 'alert',
'text' => 'Alert',
);
$this->assertCommand($commands, $expected, "'alert' AJAX Command issued with correct text");
Angie Byron
committed
// Tests the 'append' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'Append': Click to append something")));
$expected = array(
'command' => 'insert',
'method' => 'append',
'data' => 'Appended text',
);
$this->assertCommand($commands, $expected, "'append' AJAX command issued with correct data");
Angie Byron
committed
// Tests the 'before' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'before': Click to put something before the div")));
$expected = array(
'command' => 'insert',
'method' => 'before',
'data' => 'Before text',
);
$this->assertCommand($commands, $expected, "'before' AJAX command issued with correct data");
Angie Byron
committed
// Tests the 'changed' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX changed: Click to mark div changed.")));
$expected = array(
'command' => 'changed',
'selector' => '#changed_div',
);
$this->assertCommand($commands, $expected, "'changed' AJAX command issued with correct selector");
Angie Byron
committed
// Tests the 'changed' command using the second argument.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX changed: Click to mark div changed with asterisk.")));
$expected = array(
'command' => 'changed',
'selector' => '#changed_div',
'asterisk' => '#changed_div_mark_this',
);
$this->assertCommand($commands, $expected, "'changed' AJAX command (with asterisk) issued with correct selector");
// Tests the 'css' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("Set the the '#box' div to be blue.")));
$expected = array(
'command' => 'css',
'selector' => '#css_div',
'argument' => array('background-color' => 'blue'),
);
$this->assertCommand($commands, $expected, "'css' AJAX command issued with correct selector");
Angie Byron
committed
// Tests the 'data' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX data command: Issue command.")));
$expected = array(
'command' => 'data',
'name' => 'testkey',
'value' => 'testvalue',
);
$this->assertCommand($commands, $expected, "'data' AJAX command issued with correct key and value");
Angie Byron
committed
Angie Byron
committed
// Tests the 'invoke' command.
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX invoke command: Invoke addClass() method.")));
$expected = array(
'command' => 'invoke',
'method' => 'addClass',
'arguments' => array('error'),
);
$this->assertCommand($commands, $expected, "'invoke' AJAX command issued with correct method and argument");
Angie Byron
committed
// Tests the 'html' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX html: Replace the HTML in a selector.")));
$expected = array(
'command' => 'insert',
'method' => 'html',
'data' => 'replacement text',
);
$this->assertCommand($commands, $expected, "'html' AJAX command issued with correct data");
Angie Byron
committed
Dries Buytaert
committed
// Tests the 'insert' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX insert: Let client insert based on #ajax['method'].")));
$expected = array(
'command' => 'insert',
'data' => 'insert replacement text',
);
$this->assertCommand($commands, $expected, "'insert' AJAX command issued with correct data");
Dries Buytaert
committed
Angie Byron
committed
// Tests the 'prepend' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'prepend': Click to prepend something")));
$expected = array(
'command' => 'insert',
'method' => 'prepend',
'data' => 'prepended text',
);
$this->assertCommand($commands, $expected, "'prepend' AJAX command issued with correct data");
Angie Byron
committed
// Tests the 'remove' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'remove': Click to remove text")));
$expected = array(
'command' => 'remove',
'selector' => '#remove_text',
);
$this->assertCommand($commands, $expected, "'remove' AJAX command issued with correct command and selector");
Angie Byron
committed
// Tests the 'restripe' command.
Dries Buytaert
committed
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'restripe' command")));
$expected = array(
'command' => 'restripe',
'selector' => '#restripe_table',
);
$this->assertCommand($commands, $expected, "'restripe' AJAX command issued with correct selector");
// Tests the 'settings' command.
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'settings' command")));
$expected = array(
'command' => 'settings',
'settings' => array('ajax_forms_test' => array('foo' => 42)),
);
$this->assertCommand($commands, $expected, "'settings' AJAX command issued with correct data");
Angie Byron
committed
}
}
Dries Buytaert
committed
/**
* Test that $form_state['values'] is properly delivered to $ajax['callback'].
*/
class AJAXFormValuesTestCase extends AJAXTestCase {
public static function getInfo() {
return array(
'name' => 'AJAX command form values',
'description' => 'Tests that form values are properly delivered to AJAX callbacks.',
'group' => 'AJAX',
);
}
function setUp() {
parent::setUp();
$this->web_user = $this->drupalCreateUser(array('access content'));
$this->drupalLogin($this->web_user);
}
/**
* Create a simple form, then POST to system/ajax to change to it.
*/
function testSimpleAJAXFormValue() {
// Verify form values of a select element.
Dries Buytaert
committed
foreach (array('red', 'green', 'blue') as $item) {
Dries Buytaert
committed
$edit = array(
'select' => $item,
);
Dries Buytaert
committed
$commands = $this->drupalPostAJAX('ajax_forms_test_get_form', $edit, 'select');
$expected = array(
'command' => 'data',
'value' => $item,
);
$this->assertCommand($commands, $expected, "verification of AJAX form values from a selectbox issued with a correct value");
Dries Buytaert
committed
}
// Verify form values of a checkbox element.
Dries Buytaert
committed
foreach (array(FALSE, TRUE) as $item) {
Dries Buytaert
committed
$edit = array(
'checkbox' => $item,
);
Dries Buytaert
committed
$commands = $this->drupalPostAJAX('ajax_forms_test_get_form', $edit, 'checkbox');
$expected = array(
'command' => 'data',
'value' => (int) $item,
);
$this->assertCommand($commands, $expected, "verification of AJAX form values from a checkbox issued with a correct value");
Dries Buytaert
committed
}
}
}
Dries Buytaert
committed
/**
* Tests that Ajax-enabled forms work when multiple instances of the same form are on a page.
Dries Buytaert
committed
*/
class AJAXMultiFormTestCase extends AJAXTestCase {
public static function getInfo() {
return array(
'name' => 'AJAX multi form',
'description' => 'Tests that AJAX-enabled forms work when multiple instances of the same form are on a page.',
'group' => 'AJAX',
);
}
function setUp() {
parent::setUp(array('form_test'));
// Create a multi-valued field for 'page' nodes to use for Ajax testing.
Dries Buytaert
committed
$field_name = 'field_ajax_test';
$field = array(
'field_name' => $field_name,
'type' => 'text',
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
);
field_create_field($field);
$instance = array(
'field_name' => $field_name,
'entity_type' => 'node',
'bundle' => 'page',
);
field_create_instance($instance);
// Login a user who can create 'page' nodes.
$this->web_user = $this->drupalCreateUser(array('create page content'));
$this->drupalLogin($this->web_user);
}
/**
* Test that a page with the 'page_node_form' included twice works correctly.
*/
function testMultiForm() {
// HTML IDs for elements within the field are potentially modified with
// each Ajax submission, but these variables are stable and help target the
Dries Buytaert
committed
// desired elements.
$field_name = 'field_ajax_test';
$field_xpaths = array(
'page-node-form' => '//form[@id="page-node-form"]//div[contains(@class, "field-name-field-ajax-test")]',
'page-node-form--2' => '//form[@id="page-node-form--2"]//div[contains(@class, "field-name-field-ajax-test")]',
);
$button_name = $field_name . '_add_more';
$button_value = t('Add another item');
$button_xpath_suffix = '//input[@name="' . $button_name . '"]';
$field_items_xpath_suffix = '//input[@type="text"]';
// Ensure the initial page contains both node forms and the correct number
// of field items and "add more" button for the multi-valued field within
// each form.
$this->drupalGet('form-test/two-instances-of-same-form');
Dries Buytaert
committed
foreach ($field_xpaths as $form_html_id => $field_xpath) {
$this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == 1, t('Found the correct number of field items on the initial page.'));
$this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button on the initial page.'));
Dries Buytaert
committed
}
Dries Buytaert
committed
$this->assertNoDuplicateIds(t('Initial page contains unique IDs'), 'Other');
Dries Buytaert
committed
// Submit the "add more" button of each form twice. After each corresponding
Dries Buytaert
committed
// page update, ensure the same as above.
foreach ($field_xpaths as $form_html_id => $field_xpath) {
Dries Buytaert
committed
for ($i = 0; $i < 2; $i++) {
Dries Buytaert
committed
$this->drupalPostAJAX(NULL, array(), array($button_name => $button_value), 'system/ajax', array(), array(), $form_html_id);
$this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == $i+2, t('Found the correct number of field items after an AJAX submission.'));
$this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button after an AJAX submission.'));
Dries Buytaert
committed
$this->assertNoDuplicateIds(t('Updated page contains unique IDs'), 'Other');
Dries Buytaert
committed
}
}
}
}
/**
* 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'));