field_ui.test 31 KB

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