UserRegistrationTest.php 17.1 KB
Newer Older
1 2 3 4
<?php

namespace Drupal\user\Tests;

5
use Drupal\Core\Entity\Entity\EntityFormDisplay;
6
use Drupal\Component\Utility\SafeMarkup;
7
use Drupal\Core\Field\FieldStorageDefinitionInterface;
8 9
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
10 11
use Drupal\simpletest\WebTestBase;

12
/**
13 14 15
 * Tests registration of user under different configurations.
 *
 * @group user
16
 */
17
class UserRegistrationTest extends WebTestBase {
18 19 20 21 22 23

  /**
   * Modules to enable.
   *
   * @var array
   */
24
  public static $modules = ['field_test'];
25

26
  public function testRegistrationWithEmailVerification() {
27
    $config = $this->config('user.settings');
28
    // Require email verification.
29
    $config->set('verify_mail', TRUE)->save();
30 31

    // Set registration to administrator only.
32
    $config->set('register', USER_REGISTER_ADMINISTRATORS_ONLY)->save();
33
    $this->drupalGet('user/register');
34
    $this->assertResponse(403, 'Registration page is inaccessible when only administrators can create accounts.');
35 36

    // Allow registration by site visitors without administrator approval.
37
    $config->set('register', USER_REGISTER_VISITORS)->save();
38
    $edit = [];
39
    $edit['name'] = $name = $this->randomMachineName();
40
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
41
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
42
    $this->assertText(t('A welcome message with further instructions has been sent to your email address.'), 'User registered successfully.');
43 44 45 46

    /** @var EntityStorageInterface $storage */
    $storage = $this->container->get('entity_type.manager')->getStorage('user');
    $accounts = $storage->loadByProperties(['name' => $name, 'mail' => $mail]);
47
    $new_user = reset($accounts);
48
    $this->assertTrue($new_user->isActive(), 'New account is active after registration.');
49 50 51
    $resetURL = user_pass_reset_url($new_user);
    $this->drupalGet($resetURL);
    $this->assertTitle(t('Set password | Drupal'), 'Page title is "Set password".');
52 53

    // Allow registration by site visitors, but require administrator approval.
54
    $config->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
55
    $edit = [];
56
    $edit['name'] = $name = $this->randomMachineName();
57
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
58
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
59
    $this->container->get('entity.manager')->getStorage('user')->resetCache();
60
    $accounts = $storage->loadByProperties(['name' => $name, 'mail' => $mail]);
61
    $new_user = reset($accounts);
62
    $this->assertFalse($new_user->isActive(), 'New account is blocked until approved by an administrator.');
63 64
  }

65
  public function testRegistrationWithoutEmailVerification() {
66
    $config = $this->config('user.settings');
67
    // Don't require email verification and allow registration by site visitors
68 69 70 71 72
    // without administrator approval.
    $config
      ->set('verify_mail', FALSE)
      ->set('register', USER_REGISTER_VISITORS)
      ->save();
73

74
    $edit = [];
75
    $edit['name'] = $name = $this->randomMachineName();
76 77 78 79 80
    $edit['mail'] = $mail = $edit['name'] . '@example.com';

    // Try entering a mismatching password.
    $edit['pass[pass1]'] = '99999.0';
    $edit['pass[pass2]'] = '99999';
81
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
82
    $this->assertText(t('The specified passwords do not match.'), 'Typing mismatched passwords displays an error message.');
83 84

    // Enter a correct password.
85
    $edit['pass[pass1]'] = $new_pass = $this->randomMachineName();
86
    $edit['pass[pass2]'] = $new_pass;
87
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
88
    $this->container->get('entity.manager')->getStorage('user')->resetCache();
89 90
    $accounts = $this->container->get('entity_type.manager')->getStorage('user')
      ->loadByProperties(['name' => $name, 'mail' => $mail]);
91
    $new_user = reset($accounts);
92
    $this->assertNotNull($new_user, 'New account successfully created with matching passwords.');
93
    $this->assertText(t('Registration successful. You are now logged in.'), 'Users are logged in after registering.');
94 95 96
    $this->drupalLogout();

    // Allow registration by site visitors, but require administrator approval.
97
    $config->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
98
    $edit = [];
99
    $edit['name'] = $name = $this->randomMachineName();
100
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
101
    $edit['pass[pass1]'] = $pass = $this->randomMachineName();
102
    $edit['pass[pass2]'] = $pass;
103
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
104
    $this->assertText(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.'), 'Users are notified of pending approval');
105

106
    // Try to log in before administrator approval.
107
    $auth = [
108 109
      'name' => $name,
      'pass' => $pass,
110
    ];
111
    $this->drupalPostForm('user/login', $auth, t('Log in'));
112
    $this->assertText(t('The username @name has not been activated or is blocked.', ['@name' => $name]), 'User cannot log in yet.');
113 114

    // Activate the new account.
115 116
    $accounts = $this->container->get('entity_type.manager')->getStorage('user')
      ->loadByProperties(['name' => $name, 'mail' => $mail]);
117
    $new_user = reset($accounts);
118
    $admin_user = $this->drupalCreateUser(['administer users']);
119
    $this->drupalLogin($admin_user);
120
    $edit = [
121
      'status' => 1,
122
    ];
123
    $this->drupalPostForm('user/' . $new_user->id() . '/edit', $edit, t('Save'));
124 125
    $this->drupalLogout();

126
    // Log in after administrator approval.
127
    $this->drupalPostForm('user/login', $auth, t('Log in'));
128
    $this->assertText(t('Member for'), 'User can log in after administrator approval.');
129 130
  }

131
  public function testRegistrationEmailDuplicates() {
132
    // Don't require email verification and allow registration by site visitors
133
    // without administrator approval.
134
    $this->config('user.settings')
135 136 137
      ->set('verify_mail', FALSE)
      ->set('register', USER_REGISTER_VISITORS)
      ->save();
138 139 140 141

    // Set up a user to check for duplicates.
    $duplicate_user = $this->drupalCreateUser();

142
    $edit = [];
143
    $edit['name'] = $this->randomMachineName();
144
    $edit['mail'] = $duplicate_user->getEmail();
145

146
    // Attempt to create a new account using an existing email address.
147
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
148
    $this->assertText(t('The email address @email is already taken.', ['@email' => $duplicate_user->getEmail()]), 'Supplying an exact duplicate email address displays an error message');
149 150

    // Attempt to bypass duplicate email registration validation by adding spaces.
151
    $edit['mail'] = '   ' . $duplicate_user->getEmail() . '   ';
152

153
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
154
    $this->assertText(t('The email address @email is already taken.', ['@email' => $duplicate_user->getEmail()]), 'Supplying a duplicate email address with added whitespace displays an error message');
155 156
  }

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
  /**
   * Tests that UUID isn't cached in form state on register form.
   *
   * This is a regression test for https://www.drupal.org/node/2500527 to ensure
   * that the form is not cached on GET requests.
   */
  public function testUuidFormState() {
    \Drupal::service('module_installer')->install(['image']);
    \Drupal::service('router.builder')->rebuild();

    // Add a picture field in order to ensure that no form cache is written,
    // which breaks registration of more than 1 user every 6 hours.
    $field_storage = FieldStorageConfig::create([
      'field_name' => 'user_picture',
      'entity_type' => 'user',
      'type' => 'image',
    ]);
    $field_storage->save();

    $field = FieldConfig::create([
      'field_name' => 'user_picture',
      'entity_type' => 'user',
      'bundle' => 'user',
    ]);
    $field->save();

    $form_display = EntityFormDisplay::create([
      'targetEntityType' => 'user',
      'bundle' => 'user',
      'mode' => 'default',
      'status' => TRUE,
    ]);
    $form_display->setComponent('user_picture', [
      'type' => 'image_image',
    ]);
    $form_display->save();

    // Don't require email verification and allow registration by site visitors
    // without administrator approval.
    $this->config('user.settings')
      ->set('verify_mail', FALSE)
      ->set('register', USER_REGISTER_VISITORS)
      ->save();

    $edit = [];
    $edit['name'] = $this->randomMachineName();
    $edit['mail'] = $edit['name'] . '@example.com';
    $edit['pass[pass2]'] = $edit['pass[pass1]'] = $this->randomMachineName();

    // Create one account.
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
    $this->assertResponse(200);

    $user_storage = \Drupal::entityManager()->getStorage('user');

    $this->assertTrue($user_storage->loadByProperties(['name' => $edit['name']]));
    $this->drupalLogout();

    // Create a second account.
    $edit['name'] = $this->randomMachineName();
    $edit['mail'] = $edit['name'] . '@example.com';
    $edit['pass[pass2]'] = $edit['pass[pass1]'] = $this->randomMachineName();

    $this->drupalPostForm('user/register', $edit, t('Create new account'));
    $this->assertResponse(200);

    $this->assertTrue($user_storage->loadByProperties(['name' => $edit['name']]));
  }

226
  public function testRegistrationDefaultValues() {
227
    // Don't require email verification and allow registration by site visitors
228
    // without administrator approval.
229
    $config_user_settings = $this->config('user.settings')
230 231 232
      ->set('verify_mail', FALSE)
      ->set('register', USER_REGISTER_VISITORS)
      ->save();
233 234

    // Set the default timezone to Brussels.
235
    $config_system_date = $this->config('system.date')
236 237
      ->set('timezone.user.configurable', 1)
      ->set('timezone.default', 'Europe/Brussels')
238
      ->save();
239

240
    // Check the presence of expected cache tags.
241
    $this->drupalGet('user/register');
242 243
    $this->assertCacheTag('config:user.settings');

244
    $edit = [];
245
    $edit['name'] = $name = $this->randomMachineName();
246
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
247
    $edit['pass[pass1]'] = $new_pass = $this->randomMachineName();
248
    $edit['pass[pass2]'] = $new_pass;
249
    $this->drupalPostForm(NULL, $edit, t('Create new account'));
250 251

    // Check user fields.
252 253
    $accounts = $this->container->get('entity_type.manager')->getStorage('user')
      ->loadByProperties(['name' => $name, 'mail' => $mail]);
254
    $new_user = reset($accounts);
255
    $this->assertEqual($new_user->getUsername(), $name, 'Username matches.');
256
    $this->assertEqual($new_user->getEmail(), $mail, 'Email address matches.');
257
    $this->assertTrue(($new_user->getCreatedTime() > REQUEST_TIME - 20), 'Correct creation time.');
258
    $this->assertEqual($new_user->isActive(), $config_user_settings->get('register') == USER_REGISTER_VISITORS ? 1 : 0, 'Correct status field.');
259
    $this->assertEqual($new_user->getTimezone(), $config_system_date->get('timezone.default'), 'Correct time zone field.');
260 261
    $this->assertEqual($new_user->langcode->value, \Drupal::languageManager()->getDefaultLanguage()->getId(), 'Correct language field.');
    $this->assertEqual($new_user->preferred_langcode->value, \Drupal::languageManager()->getDefaultLanguage()->getId(), 'Correct preferred language field.');
262
    $this->assertEqual($new_user->init->value, $mail, 'Correct init field.');
263 264
  }

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
  /**
   * Tests username and email field constraints on user registration.
   *
   * @see \Drupal\user\Plugin\Validation\Constraint\UserNameUnique
   * @see \Drupal\user\Plugin\Validation\Constraint\UserMailUnique
   */
  public function testUniqueFields() {
    $account = $this->drupalCreateUser();

    $edit = ['mail' => 'test@example.com', 'name' => $account->getUsername()];
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
    $this->assertRaw(SafeMarkup::format('The username %value is already taken.', ['%value' => $account->getUsername()]));

    $edit = ['mail' => $account->getEmail(), 'name' => $this->randomString()];
    $this->drupalPostForm('user/register', $edit, t('Create new account'));
    $this->assertRaw(SafeMarkup::format('The email address %value is already taken.', ['%value' => $account->getEmail()]));
  }

283 284 285
  /**
   * Tests Field API fields on user registration forms.
   */
286
  public function testRegistrationWithUserFields() {
287
    // Create a field on 'user' entity type.
288
    $field_storage = FieldStorageConfig::create([
289
      'field_name' => 'test_user_field',
290
      'entity_type' => 'user',
291 292
      'type' => 'test_field',
      'cardinality' => 1,
293
    ]);
294
    $field_storage->save();
295
    $field = FieldConfig::create([
296
      'field_storage' => $field_storage,
297 298 299
      'label' => 'Some user field',
      'bundle' => 'user',
      'required' => TRUE,
300
    ]);
301
    $field->save();
302
    entity_get_form_display('user', 'user', 'default')
303
      ->setComponent('test_user_field', ['type' => 'test_field_widget'])
304
      ->save();
305 306
    entity_get_form_display('user', 'user', 'register')
      ->save();
307 308 309

    // Check that the field does not appear on the registration form.
    $this->drupalGet('user/register');
310
    $this->assertNoText($field->label(), 'The field does not appear on user registration form');
311 312
    $this->assertCacheTag('config:core.entity_form_display.user.user.register');
    $this->assertCacheTag('config:user.settings');
313 314

    // Have the field appear on the registration form.
315
    entity_get_form_display('user', 'user', 'register')
316
      ->setComponent('test_user_field', ['type' => 'test_field_widget'])
317 318
      ->save();

319
    $this->drupalGet('user/register');
320
    $this->assertText($field->label(), 'The field appears on user registration form');
321
    $this->assertRegistrationFormCacheTagsWithUserFields();
322 323

    // Check that validation errors are correctly reported.
324
    $edit = [];
325
    $edit['name'] = $name = $this->randomMachineName();
326 327
    $edit['mail'] = $mail = $edit['name'] . '@example.com';
    // Missing input in required field.
328
    $edit['test_user_field[0][value]'] = '';
329
    $this->drupalPostForm(NULL, $edit, t('Create new account'));
330
    $this->assertRegistrationFormCacheTagsWithUserFields();
331
    $this->assertRaw(t('@name field is required.', ['@name' => $field->label()]), 'Field validation error was correctly reported.');
332
    // Invalid input.
333
    $edit['test_user_field[0][value]'] = '-1';
334
    $this->drupalPostForm(NULL, $edit, t('Create new account'));
335
    $this->assertRegistrationFormCacheTagsWithUserFields();
336
    $this->assertRaw(t('%name does not accept the value -1.', ['%name' => $field->label()]), 'Field validation error was correctly reported.');
337 338 339

    // Submit with valid data.
    $value = rand(1, 255);
340
    $edit['test_user_field[0][value]'] = $value;
341
    $this->drupalPostForm(NULL, $edit, t('Create new account'));
342
    // Check user fields.
343 344
    $accounts = $this->container->get('entity_type.manager')->getStorage('user')
      ->loadByProperties(['name' => $name, 'mail' => $mail]);
345
    $new_user = reset($accounts);
346
    $this->assertEqual($new_user->test_user_field->value, $value, 'The field value was correctly saved.');
347 348

    // Check that the 'add more' button works.
349
    $field_storage->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
350
    $field_storage->save();
351
    foreach (['js', 'nojs'] as $js) {
352
      $this->drupalGet('user/register');
353
      $this->assertRegistrationFormCacheTagsWithUserFields();
354 355
      // Add two inputs.
      $value = rand(1, 255);
356
      $edit = [];
357
      $edit['test_user_field[0][value]'] = $value;
358
      if ($js == 'js') {
359 360
        $this->drupalPostAjaxForm(NULL, $edit, 'test_user_field_add_more');
        $this->drupalPostAjaxForm(NULL, $edit, 'test_user_field_add_more');
361 362
      }
      else {
363 364
        $this->drupalPostForm(NULL, $edit, t('Add another item'));
        $this->drupalPostForm(NULL, $edit, t('Add another item'));
365 366
      }
      // Submit with three values.
367 368
      $edit['test_user_field[1][value]'] = $value + 1;
      $edit['test_user_field[2][value]'] = $value + 2;
369
      $edit['name'] = $name = $this->randomMachineName();
370
      $edit['mail'] = $mail = $edit['name'] . '@example.com';
371
      $this->drupalPostForm(NULL, $edit, t('Create new account'));
372
      // Check user fields.
373
      $accounts = $this->container->get('entity_type.manager')->getStorage('user')
374
        ->loadByProperties(['name' => $name, 'mail' => $mail]);
375
      $new_user = reset($accounts);
376 377 378
      $this->assertEqual($new_user->test_user_field[0]->value, $value, format_string('@js : The field value was correctly saved.', ['@js' => $js]));
      $this->assertEqual($new_user->test_user_field[1]->value, $value + 1, format_string('@js : The field value was correctly saved.', ['@js' => $js]));
      $this->assertEqual($new_user->test_user_field[2]->value, $value + 2, format_string('@js : The field value was correctly saved.', ['@js' => $js]));
379 380
    }
  }
381

382 383 384 385 386 387 388 389 390 391
  /**
   * Asserts the presence of cache tags on registration form with user fields.
   */
  protected function assertRegistrationFormCacheTagsWithUserFields() {
    $this->assertCacheTag('config:core.entity_form_display.user.user.register');
    $this->assertCacheTag('config:field.field.user.user.test_user_field');
    $this->assertCacheTag('config:field.storage.user.test_user_field');
    $this->assertCacheTag('config:user.settings');
  }

392
}