]> BookStack Code Mirror - bookstack/blob - tests/Auth/AuthTest.php
Updated styles to use logical properties/values
[bookstack] / tests / Auth / AuthTest.php
1 <?php namespace Tests\Auth;
2
3 use BookStack\Auth\User;
4 use BookStack\Entities\Page;
5 use BookStack\Notifications\ConfirmEmail;
6 use BookStack\Settings\SettingService;
7 use Illuminate\Support\Facades\Notification;
8 use Tests\BrowserKitTest;
9
10 class AuthTest extends BrowserKitTest
11 {
12
13     public function test_auth_working()
14     {
15         $this->visit('/')
16             ->seePageIs('/login');
17     }
18
19     public function test_login()
20     {
21         $this->login('[email protected]', 'password')
22             ->seePageIs('/');
23     }
24
25     public function test_public_viewing()
26     {
27         $settings = app(SettingService::class);
28         $settings->put('app-public', 'true');
29         $this->visit('/')
30             ->seePageIs('/')
31             ->see('Log In');
32     }
33
34     public function test_registration_showing()
35     {
36         // Ensure registration form is showing
37         $this->setSettings(['registration-enabled' => 'true']);
38         $this->visit('/login')
39             ->see('Sign up')
40             ->click('Sign up')
41             ->seePageIs('/register');
42     }
43
44     public function test_normal_registration()
45     {
46         // Set settings and get user instance
47         $this->setSettings(['registration-enabled' => 'true']);
48         $user = factory(User::class)->make();
49
50         // Test form and ensure user is created
51         $this->visit('/register')
52             ->see('Sign Up')
53             ->type($user->name, '#name')
54             ->type($user->email, '#email')
55             ->type($user->password, '#password')
56             ->press('Create Account')
57             ->seePageIs('/')
58             ->see($user->name)
59             ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email]);
60     }
61
62     public function test_empty_registration_redirects_back_with_errors()
63     {
64         // Set settings and get user instance
65         $this->setSettings(['registration-enabled' => 'true']);
66
67         // Test form and ensure user is created
68         $this->visit('/register')
69             ->press('Create Account')
70             ->see('The name field is required')
71             ->seePageIs('/register');
72     }
73
74     public function test_registration_validation()
75     {
76         $this->setSettings(['registration-enabled' => 'true']);
77
78         $this->visit('/register')
79             ->type('1', '#name')
80             ->type('1', '#email')
81             ->type('1', '#password')
82             ->press('Create Account')
83             ->see('The name must be at least 2 characters.')
84             ->see('The email must be a valid email address.')
85             ->see('The password must be at least 8 characters.')
86             ->seePageIs('/register');
87     }
88
89     public function test_sign_up_link_on_login()
90     {
91         $this->visit('/login')
92             ->dontSee('Sign up');
93
94         $this->setSettings(['registration-enabled' => 'true']);
95
96         $this->visit('/login')
97             ->see('Sign up');
98     }
99
100     public function test_confirmed_registration()
101     {
102         // Fake notifications
103         Notification::fake();
104
105         // Set settings and get user instance
106         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
107         $user = factory(User::class)->make();
108
109         // Go through registration process
110         $this->visit('/register')
111             ->see('Sign Up')
112             ->type($user->name, '#name')
113             ->type($user->email, '#email')
114             ->type($user->password, '#password')
115             ->press('Create Account')
116             ->seePageIs('/register/confirm')
117             ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
118
119         // Ensure notification sent
120         $dbUser = User::where('email', '=', $user->email)->first();
121         Notification::assertSentTo($dbUser, ConfirmEmail::class);
122
123         // Test access and resend confirmation email
124         $this->login($user->email, $user->password)
125             ->seePageIs('/register/confirm/awaiting')
126             ->see('Resend')
127             ->visit('/books')
128             ->seePageIs('/register/confirm/awaiting')
129             ->press('Resend Confirmation Email');
130
131         // Get confirmation and confirm notification matches
132         $emailConfirmation = \DB::table('email_confirmations')->where('user_id', '=', $dbUser->id)->first();
133         Notification::assertSentTo($dbUser, ConfirmEmail::class, function($notification, $channels) use ($emailConfirmation) {
134             return $notification->token === $emailConfirmation->token;
135         });
136         
137         // Check confirmation email confirmation activation.
138         $this->visit('/register/confirm/' . $emailConfirmation->token)
139             ->seePageIs('/')
140             ->see($user->name)
141             ->notSeeInDatabase('email_confirmations', ['token' => $emailConfirmation->token])
142             ->seeInDatabase('users', ['name' => $dbUser->name, 'email' => $dbUser->email, 'email_confirmed' => true]);
143     }
144
145     public function test_restricted_registration()
146     {
147         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true', 'registration-restrict' => 'example.com']);
148         $user = factory(User::class)->make();
149         // Go through registration process
150         $this->visit('/register')
151             ->type($user->name, '#name')
152             ->type($user->email, '#email')
153             ->type($user->password, '#password')
154             ->press('Create Account')
155             ->seePageIs('/register')
156             ->dontSeeInDatabase('users', ['email' => $user->email])
157             ->see('That email domain does not have access to this application');
158
159         $user->email = '[email protected]';
160
161         $this->visit('/register')
162             ->type($user->name, '#name')
163             ->type($user->email, '#email')
164             ->type($user->password, '#password')
165             ->press('Create Account')
166             ->seePageIs('/register/confirm')
167             ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
168
169         $this->visit('/')->seePageIs('/login')
170             ->type($user->email, '#email')
171             ->type($user->password, '#password')
172             ->press('Log In')
173             ->seePageIs('/register/confirm/awaiting')
174             ->seeText('Email Address Not Confirmed');
175     }
176
177     public function test_restricted_registration_with_confirmation_disabled()
178     {
179         $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'false', 'registration-restrict' => 'example.com']);
180         $user = factory(User::class)->make();
181         // Go through registration process
182         $this->visit('/register')
183             ->type($user->name, '#name')
184             ->type($user->email, '#email')
185             ->type($user->password, '#password')
186             ->press('Create Account')
187             ->seePageIs('/register')
188             ->dontSeeInDatabase('users', ['email' => $user->email])
189             ->see('That email domain does not have access to this application');
190
191         $user->email = '[email protected]';
192
193         $this->visit('/register')
194             ->type($user->name, '#name')
195             ->type($user->email, '#email')
196             ->type($user->password, '#password')
197             ->press('Create Account')
198             ->seePageIs('/register/confirm')
199             ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
200
201         $this->visit('/')->seePageIs('/login')
202             ->type($user->email, '#email')
203             ->type($user->password, '#password')
204             ->press('Log In')
205             ->seePageIs('/register/confirm/awaiting')
206             ->seeText('Email Address Not Confirmed');
207     }
208
209     public function test_user_creation()
210     {
211         $user = factory(User::class)->make();
212
213         $this->asAdmin()
214             ->visit('/settings/users')
215             ->click('Add New User')
216             ->type($user->name, '#name')
217             ->type($user->email, '#email')
218             ->check('roles[admin]')
219             ->type($user->password, '#password')
220             ->type($user->password, '#password-confirm')
221             ->press('Save')
222             ->seePageIs('/settings/users')
223             ->seeInDatabase('users', $user->toArray())
224             ->see($user->name);
225     }
226
227     public function test_user_updating()
228     {
229         $user = $this->getNormalUser();
230         $password = $user->password;
231         $this->asAdmin()
232             ->visit('/settings/users')
233             ->click($user->name)
234             ->seePageIs('/settings/users/' . $user->id)
235             ->see($user->email)
236             ->type('Barry Scott', '#name')
237             ->press('Save')
238             ->seePageIs('/settings/users')
239             ->seeInDatabase('users', ['id' => $user->id, 'name' => 'Barry Scott', 'password' => $password])
240             ->notSeeInDatabase('users', ['name' => $user->name]);
241     }
242
243     public function test_user_password_update()
244     {
245         $user = $this->getNormalUser();
246         $userProfilePage = '/settings/users/' . $user->id;
247         $this->asAdmin()
248             ->visit($userProfilePage)
249             ->type('newpassword', '#password')
250             ->press('Save')
251             ->seePageIs($userProfilePage)
252             ->see('Password confirmation required')
253
254             ->type('newpassword', '#password')
255             ->type('newpassword', '#password-confirm')
256             ->press('Save')
257             ->seePageIs('/settings/users');
258
259             $userPassword = User::find($user->id)->password;
260             $this->assertTrue(\Hash::check('newpassword', $userPassword));
261     }
262
263     public function test_user_deletion()
264     {
265         $userDetails = factory(User::class)->make();
266         $user = $this->getEditor($userDetails->toArray());
267
268         $this->asAdmin()
269             ->visit('/settings/users/' . $user->id)
270             ->click('Delete User')
271             ->see($user->name)
272             ->press('Confirm')
273             ->seePageIs('/settings/users')
274             ->notSeeInDatabase('users', ['name' => $user->name]);
275     }
276
277     public function test_user_cannot_be_deleted_if_last_admin()
278     {
279         $adminRole = \BookStack\Auth\Role::getRole('admin');
280
281         // Delete all but one admin user if there are more than one
282         $adminUsers = $adminRole->users;
283         if (count($adminUsers) > 1) {
284             foreach ($adminUsers->splice(1) as $user) {
285                 $user->delete();
286             }
287         }
288
289         // Ensure we currently only have 1 admin user
290         $this->assertEquals(1, $adminRole->users()->count());
291         $user = $adminRole->users->first();
292
293         $this->asAdmin()->visit('/settings/users/' . $user->id)
294             ->click('Delete User')
295             ->press('Confirm')
296             ->seePageIs('/settings/users/' . $user->id)
297             ->see('You cannot delete the only admin');
298     }
299
300     public function test_logout()
301     {
302         $this->asAdmin()
303             ->visit('/')
304             ->seePageIs('/')
305             ->visit('/logout')
306             ->visit('/')
307             ->seePageIs('/login');
308     }
309
310     public function test_reset_password_flow()
311     {
312
313         Notification::fake();
314
315         $this->visit('/login')->click('Forgot Password?')
316             ->seePageIs('/password/email')
317             ->type('[email protected]', 'email')
318             ->press('Send Reset Link')
319             ->see('A password reset link has been sent to [email protected]');
320
321         $this->seeInDatabase('password_resets', [
322             'email' => '[email protected]'
323         ]);
324
325         $user = User::where('email', '=', '[email protected]')->first();
326
327         Notification::assertSentTo($user, \BookStack\Notifications\ResetPassword::class);
328         $n = Notification::sent($user, \BookStack\Notifications\ResetPassword::class);
329
330         $this->visit('/password/reset/' . $n->first()->token)
331             ->see('Reset Password')
332             ->submitForm('Reset Password', [
333                 'email' => '[email protected]',
334                 'password' => 'randompass',
335                 'password_confirmation' => 'randompass'
336             ])->seePageIs('/')
337             ->see('Your password has been successfully reset');
338     }
339
340     public function test_reset_password_page_shows_sign_links()
341     {
342         $this->setSettings(['registration-enabled' => 'true']);
343         $this->visit('/password/email')
344             ->seeLink('Log in')
345             ->seeLink('Sign up');
346     }
347
348     public function test_login_redirects_to_initially_requested_url_correctly()
349     {
350         config()->set('app.url', 'http://localhost');
351         $page = Page::query()->first();
352
353         $this->visit($page->getUrl())
354             ->seePageUrlIs(url('/login'));
355         $this->login('[email protected]', 'password')
356             ->seePageUrlIs($page->getUrl());
357     }
358
359     /**
360      * Perform a login
361      * @param string $email
362      * @param string $password
363      * @return $this
364      */
365     protected function login($email, $password)
366     {
367         return $this->visit('/login')
368             ->type($email, '#email')
369             ->type($password, '#password')
370             ->press('Log In');
371     }
372 }