profile.test 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. <?php
  2. /**
  3. * @file
  4. * Tests for profile.module.
  5. */
  6. /**
  7. * A class for common methods for testing profile fields.
  8. */
  9. class ProfileTestCase extends DrupalWebTestCase {
  10. protected $admin_user;
  11. protected $normal_user;
  12. function setUp() {
  13. parent::setUp('profile');
  14. variable_set('user_register', USER_REGISTER_VISITORS);
  15. $this->admin_user = $this->drupalCreateUser(array('administer users', 'access user profiles', 'administer blocks'));
  16. // This is the user whose profile will be edited.
  17. $this->normal_user = $this->drupalCreateUser();
  18. }
  19. /**
  20. * Create a profile field.
  21. *
  22. * @param $type
  23. * The field type to be created.
  24. * @param $category
  25. * The category in which the field should be created.
  26. * @param $edit
  27. * Additional parameters to be submitted.
  28. * @return
  29. * The fid of the field that was just created.
  30. */
  31. function createProfileField($type = 'textfield', $category = 'simpletest', $edit = array()) {
  32. $edit['title'] = $title = $this->randomName(8);
  33. $edit['name'] = $form_name = 'profile_' . $title;
  34. $edit['category'] = $category;
  35. $edit['explanation'] = $this->randomName(50);
  36. $this->drupalPost('admin/config/people/profile/add/' . $type, $edit, t('Save field'));
  37. $fid = db_query("SELECT fid FROM {profile_field} WHERE title = :title", array(':title' => $title))->fetchField();
  38. $this->assertTrue($fid, 'New Profile field has been entered in the database');
  39. // Check that the new field is appearing on the user edit form.
  40. $this->drupalGet('user/' . $this->admin_user->uid . '/edit/' . $category);
  41. // Checking field.
  42. if ($type == 'date') {
  43. $this->assertField($form_name . '[month]', 'Found month selection field');
  44. $this->assertField($form_name . '[day]', 'Found day selection field');
  45. $this->assertField($form_name . '[year]', 'Found day selection field');
  46. }
  47. else {
  48. $this->assertField($form_name , format_string('Found form named @name', array('@name' => $form_name)));
  49. }
  50. // Checking name.
  51. $this->assertText($title, format_string('Checking title for field %title', array('%title' => $title)));
  52. // Checking explanation.
  53. $this->assertText($edit['explanation'], format_string('Checking explanation for field %title', array('%title' => $title)));
  54. return array(
  55. 'fid' => $fid,
  56. 'type' => $type,
  57. 'form_name' => $form_name,
  58. 'title' => $title,
  59. 'category' => $category,
  60. );
  61. }
  62. /**
  63. * Update a profile field.
  64. *
  65. * @param $fid
  66. * The fid of the field to be updated.
  67. * @param $type
  68. * The type of field to be updated.
  69. * @param $edit
  70. * Field parameters to be submitted.
  71. * @return
  72. * Array representation of the updated field.
  73. */
  74. function updateProfileField($fid, $type = 'textfield', $edit = array()) {
  75. $form_name = $edit['name'];
  76. $title = $edit['title'];
  77. $category = $edit['category'];
  78. $this->drupalPost('admin/config/people/profile/edit/' . $fid, $edit, t('Save field'));
  79. // Check that the updated field is appearing on the user edit form.
  80. $this->drupalGet('user/' . $this->admin_user->uid . '/edit/' . $category);
  81. // Checking field.
  82. if ($type == 'date') {
  83. $this->assertField($form_name . '[month]', 'Found month selection field');
  84. $this->assertField($form_name . '[day]', 'Found day selection field');
  85. $this->assertField($form_name . '[year]', 'Found day selection field');
  86. }
  87. else {
  88. $this->assertField($form_name , format_string('Found form named @name', array('@name' => $form_name)));
  89. }
  90. // Checking name.
  91. $this->assertText($title, format_string('Checking title for field %title', array('%title' => $title)));
  92. // Checking explanation.
  93. $this->assertText($edit['explanation'], format_string('Checking explanation for field %title', array('%title' => $title)));
  94. return array(
  95. 'fid' => $fid,
  96. 'type' => $type,
  97. 'form_name' => $form_name,
  98. 'title' => $title,
  99. 'category' => $category,
  100. );
  101. }
  102. /**
  103. * Set the profile field to a random value
  104. *
  105. * @param $field
  106. * The field that should be set.
  107. * @param $value
  108. * The value for the field, defaults to a random string.
  109. * @return
  110. * The value that has been assigned to
  111. */
  112. function setProfileField($field, $value = NULL) {
  113. if (!isset($value)) {
  114. $value = $this->randomName();
  115. }
  116. $edit = array(
  117. $field['form_name'] => $value,
  118. );
  119. $this->drupalPost('user/' . $this->normal_user->uid . '/edit/' . $field['category'], $edit, t('Save'));
  120. // Check profile page.
  121. $content = $this->drupalGet('user/' . $this->normal_user->uid);
  122. $this->assertText($field['title'], format_string('Found profile field with title %title', array('%title' => $field['title'])));
  123. if ($field['type'] != 'checkbox') {
  124. // $value must be cast to a string in order to be found by assertText.
  125. $this->assertText("$value", format_string('Found profile field with value %value', array('%value' => $value)));
  126. }
  127. return $value;
  128. }
  129. /**
  130. * Delete a profile field.
  131. *
  132. * @param $field
  133. * The field to be deleted.
  134. */
  135. function deleteProfileField($field) {
  136. $this->drupalPost('admin/config/people/profile/delete/' . $field['fid'], array(), t('Delete'));
  137. $this->drupalGet('admin/config/people/profile');
  138. $this->assertNoText($field['title'], format_string('Checking deleted field %title', array('%title' => $field['title'])));
  139. }
  140. }
  141. class ProfileTestFields extends ProfileTestCase {
  142. public static function getInfo() {
  143. return array(
  144. 'name' => 'Test single fields',
  145. 'description' => 'Testing profile module with add/edit/delete textfield, textarea, list, checkbox, and url fields into profile page',
  146. 'group' => 'Profile'
  147. );
  148. }
  149. /**
  150. * Test each of the field types. List selection and date fields are tested
  151. * separately because they need some special handling.
  152. */
  153. function testProfileFields() {
  154. $this->drupalLogin($this->admin_user);
  155. // Set test values for every field type.
  156. $field_types = array(
  157. 'textfield' => $this->randomName(),
  158. 'textarea' => $this->randomName(),
  159. 'list' => $this->randomName(),
  160. 'checkbox' => 1,
  161. // An underscore is an invalid character in a domain name. The method randomName can
  162. // return an underscore.
  163. 'url' => 'http://www.' . str_replace('_', '', $this->randomName(10)) . '.org',
  164. );
  165. // For each field type, create a field, give it a value, update the field,
  166. // and delete the field.
  167. foreach ($field_types as $type => $value) {
  168. $field = $this->createProfileField($type);
  169. $this->setProfileField($field, $value);
  170. $edit = array(
  171. 'name' => $field['form_name'],
  172. 'title' => $this->randomName(),
  173. 'category' => $field['category'],
  174. 'explanation' => $this->randomName(),
  175. );
  176. $field = $this->updateProfileField($field['fid'], $field['type'], $edit);
  177. $this->deleteProfileField($field);
  178. }
  179. }
  180. }
  181. class ProfileTestSelect extends ProfileTestCase {
  182. public static function getInfo() {
  183. return array(
  184. 'name' => 'Test select field',
  185. 'description' => 'Testing profile module with add/edit/delete a select field',
  186. 'group' => 'Profile'
  187. );
  188. }
  189. /**
  190. * Create a list selection field, give it a value, update and delete the field.
  191. */
  192. function testProfileSelectionField() {
  193. $this->drupalLogin($this->admin_user);
  194. $edit = array(
  195. 'options' => implode("\n", range(1, 10)),
  196. );
  197. $field = $this->createProfileField('selection', 'simpletest', $edit);
  198. $this->setProfileField($field, rand(1, 10));
  199. $edit = array(
  200. 'name' => $field['form_name'],
  201. 'title' => $this->randomName(),
  202. 'category' => $field['category'],
  203. 'explanation' => $this->randomName(),
  204. );
  205. $field = $this->updateProfileField($field['fid'], $field['type'], $edit);
  206. $this->deleteProfileField($field);
  207. }
  208. }
  209. class ProfileTestDate extends ProfileTestCase {
  210. public static function getInfo() {
  211. return array(
  212. 'name' => 'Test date field',
  213. 'description' => 'Testing profile module with add/edit/delete a date field',
  214. 'group' => 'Profile'
  215. );
  216. }
  217. /**
  218. * Create a date field, give it a value, update and delete the field.
  219. */
  220. function testProfileDateField() {
  221. $this->drupalLogin($this->admin_user);
  222. variable_set('date_format_short', 'm/d/Y - H:i');
  223. $field = $this->createProfileField('date');
  224. // Set date to January 09, 1983
  225. $edit = array(
  226. $field['form_name'] . '[month]' => 1,
  227. $field['form_name'] . '[day]' => 9,
  228. $field['form_name'] . '[year]' => 1983,
  229. );
  230. $this->drupalPost('user/' . $this->normal_user->uid . '/edit/' . $field['category'], $edit, t('Save'));
  231. // Check profile page.
  232. $this->drupalGet('user/' . $this->normal_user->uid);
  233. $this->assertText($field['title'], format_string('Found profile field with title %title', array('%title' => $field['title'])));
  234. $this->assertText('01/09/1983', 'Found date profile field.');
  235. $edit = array(
  236. 'name' => $field['form_name'],
  237. 'title' => $this->randomName(),
  238. 'category' => $field['category'],
  239. 'explanation' => $this->randomName(),
  240. );
  241. $field = $this->updateProfileField($field['fid'], $field['type'], $edit);
  242. $this->deleteProfileField($field);
  243. }
  244. }
  245. class ProfileTestWeights extends ProfileTestCase {
  246. public static function getInfo() {
  247. return array(
  248. 'name' => 'Test field weights',
  249. 'description' => 'Testing profile modules weigting of fields',
  250. 'group' => 'Profile'
  251. );
  252. }
  253. function testProfileFieldWeights() {
  254. $this->drupalLogin($this->admin_user);
  255. $category = $this->randomName();
  256. $field1 = $this->createProfileField('textfield', $category, array('weight' => 1));
  257. $field2 = $this->createProfileField('textfield', $category, array('weight' => -1));
  258. $this->setProfileField($field1, $this->randomName(8));
  259. $this->setProfileField($field2, $this->randomName(8));
  260. $profile_edit = $this->drupalGet('user/' . $this->normal_user->uid . '/edit/' . $category);
  261. $this->assertTrue(strpos($profile_edit, $field1['title']) > strpos($profile_edit, $field2['title']), 'Profile field weights are respected on the user edit form.');
  262. $profile_page = $this->drupalGet('user/' . $this->normal_user->uid);
  263. $this->assertTrue(strpos($profile_page, $field1['title']) > strpos($profile_page, $field2['title']), 'Profile field weights are respected on the user profile page.');
  264. }
  265. }
  266. /**
  267. * Test profile field autocompletion and access.
  268. */
  269. class ProfileTestAutocomplete extends ProfileTestCase {
  270. public static function getInfo() {
  271. return array(
  272. 'name' => 'Autocompletion',
  273. 'description' => 'Test profile fields with autocompletion.',
  274. 'group' => 'Profile'
  275. );
  276. }
  277. /**
  278. * Tests profile field autocompletion and access.
  279. */
  280. function testAutocomplete() {
  281. $this->drupalLogin($this->admin_user);
  282. // Create a new profile field with autocompletion enabled.
  283. $category = $this->randomName();
  284. $field = $this->createProfileField('textfield', $category, array('weight' => 1, 'autocomplete' => 1));
  285. // Enter profile field value.
  286. $field['value'] = $this->randomName();
  287. $this->setProfileField($field, $field['value']);
  288. // Set some html for what we want to see in the page output later.
  289. // Autocomplete always uses non-clean URLs.
  290. $current_clean_url = isset($GLOBALS['conf']['clean_url']) ? $GLOBALS['conf']['clean_url'] : NULL;
  291. $GLOBALS['conf']['clean_url'] = 0;
  292. $autocomplete_url = url('profile/autocomplete/' . $field['fid'], array('absolute' => TRUE));
  293. $GLOBALS['conf']['clean_url'] = $current_clean_url;
  294. $autocomplete_id = drupal_html_id('edit-' . $field['form_name'] . '-autocomplete');
  295. $autocomplete_html = '<input type="hidden" id="' . $autocomplete_id . '" value="' . $autocomplete_url . '" disabled="disabled" class="autocomplete" />';
  296. // Check that autocompletion html is found on the user's profile edit page.
  297. $this->drupalGet('user/' . $this->admin_user->uid . '/edit/' . $category);
  298. $this->assertRaw($autocomplete_html, 'Autocomplete found.');
  299. $this->assertFieldByXPath(
  300. '//input[@type="text" and @name="' . $field['form_name'] . '" and contains(@class, "form-autocomplete")]',
  301. '',
  302. 'Text input field found'
  303. );
  304. $this->assertRaw('misc/autocomplete.js', 'Autocomplete JavaScript found.');
  305. $this->assertRaw('class="form-text form-autocomplete"', 'Autocomplete form element class found.');
  306. // Check the autocompletion path using the first letter of our user's profile
  307. // field value to make sure access is allowed and a valid result if found.
  308. $this->drupalGet('profile/autocomplete/' . $field['fid'] . '/' . $field['value'][0]);
  309. $this->assertResponse(200, 'Autocomplete path allowed to user with permission.');
  310. $this->assertRaw($field['value'], 'Autocomplete value found.');
  311. // Logout and login with a user without the 'access user profiles' permission.
  312. $this->drupalLogout();
  313. $this->drupalLogin($this->normal_user);
  314. // Check that autocompletion html is not found on the user's profile edit page.
  315. $this->drupalGet('user/' . $this->normal_user->uid . '/edit/' . $category);
  316. $this->assertNoRaw($autocomplete_html, 'Autocomplete not found.');
  317. // User should be denied access to the profile autocomplete path.
  318. $this->drupalGet('profile/autocomplete/' . $field['fid'] . '/' . $field['value'][0]);
  319. $this->assertResponse(403, 'Autocomplete path denied to user without permission.');
  320. }
  321. }
  322. class ProfileBlockTestCase extends ProfileTestCase {
  323. public static function getInfo() {
  324. return array(
  325. 'name' => 'Block availability',
  326. 'description' => 'Check if the Author Information block is available.',
  327. 'group' => 'Profile',
  328. );
  329. }
  330. function setUp() {
  331. parent::setUp();
  332. // Login the admin user.
  333. $this->drupalLogin($this->admin_user);
  334. // Create two fields.
  335. $category = $this->randomName();
  336. $this->field1 = $this->createProfileField('textfield', $category, array('weight' => 0));
  337. $this->field2 = $this->createProfileField('textfield', $category, array('weight' => 1));
  338. // Assign values to those fields.
  339. $this->value1 = $this->setProfileField($this->field1);
  340. $this->value2 = $this->setProfileField($this->field2);
  341. // Create a node authored by the normal user.
  342. $this->node = $this->drupalCreateNode(array(
  343. 'uid' => $this->normal_user->uid,
  344. ));
  345. }
  346. function testAuthorInformationBlock() {
  347. // Set the block to a region to confirm the block is available.
  348. $edit = array();
  349. $edit['blocks[profile_author-information][region]'] = 'footer';
  350. $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
  351. $this->assertText(t('The block settings have been updated.'), 'Block successfully move to footer region.');
  352. // Enable field 1.
  353. $this->drupalPost('admin/structure/block/manage/profile/author-information/configure', array(
  354. 'profile_block_author_fields[' . $this->field1['form_name'] . ']' => TRUE,
  355. ), t('Save block'));
  356. $this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
  357. // Visit the node and confirm that the field is displayed.
  358. $this->drupalGet('node/' . $this->node->nid);
  359. $this->assertRaw($this->value1, 'Field 1 is displayed');
  360. $this->assertNoRaw($this->value2, 'Field 2 is not displayed');
  361. // Enable only field 2.
  362. $this->drupalPost('admin/structure/block/manage/profile/author-information/configure', array(
  363. 'profile_block_author_fields[' . $this->field1['form_name'] . ']' => FALSE,
  364. 'profile_block_author_fields[' . $this->field2['form_name'] . ']' => TRUE,
  365. ), t('Save block'));
  366. $this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
  367. // Visit the node and confirm that the field is displayed.
  368. $this->drupalGet('node/' . $this->node->nid);
  369. $this->assertNoRaw($this->value1, 'Field 1 is not displayed');
  370. $this->assertRaw($this->value2, 'Field 2 is displayed');
  371. // Enable both fields.
  372. $this->drupalPost('admin/structure/block/manage/profile/author-information/configure', array(
  373. 'profile_block_author_fields[' . $this->field1['form_name'] . ']' => TRUE,
  374. 'profile_block_author_fields[' . $this->field2['form_name'] . ']' => TRUE,
  375. ), t('Save block'));
  376. $this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
  377. // Visit the node and confirm that the field is displayed.
  378. $this->drupalGet('node/' . $this->node->nid);
  379. $this->assertRaw($this->value1, 'Field 1 is displayed');
  380. $this->assertRaw($this->value2, 'Field 2 is displayed');
  381. // Enable the link to the user profile.
  382. $this->drupalPost('admin/structure/block/manage/profile/author-information/configure', array(
  383. 'profile_block_author_fields[user_profile]' => TRUE,
  384. ), t('Save block'));
  385. $this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
  386. // Visit the node and confirm that the user profile link is displayed.
  387. $this->drupalGet('node/' . $this->node->nid);
  388. $this->clickLink(t('View full user profile'));
  389. $this->assertEqual($this->getUrl(), url('user/' . $this->normal_user->uid, array('absolute' => TRUE)));
  390. }
  391. }
  392. /**
  393. * Test profile browsing.
  394. */
  395. class ProfileTestBrowsing extends ProfileTestCase {
  396. public static function getInfo() {
  397. return array(
  398. 'name' => 'Profile browsing',
  399. 'description' => 'Test profile browsing.',
  400. 'group' => 'Profile',
  401. );
  402. }
  403. /**
  404. * Test profile browsing.
  405. */
  406. function testProfileBrowsing() {
  407. $this->drupalLogin($this->admin_user);
  408. $field = $this->createProfileField('list', 'simpletest', array('page' => '%value'));
  409. // Set a random value for the profile field.
  410. $value = $this->setProfileField($field);
  411. // Check that user is found on the profile browse page.
  412. $this->drupalGet("profile/{$field['form_name']}/$value");
  413. $this->assertText($this->normal_user->name);
  414. }
  415. }
  416. /**
  417. * Test profile integration with user CRUD operations.
  418. */
  419. class ProfileCrudTestCase extends ProfileTestCase {
  420. public static function getInfo() {
  421. return array(
  422. 'name' => 'Profile CRUD tests',
  423. 'description' => 'Test profile integration with user create, read, update, delete.',
  424. 'group' => 'Profile',
  425. );
  426. }
  427. /**
  428. * Test profile integration with user CRUD operations.
  429. */
  430. public function testUserCRUD() {
  431. // @todo Add profile fields in addition to base user properties.
  432. $edit = array(
  433. 'name' => 'Test user',
  434. 'mail' => 'test@example.com',
  435. );
  436. // Create.
  437. // @todo Add assertions.
  438. $account = user_save(NULL, $edit);
  439. // Read.
  440. // @todo Add assertions.
  441. $account = user_load($account->uid);
  442. // Update.
  443. // @todo Add assertions.
  444. $account = user_save($account, $edit);
  445. // Delete.
  446. // @todo Add assertions.
  447. user_delete($account->uid);
  448. }
  449. }
  450. /**
  451. * TODO:
  452. * - Test field visibility
  453. * - Test required fields
  454. * - Test fields on registration form
  455. * - Test updating fields
  456. */