Skip to content

Commit 7a5f7b9

Browse files
committed
Add integration test covering account endpoint
1 parent 8fb21a5 commit 7a5f7b9

File tree

2 files changed

+178
-5
lines changed

2 files changed

+178
-5
lines changed

app/Http/Controllers/Api/Client/AccountController.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,16 @@ public function index(Request $request): array
5252
* Update the authenticated user's email address.
5353
*
5454
* @param \Pterodactyl\Http\Requests\Api\Client\Account\UpdateEmailRequest $request
55-
* @return \Illuminate\Http\Response
55+
* @return \Illuminate\Http\JsonResponse
5656
*
5757
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
5858
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
5959
*/
60-
public function updateEmail(UpdateEmailRequest $request): Response
60+
public function updateEmail(UpdateEmailRequest $request): JsonResponse
6161
{
6262
$this->updateService->handle($request->user(), $request->validated());
6363

64-
return response('', Response::HTTP_CREATED);
64+
return new JsonResponse([], Response::HTTP_NO_CONTENT);
6565
}
6666

6767
/**
@@ -74,12 +74,12 @@ public function updateEmail(UpdateEmailRequest $request): Response
7474
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
7575
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
7676
*/
77-
public function updatePassword(UpdatePasswordRequest $request): \Illuminate\Http\JsonResponse
77+
public function updatePassword(UpdatePasswordRequest $request): JsonResponse
7878
{
7979
$this->updateService->handle($request->user(), $request->validated());
8080

8181
$this->sessionGuard->logoutOtherDevices($request->input('password'));
8282

83-
return JsonResponse::create([], Response::HTTP_NO_CONTENT);
83+
return new JsonResponse([], Response::HTTP_NO_CONTENT);
8484
}
8585
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<?php
2+
3+
namespace Pterodactyl\Tests\Integration\Api\Client;
4+
5+
use Mockery;
6+
use Pterodactyl\Models\User;
7+
use Illuminate\Http\Response;
8+
use Illuminate\Auth\AuthManager;
9+
use Pterodactyl\Tests\Integration\IntegrationTestCase;
10+
11+
class AccountControllerTest extends IntegrationTestCase
12+
{
13+
/**
14+
* Clean up after running tests.
15+
*/
16+
protected function tearDown(): void
17+
{
18+
User::query()->forceDelete();
19+
20+
parent::tearDown();
21+
}
22+
23+
/**
24+
* Test that the user's account details are returned from the account endpoint.
25+
*/
26+
public function testAccountDetailsAreReturned()
27+
{
28+
/** @var \Pterodactyl\Models\User $user */
29+
$user = factory(User::class)->create();
30+
31+
$response = $this->actingAs($user)->get('/api/client/account');
32+
33+
$response->assertOk()->assertJson([
34+
'object' => 'user',
35+
'attributes' => [
36+
'id' => $user->id,
37+
'admin' => false,
38+
'username' => $user->username,
39+
'email' => $user->email,
40+
'first_name' => $user->name_first,
41+
'last_name' => $user->name_last,
42+
'language' => $user->language,
43+
],
44+
]);
45+
}
46+
47+
/**
48+
* Test that the user's email address can be updated via the API.
49+
*/
50+
public function testEmailIsUpdated()
51+
{
52+
/** @var \Pterodactyl\Models\User $user */
53+
$user = factory(User::class)->create();
54+
55+
$response = $this->actingAs($user)->putJson('/api/client/account/email', [
56+
'email' => 'hodor@example.com',
57+
'password' => 'password',
58+
]);
59+
60+
$response->assertStatus(Response::HTTP_NO_CONTENT);
61+
62+
$this->assertDatabaseHas('users', ['id' => $user->id, 'email' => 'hodor@example.com']);
63+
}
64+
65+
/**
66+
* Tests that an email is not updated if the password provided in the reuqest is not
67+
* valid for the account.
68+
*/
69+
public function testEmailIsNotUpdatedWhenPasswordIsInvalid()
70+
{
71+
/** @var \Pterodactyl\Models\User $user */
72+
$user = factory(User::class)->create();
73+
74+
$response = $this->actingAs($user)->putJson('/api/client/account/email', [
75+
'email' => 'hodor@example.com',
76+
'password' => 'invalid',
77+
]);
78+
79+
$response->assertStatus(Response::HTTP_BAD_REQUEST);
80+
$response->assertJsonPath('errors.0.code', 'InvalidPasswordProvidedException');
81+
$response->assertJsonPath('errors.0.detail', 'The password provided was invalid for this account.');
82+
}
83+
84+
/**
85+
* Tests that an email is not updated if an invalid email address is passed through
86+
* in the request.
87+
*/
88+
public function testEmailIsNotUpdatedWhenNotValid()
89+
{
90+
/** @var \Pterodactyl\Models\User $user */
91+
$user = factory(User::class)->create();
92+
93+
$response = $this->actingAs($user)->putJson('/api/client/account/email', [
94+
'email' => '',
95+
'password' => 'password',
96+
]);
97+
98+
$response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
99+
$response->assertJsonPath('errors.0.code', 'required');
100+
$response->assertJsonPath('errors.0.detail', 'The email field is required.');
101+
102+
$response = $this->actingAs($user)->putJson('/api/client/account/email', [
103+
'email' => 'invalid',
104+
'password' => 'password',
105+
]);
106+
107+
$response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
108+
$response->assertJsonPath('errors.0.code', 'email');
109+
$response->assertJsonPath('errors.0.detail', 'The email must be a valid email address.');
110+
}
111+
112+
/**
113+
* Test that the password for an account can be successfully updated.
114+
*/
115+
public function testPasswordIsUpdated()
116+
{
117+
/** @var \Pterodactyl\Models\User $user */
118+
$user = factory(User::class)->create();
119+
120+
$mock = Mockery::mock(AuthManager::class);
121+
$mock->expects('logoutOtherDevices')->with('New_Password1');
122+
123+
$this->app->instance(AuthManager::class, $mock);
124+
125+
$response = $this->actingAs($user)->putJson('/api/client/account/password', [
126+
'current_password' => 'password',
127+
'password' => 'New_Password1',
128+
'password_confirmation' => 'New_Password1',
129+
]);
130+
131+
$response->assertStatus(Response::HTTP_NO_CONTENT);
132+
}
133+
134+
/**
135+
* Test that the password for an account is not updated if the current password is not
136+
* provided correctly.
137+
*/
138+
public function testPasswordIsNotUpdatedIfCurrentPasswordIsInvalid()
139+
{
140+
/** @var \Pterodactyl\Models\User $user */
141+
$user = factory(User::class)->create();
142+
143+
$response = $this->actingAs($user)->putJson('/api/client/account/password', [
144+
'current_password' => 'invalid',
145+
'password' => 'New_Password1',
146+
'password_confirmation' => 'New_Password1',
147+
]);
148+
149+
$response->assertStatus(Response::HTTP_BAD_REQUEST);
150+
$response->assertJsonPath('errors.0.code', 'InvalidPasswordProvidedException');
151+
$response->assertJsonPath('errors.0.detail', 'The password provided was invalid for this account.');
152+
}
153+
154+
/**
155+
* Test that a validation error is returned if the password passed in the request
156+
* does not have a confirmation, or the confirmation is not the same as the password.
157+
*/
158+
public function testErrorIsReturnedIfPasswordIsNotConfirmed()
159+
{
160+
/** @var \Pterodactyl\Models\User $user */
161+
$user = factory(User::class)->create();
162+
163+
$response = $this->actingAs($user)->putJson('/api/client/account/password', [
164+
'current_password' => 'password',
165+
'password' => 'New_Password1',
166+
'password_confirmation' => 'Invalid_New_Password',
167+
]);
168+
169+
$response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
170+
$response->assertJsonPath('errors.0.code', 'confirmed');
171+
$response->assertJsonPath('errors.0.detail', 'The password confirmation does not match.');
172+
}
173+
}

0 commit comments

Comments
 (0)