field_ui.test 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. <?php
  2. /**
  3. * @file
  4. * Tests for field_ui.module.
  5. */
  6. /**
  7. * Provides common functionality for the Field UI test classes.
  8. */
  9. class FieldUITestCase extends DrupalWebTestCase {
  10. function setUp() {
  11. // Since this is a base class for many test cases, support the same
  12. // flexibility that DrupalWebTestCase::setUp() has for the modules to be
  13. // passed in as either an array or a variable number of string arguments.
  14. $modules = func_get_args();
  15. if (isset($modules[0]) && is_array($modules[0])) {
  16. $modules = $modules[0];
  17. }
  18. $modules[] = 'field_test';
  19. parent::setUp($modules);
  20. // Create test user.
  21. $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy'));
  22. $this->drupalLogin($admin_user);
  23. // Create content type, with underscores.
  24. $type_name = strtolower($this->randomName(8)) . '_test';
  25. $type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
  26. $this->type = $type->type;
  27. // Store a valid URL name, with hyphens instead of underscores.
  28. $this->hyphen_type = str_replace('_', '-', $this->type);
  29. }
  30. /**
  31. * Creates a new field through the Field UI.
  32. *
  33. * @param $bundle_path
  34. * Admin path of the bundle that the new field is to be attached to.
  35. * @param $initial_edit
  36. * $edit parameter for drupalPost() on the first step ('Manage fields'
  37. * screen).
  38. * @param $field_edit
  39. * $edit parameter for drupalPost() on the second step ('Field settings'
  40. * form).
  41. * @param $instance_edit
  42. * $edit parameter for drupalPost() on the third step ('Instance settings'
  43. * form).
  44. */
  45. function fieldUIAddNewField($bundle_path, $initial_edit, $field_edit = array(), $instance_edit = array()) {
  46. // Use 'test_field' field type by default.
  47. $initial_edit += array(
  48. 'fields[_add_new_field][type]' => 'test_field',
  49. 'fields[_add_new_field][widget_type]' => 'test_field_widget',
  50. );
  51. $label = $initial_edit['fields[_add_new_field][label]'];
  52. $field_name = $initial_edit['fields[_add_new_field][field_name]'];
  53. // First step : 'Add new field' on the 'Manage fields' page.
  54. $this->drupalPost("$bundle_path/fields", $initial_edit, t('Save'));
  55. $this->assertRaw(t('These settings apply to the %label field everywhere it is used.', array('%label' => $label)), 'Field settings page was displayed.');
  56. // Second step : 'Field settings' form.
  57. $this->drupalPost(NULL, $field_edit, t('Save field settings'));
  58. $this->assertRaw(t('Updated field %label field settings.', array('%label' => $label)), 'Redirected to instance and widget settings page.');
  59. // Third step : 'Instance settings' form.
  60. $this->drupalPost(NULL, $instance_edit, t('Save settings'));
  61. $this->assertRaw(t('Saved %label configuration.', array('%label' => $label)), 'Redirected to "Manage fields" page.');
  62. // Check that the field appears in the overview form.
  63. $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $label, 'Field was created and appears in the overview page.');
  64. }
  65. /**
  66. * Adds an existing field through the Field UI.
  67. *
  68. * @param $bundle_path
  69. * Admin path of the bundle that the field is to be attached to.
  70. * @param $initial_edit
  71. * $edit parameter for drupalPost() on the first step ('Manage fields'
  72. * screen).
  73. * @param $instance_edit
  74. * $edit parameter for drupalPost() on the second step ('Instance settings'
  75. * form).
  76. */
  77. function fieldUIAddExistingField($bundle_path, $initial_edit, $instance_edit = array()) {
  78. // Use 'test_field_widget' by default.
  79. $initial_edit += array(
  80. 'fields[_add_existing_field][widget_type]' => 'test_field_widget',
  81. );
  82. $label = $initial_edit['fields[_add_existing_field][label]'];
  83. $field_name = $initial_edit['fields[_add_existing_field][field_name]'];
  84. // First step : 'Add existing field' on the 'Manage fields' page.
  85. $this->drupalPost("$bundle_path/fields", $initial_edit, t('Save'));
  86. // Second step : 'Instance settings' form.
  87. $this->drupalPost(NULL, $instance_edit, t('Save settings'));
  88. $this->assertRaw(t('Saved %label configuration.', array('%label' => $label)), 'Redirected to "Manage fields" page.');
  89. // Check that the field appears in the overview form.
  90. $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $label, 'Field was created and appears in the overview page.');
  91. }
  92. /**
  93. * Deletes a field instance through the Field UI.
  94. *
  95. * @param $bundle_path
  96. * Admin path of the bundle that the field instance is to be deleted from.
  97. * @param $field_name
  98. * The name of the field.
  99. * @param $label
  100. * The label of the field.
  101. * @param $bundle_label
  102. * The label of the bundle.
  103. */
  104. function fieldUIDeleteField($bundle_path, $field_name, $label, $bundle_label) {
  105. // Display confirmation form.
  106. $this->drupalGet("$bundle_path/fields/$field_name/delete");
  107. $this->assertRaw(t('Are you sure you want to delete the field %label', array('%label' => $label)), 'Delete confirmation was found.');
  108. // Submit confirmation form.
  109. $this->drupalPost(NULL, array(), t('Delete'));
  110. $this->assertRaw(t('The field %label has been deleted from the %type content type.', array('%label' => $label, '%type' => $bundle_label)), 'Delete message was found.');
  111. // Check that the field does not appear in the overview form.
  112. $this->assertNoFieldByXPath('//table[@id="field-overview"]//span[@class="label-field"]', $label, 'Field does not appear in the overview page.');
  113. }
  114. }
  115. /**
  116. * Tests the functionality of the 'Manage fields' screen.
  117. */
  118. class FieldUIManageFieldsTestCase extends FieldUITestCase {
  119. public static function getInfo() {
  120. return array(
  121. 'name' => 'Manage fields',
  122. 'description' => 'Test the Field UI "Manage fields" screen.',
  123. 'group' => 'Field UI',
  124. );
  125. }
  126. function setUp() {
  127. parent::setUp();
  128. // Create random field name.
  129. $this->field_label = $this->randomName(8);
  130. $this->field_name_input = strtolower($this->randomName(8));
  131. $this->field_name = 'field_'. $this->field_name_input;
  132. }
  133. /**
  134. * Runs the field CRUD tests.
  135. *
  136. * In order to act on the same fields, and not create the fields over and over
  137. * again the following tests create, update and delete the same fields.
  138. */
  139. function testCRUDFields() {
  140. $this->manageFieldsPage();
  141. $this->createField();
  142. $this->updateField();
  143. $this->addExistingField();
  144. }
  145. /**
  146. * Tests the manage fields page.
  147. */
  148. function manageFieldsPage() {
  149. $this->drupalGet('admin/structure/types/manage/' . $this->hyphen_type . '/fields');
  150. // Check all table columns.
  151. $table_headers = array(
  152. t('Label'),
  153. t('Machine name'),
  154. t('Field type'),
  155. t('Widget'),
  156. t('Operations'),
  157. );
  158. foreach ($table_headers as $table_header) {
  159. // We check that the label appear in the table headings.
  160. $this->assertRaw($table_header . '</th>', format_string('%table_header table header was found.', array('%table_header' => $table_header)));
  161. }
  162. // "Add new field" and "Add existing field" aren't a table heading so just
  163. // test the text.
  164. foreach (array('Add new field', 'Add existing field') as $element) {
  165. $this->assertText($element, format_string('"@element" was found.', array('@element' => $element)));
  166. }
  167. }
  168. /**
  169. * Tests adding a new field.
  170. *
  171. * @todo Assert properties can bet set in the form and read back in $field and
  172. * $instances.
  173. */
  174. function createField() {
  175. // Create a test field.
  176. $edit = array(
  177. 'fields[_add_new_field][label]' => $this->field_label,
  178. 'fields[_add_new_field][field_name]' => $this->field_name_input,
  179. );
  180. $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->hyphen_type, $edit);
  181. // Assert the field appears in the "add existing field" section for
  182. // different entity types; e.g. if a field was added in a node entity, it
  183. // should also appear in the 'taxonomy term' entity.
  184. $vocabulary = taxonomy_vocabulary_load(1);
  185. $this->drupalGet('admin/structure/taxonomy/' . $vocabulary->machine_name . '/fields');
  186. $this->assertTrue($this->xpath('//select[@name="fields[_add_existing_field][field_name]"]//option[@value="' . $this->field_name . '"]'), 'Existing field was found in account settings.');
  187. }
  188. /**
  189. * Tests editing an existing field.
  190. */
  191. function updateField() {
  192. // Go to the field edit page.
  193. $this->drupalGet('admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $this->field_name);
  194. // Populate the field settings with new settings.
  195. $string = 'updated dummy test string';
  196. $edit = array(
  197. 'field[settings][test_field_setting]' => $string,
  198. 'instance[settings][test_instance_setting]' => $string,
  199. 'instance[widget][settings][test_widget_setting]' => $string,
  200. );
  201. $this->drupalPost(NULL, $edit, t('Save settings'));
  202. // Assert the field settings are correct.
  203. $this->assertFieldSettings($this->type, $this->field_name, $string);
  204. // Assert redirection back to the "manage fields" page.
  205. $this->assertText(t('Saved @label configuration.', array('@label' => $this->field_label)), 'Redirected to "Manage fields" page.');
  206. }
  207. /**
  208. * Tests adding an existing field in another content type.
  209. */
  210. function addExistingField() {
  211. // Check "Add existing field" appears.
  212. $this->drupalGet('admin/structure/types/manage/page/fields');
  213. $this->assertRaw(t('Add existing field'), '"Add existing field" was found.');
  214. // Check that the list of options respects entity type restrictions on
  215. // fields. The 'comment' field is restricted to the 'comment' entity type
  216. // and should not appear in the list.
  217. $this->assertFalse($this->xpath('//select[@id="edit-add-existing-field-field-name"]//option[@value="comment"]'), 'The list of options respects entity type restrictions.');
  218. // Add a new field based on an existing field.
  219. $edit = array(
  220. 'fields[_add_existing_field][label]' => $this->field_label . '_2',
  221. 'fields[_add_existing_field][field_name]' => $this->field_name,
  222. );
  223. $this->fieldUIAddExistingField("admin/structure/types/manage/page", $edit);
  224. }
  225. /**
  226. * Asserts field settings are as expected.
  227. *
  228. * @param $bundle
  229. * The bundle name for the instance.
  230. * @param $field_name
  231. * The field name for the instance.
  232. * @param $string
  233. * The settings text.
  234. * @param $entity_type
  235. * The entity type for the instance.
  236. */
  237. function assertFieldSettings($bundle, $field_name, $string = 'dummy test string', $entity_type = 'node') {
  238. // Reset the fields info.
  239. field_info_cache_clear();
  240. // Assert field settings.
  241. $field = field_info_field($field_name);
  242. $this->assertTrue($field['settings']['test_field_setting'] == $string, 'Field settings were found.');
  243. // Assert instance and widget settings.
  244. $instance = field_info_instance($entity_type, $field_name, $bundle);
  245. $this->assertTrue($instance['settings']['test_instance_setting'] == $string, 'Field instance settings were found.');
  246. $this->assertTrue($instance['widget']['settings']['test_widget_setting'] == $string, 'Field widget settings were found.');
  247. }
  248. /**
  249. * Tests that default value is correctly validated and saved.
  250. */
  251. function testDefaultValue() {
  252. // Create a test field and instance.
  253. $field_name = 'test';
  254. $field = array(
  255. 'field_name' => $field_name,
  256. 'type' => 'test_field'
  257. );
  258. field_create_field($field);
  259. $instance = array(
  260. 'field_name' => $field_name,
  261. 'entity_type' => 'node',
  262. 'bundle' => $this->type,
  263. );
  264. field_create_instance($instance);
  265. $langcode = LANGUAGE_NONE;
  266. $admin_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $field_name;
  267. $element_id = "edit-$field_name-$langcode-0-value";
  268. $element_name = "{$field_name}[$langcode][0][value]";
  269. $this->drupalGet($admin_path);
  270. $this->assertFieldById($element_id, '', 'The default value widget was empty.');
  271. // Check that invalid default values are rejected.
  272. $edit = array($element_name => '-1');
  273. $this->drupalPost($admin_path, $edit, t('Save settings'));
  274. $this->assertText("$field_name does not accept the value -1", 'Form vaildation failed.');
  275. // Check that the default value is saved.
  276. $edit = array($element_name => '1');
  277. $this->drupalPost($admin_path, $edit, t('Save settings'));
  278. $this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
  279. $instance = field_info_instance('node', $field_name, $this->type);
  280. $this->assertEqual($instance['default_value'], array(array('value' => 1)), 'The default value was correctly saved.');
  281. // Check that the default value shows up in the form
  282. $this->drupalGet($admin_path);
  283. $this->assertFieldById($element_id, '1', 'The default value widget was displayed with the correct value.');
  284. // Check that the default value can be emptied.
  285. $edit = array($element_name => '');
  286. $this->drupalPost(NULL, $edit, t('Save settings'));
  287. $this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
  288. field_info_cache_clear();
  289. $instance = field_info_instance('node', $field_name, $this->type);
  290. $this->assertEqual($instance['default_value'], NULL, 'The default value was correctly saved.');
  291. }
  292. /**
  293. * Tests that deletion removes fields and instances as expected.
  294. */
  295. function testDeleteField() {
  296. // Create a new field.
  297. $bundle_path1 = 'admin/structure/types/manage/' . $this->hyphen_type;
  298. $edit1 = array(
  299. 'fields[_add_new_field][label]' => $this->field_label,
  300. 'fields[_add_new_field][field_name]' => $this->field_name_input,
  301. );
  302. $this->fieldUIAddNewField($bundle_path1, $edit1);
  303. // Create an additional node type.
  304. $type_name2 = strtolower($this->randomName(8)) . '_test';
  305. $type2 = $this->drupalCreateContentType(array('name' => $type_name2, 'type' => $type_name2));
  306. $type_name2 = $type2->type;
  307. $hyphen_type2 = str_replace('_', '-', $type_name2);
  308. // Add an instance to the second node type.
  309. $bundle_path2 = 'admin/structure/types/manage/' . $hyphen_type2;
  310. $edit2 = array(
  311. 'fields[_add_existing_field][label]' => $this->field_label,
  312. 'fields[_add_existing_field][field_name]' => $this->field_name,
  313. );
  314. $this->fieldUIAddExistingField($bundle_path2, $edit2);
  315. // Delete the first instance.
  316. $this->fieldUIDeleteField($bundle_path1, $this->field_name, $this->field_label, $this->type);
  317. // Reset the fields info.
  318. field_info_cache_clear();
  319. // Check that the field instance was deleted.
  320. $this->assertNull(field_info_instance('node', $this->field_name, $this->type), 'Field instance was deleted.');
  321. // Check that the field was not deleted
  322. $this->assertNotNull(field_info_field($this->field_name), 'Field was not deleted.');
  323. // Delete the second instance.
  324. $this->fieldUIDeleteField($bundle_path2, $this->field_name, $this->field_label, $type_name2);
  325. // Reset the fields info.
  326. field_info_cache_clear();
  327. // Check that the field instance was deleted.
  328. $this->assertNull(field_info_instance('node', $this->field_name, $type_name2), 'Field instance was deleted.');
  329. // Check that the field was deleted too.
  330. $this->assertNull(field_info_field($this->field_name), 'Field was deleted.');
  331. }
  332. /**
  333. * Tests that Field UI respects the 'no_ui' option in hook_field_info().
  334. */
  335. function testHiddenFields() {
  336. $bundle_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/';
  337. // Check that the field type is not available in the 'add new field' row.
  338. $this->drupalGet($bundle_path);
  339. $this->assertFalse($this->xpath('//select[@id="edit-add-new-field-type"]//option[@value="hidden_test_field"]'), "The 'add new field' select respects field types 'no_ui' property.");
  340. // Create a field and an instance programmatically.
  341. $field_name = 'hidden_test_field';
  342. field_create_field(array('field_name' => $field_name, 'type' => $field_name));
  343. $instance = array(
  344. 'field_name' => $field_name,
  345. 'bundle' => $this->type,
  346. 'entity_type' => 'node',
  347. 'label' => t('Hidden field'),
  348. 'widget' => array('type' => 'test_field_widget'),
  349. );
  350. field_create_instance($instance);
  351. $this->assertTrue(field_read_instance('node', $field_name, $this->type), format_string('An instance of the field %field was created programmatically.', array('%field' => $field_name)));
  352. // Check that the newly added instance appears on the 'Manage Fields'
  353. // screen.
  354. $this->drupalGet($bundle_path);
  355. $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $instance['label'], 'Field was created and appears in the overview page.');
  356. // Check that the instance does not appear in the 'add existing field' row
  357. // on other bundles.
  358. $bundle_path = 'admin/structure/types/manage/article/fields/';
  359. $this->drupalGet($bundle_path);
  360. $this->assertFalse($this->xpath('//select[@id="edit-add-existing-field-field-name"]//option[@value=:field_name]', array(':field_name' => $field_name)), "The 'add existing field' select respects field types 'no_ui' property.");
  361. }
  362. /**
  363. * Tests renaming a bundle.
  364. */
  365. function testRenameBundle() {
  366. $type2 = strtolower($this->randomName(8)) . '_' .'test';
  367. $hyphen_type2 = str_replace('_', '-', $type2);
  368. $options = array(
  369. 'type' => $type2,
  370. );
  371. $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type, $options, t('Save content type'));
  372. $this->drupalGet('admin/structure/types/manage/' . $hyphen_type2 . '/fields');
  373. }
  374. /**
  375. * Tests that a duplicate field name is caught by validation.
  376. */
  377. function testDuplicateFieldName() {
  378. // field_tags already exists, so we're expecting an error when trying to
  379. // create a new field with the same name.
  380. $edit = array(
  381. 'fields[_add_new_field][field_name]' => 'tags',
  382. 'fields[_add_new_field][label]' => $this->randomName(),
  383. 'fields[_add_new_field][type]' => 'taxonomy_term_reference',
  384. 'fields[_add_new_field][widget_type]' => 'options_select',
  385. );
  386. $url = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields';
  387. $this->drupalPost($url, $edit, t('Save'));
  388. $this->assertText(t('The machine-readable name is already in use. It must be unique.'));
  389. $this->assertUrl($url, array(), 'Stayed on the same page.');
  390. }
  391. }
  392. /**
  393. * Tests the functionality of the 'Manage display' screens.
  394. */
  395. class FieldUIManageDisplayTestCase extends FieldUITestCase {
  396. public static function getInfo() {
  397. return array(
  398. 'name' => 'Manage display',
  399. 'description' => 'Test the Field UI "Manage display" screens.',
  400. 'group' => 'Field UI',
  401. );
  402. }
  403. function setUp() {
  404. parent::setUp(array('search'));
  405. }
  406. /**
  407. * Tests formatter settings.
  408. */
  409. function testFormatterUI() {
  410. $manage_fields = 'admin/structure/types/manage/' . $this->hyphen_type;
  411. $manage_display = $manage_fields . '/display';
  412. // Create a field, and a node with some data for the field.
  413. $edit = array(
  414. 'fields[_add_new_field][label]' => 'Test field',
  415. 'fields[_add_new_field][field_name]' => 'test',
  416. );
  417. $this->fieldUIAddNewField($manage_fields, $edit);
  418. // Clear the test-side cache and get the saved field instance.
  419. field_info_cache_clear();
  420. $instance = field_info_instance('node', 'field_test', $this->type);
  421. $format = $instance['display']['default']['type'];
  422. $default_settings = field_info_formatter_settings($format);
  423. $setting_name = key($default_settings);
  424. $setting_value = $instance['display']['default']['settings'][$setting_name];
  425. // Display the "Manage display" screen and check that the expected formatter is
  426. // selected.
  427. $this->drupalGet($manage_display);
  428. $this->assertFieldByName('fields[field_test][type]', $format, 'The expected formatter is selected.');
  429. $this->assertText("$setting_name: $setting_value", 'The expected summary is displayed.');
  430. // Change the formatter and check that the summary is updated.
  431. $edit = array('fields[field_test][type]' => 'field_test_multiple', 'refresh_rows' => 'field_test');
  432. $this->drupalPostAJAX(NULL, $edit, array('op' => t('Refresh')));
  433. $format = 'field_test_multiple';
  434. $default_settings = field_info_formatter_settings($format);
  435. $setting_name = key($default_settings);
  436. $setting_value = $default_settings[$setting_name];
  437. $this->assertFieldByName('fields[field_test][type]', $format, 'The expected formatter is selected.');
  438. $this->assertText("$setting_name: $setting_value", 'The expected summary is displayed.');
  439. // Submit the form and check that the instance is updated.
  440. $this->drupalPost(NULL, array(), t('Save'));
  441. field_info_cache_clear();
  442. $instance = field_info_instance('node', 'field_test', $this->type);
  443. $current_format = $instance['display']['default']['type'];
  444. $current_setting_value = $instance['display']['default']['settings'][$setting_name];
  445. $this->assertEqual($current_format, $format, 'The formatter was updated.');
  446. $this->assertEqual($current_setting_value, $setting_value, 'The setting was updated.');
  447. }
  448. /**
  449. * Tests switching view modes to use custom or 'default' settings'.
  450. */
  451. function testViewModeCustom() {
  452. // Create a field, and a node with some data for the field.
  453. $edit = array(
  454. 'fields[_add_new_field][label]' => 'Test field',
  455. 'fields[_add_new_field][field_name]' => 'test',
  456. );
  457. $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->hyphen_type, $edit);
  458. // For this test, use a formatter setting value that is an integer unlikely
  459. // to appear in a rendered node other than as part of the field being tested
  460. // (for example, unlikely to be part of the "Submitted by ... on ..." line).
  461. $value = 12345;
  462. $settings = array(
  463. 'type' => $this->type,
  464. 'field_test' => array(LANGUAGE_NONE => array(array('value' => $value))),
  465. );
  466. $node = $this->drupalCreateNode($settings);
  467. // Gather expected output values with the various formatters.
  468. $formatters = field_info_formatter_types();
  469. $output = array(
  470. 'field_test_default' => $formatters['field_test_default']['settings']['test_formatter_setting'] . '|' . $value,
  471. 'field_test_with_prepare_view' => $formatters['field_test_with_prepare_view']['settings']['test_formatter_setting_additional'] . '|' . $value. '|' . ($value + 1),
  472. );
  473. // Check that the field is displayed with the default formatter in 'rss'
  474. // mode (uses 'default'), and hidden in 'teaser' mode (uses custom settings).
  475. $this->assertNodeViewText($node, 'rss', $output['field_test_default'], "The field is displayed as expected in view modes that use 'default' settings.");
  476. $this->assertNodeViewNoText($node, 'teaser', $value, "The field is hidden in view modes that use custom settings.");
  477. // Change fomatter for 'default' mode, check that the field is displayed
  478. // accordingly in 'rss' mode.
  479. $edit = array(
  480. 'fields[field_test][type]' => 'field_test_with_prepare_view',
  481. );
  482. $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save'));
  483. $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], "The field is displayed as expected in view modes that use 'default' settings.");
  484. // Specialize the 'rss' mode, check that the field is displayed the same.
  485. $edit = array(
  486. "view_modes_custom[rss]" => TRUE,
  487. );
  488. $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save'));
  489. $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], "The field is displayed as expected in newly specialized 'rss' mode.");
  490. // Set the field to 'hidden' in the view mode, check that the field is
  491. // hidden.
  492. $edit = array(
  493. 'fields[field_test][type]' => 'hidden',
  494. );
  495. $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display/rss', $edit, t('Save'));
  496. $this->assertNodeViewNoText($node, 'rss', $value, "The field is hidden in 'rss' mode.");
  497. // Set the view mode back to 'default', check that the field is displayed
  498. // accordingly.
  499. $edit = array(
  500. "view_modes_custom[rss]" => FALSE,
  501. );
  502. $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save'));
  503. $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], "The field is displayed as expected when 'rss' mode is set back to 'default' settings.");
  504. // Specialize the view mode again.
  505. $edit = array(
  506. "view_modes_custom[rss]" => TRUE,
  507. );
  508. $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save'));
  509. // Check that the previous settings for the view mode have been kept.
  510. $this->assertNodeViewNoText($node, 'rss', $value, "The previous settings are kept when 'rss' mode is specialized again.");
  511. }
  512. /**
  513. * Asserts that a string is found in the rendered node in a view mode.
  514. *
  515. * @param $node
  516. * The node.
  517. * @param $view_mode
  518. * The view mode in which the node should be displayed.
  519. * @param $text
  520. * Plain text to look for.
  521. * @param $message
  522. * Message to display.
  523. *
  524. * @return
  525. * TRUE on pass, FALSE on fail.
  526. */
  527. function assertNodeViewText($node, $view_mode, $text, $message) {
  528. return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, FALSE);
  529. }
  530. /**
  531. * Asserts that a string is not found in the rendered node in a view mode.
  532. *
  533. * @param $node
  534. * The node.
  535. * @param $view_mode
  536. * The view mode in which the node should be displayed.
  537. * @param $text
  538. * Plain text to look for.
  539. * @param $message
  540. * Message to display.
  541. * @return
  542. * TRUE on pass, FALSE on fail.
  543. */
  544. function assertNodeViewNoText($node, $view_mode, $text, $message) {
  545. return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, TRUE);
  546. }
  547. /**
  548. * Asserts that a string is (not) found in the rendered nodein a view mode.
  549. *
  550. * This helper function is used by assertNodeViewText() and
  551. * assertNodeViewNoText().
  552. *
  553. * @param $node
  554. * The node.
  555. * @param $view_mode
  556. * The view mode in which the node should be displayed.
  557. * @param $text
  558. * Plain text to look for.
  559. * @param $message
  560. * Message to display.
  561. * @param $not_exists
  562. * TRUE if this text should not exist, FALSE if it should.
  563. *
  564. * @return
  565. * TRUE on pass, FALSE on fail.
  566. */
  567. function assertNodeViewTextHelper($node, $view_mode, $text, $message, $not_exists) {
  568. // Make sure caches on the tester side are refreshed after changes
  569. // submitted on the tested side.
  570. field_info_cache_clear();
  571. // Save current content so that we can restore it when we're done.
  572. $old_content = $this->drupalGetContent();
  573. // Render a cloned node, so that we do not alter the original.
  574. $clone = clone $node;
  575. $element = node_view($clone, $view_mode);
  576. $output = drupal_render($element);
  577. $this->verbose(t('Rendered node - view mode: @view_mode', array('@view_mode' => $view_mode)) . '<hr />'. $output);
  578. // Assign content so that DrupalWebTestCase functions can be used.
  579. $this->drupalSetContent($output);
  580. $method = ($not_exists ? 'assertNoText' : 'assertText');
  581. $return = $this->{$method}((string) $text, $message);
  582. // Restore previous content.
  583. $this->drupalSetContent($old_content);
  584. return $return;
  585. }
  586. }
  587. /**
  588. * Tests custom widget hooks and callbacks on the field administration pages.
  589. */
  590. class FieldUIAlterTestCase extends DrupalWebTestCase {
  591. public static function getInfo() {
  592. return array(
  593. 'name' => 'Widget customization',
  594. 'description' => 'Test custom field widget hooks and callbacks on field administration pages.',
  595. 'group' => 'Field UI',
  596. );
  597. }
  598. function setUp() {
  599. parent::setUp(array('field_test'));
  600. // Create test user.
  601. $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer users'));
  602. $this->drupalLogin($admin_user);
  603. }
  604. /**
  605. * Tests hook_field_widget_properties_alter() on the default field widget.
  606. *
  607. * @see field_test_field_widget_properties_alter()
  608. * @see field_test_field_widget_properties_user_alter()
  609. * @see field_test_field_widget_form_alter()
  610. */
  611. function testDefaultWidgetPropertiesAlter() {
  612. // Create the alter_test_text field and an instance on article nodes.
  613. field_create_field(array(
  614. 'field_name' => 'alter_test_text',
  615. 'type' => 'text',
  616. ));
  617. field_create_instance(array(
  618. 'field_name' => 'alter_test_text',
  619. 'entity_type' => 'node',
  620. 'bundle' => 'article',
  621. 'widget' => array(
  622. 'type' => 'text_textfield',
  623. 'size' => 60,
  624. ),
  625. ));
  626. // Test that field_test_field_widget_properties_alter() sets the size to
  627. // 42 and that field_test_field_widget_form_alter() reports the correct
  628. // size when the form is displayed.
  629. $this->drupalGet('admin/structure/types/manage/article/fields/alter_test_text');
  630. $this->assertText('Field size: 42', 'Altered field size is found in hook_field_widget_form_alter().');
  631. // Create the alter_test_options field.
  632. field_create_field(array(
  633. 'field_name' => 'alter_test_options',
  634. 'type' => 'list_text'
  635. ));
  636. // Create instances on users and page nodes.
  637. field_create_instance(array(
  638. 'field_name' => 'alter_test_options',
  639. 'entity_type' => 'user',
  640. 'bundle' => 'user',
  641. 'widget' => array(
  642. 'type' => 'options_select',
  643. )
  644. ));
  645. field_create_instance(array(
  646. 'field_name' => 'alter_test_options',
  647. 'entity_type' => 'node',
  648. 'bundle' => 'page',
  649. 'widget' => array(
  650. 'type' => 'options_select',
  651. )
  652. ));
  653. // Test that field_test_field_widget_properties_user_alter() replaces
  654. // the widget and that field_test_field_widget_form_alter() reports the
  655. // correct widget name when the form is displayed.
  656. $this->drupalGet('admin/config/people/accounts/fields/alter_test_options');
  657. $this->assertText('Widget type: options_buttons', 'Widget type is altered for users in hook_field_widget_form_alter().');
  658. // Test that the widget is not altered on page nodes.
  659. $this->drupalGet('admin/structure/types/manage/page/fields/alter_test_options');
  660. $this->assertText('Widget type: options_select', 'Widget type is not altered for pages in hook_field_widget_form_alter().');
  661. }
  662. }