primo upload

This commit is contained in:
claus75a
2024-03-16 20:37:32 +01:00
commit e43b9b4b28
3019 changed files with 406000 additions and 0 deletions
@@ -0,0 +1,152 @@
<?php
namespace Tests\Feature\Api\Auth;
use Carbon\Carbon;
use Tests\Feature\ApiTestCase;
use Vanguard\Support\Enum\UserStatus;
use Vanguard\User;
class AuthControllerTest extends ApiTestCase
{
/** @test */
public function login()
{
$credentials = $this->defaultCredentials();
$user = User::factory()->create($credentials);
$credentials['device_name'] = 'test';
$this->postJson("/api/login", $credentials)->assertOk();
$this->assertNotNull($user->tokens()->first());
}
/** @test */
public function last_login_timestamp_is_updated_after_login()
{
$credentials = $this->defaultCredentials();
$now = Carbon::now();
Carbon::setTestNow($now);
$user = User::factory()->create($credentials);
$this->assertDatabaseHas('users', [
'id' => $user->id,
'last_login' => null
]);
$credentials['device_name'] = 'test';
$this->postJson("/api/login", $credentials)->assertOk();
$this->assertDatabaseHas('users', [
'id' => $user->id,
'last_login' => $now
]);
}
/** @test */
public function login_with_invalid_credentials()
{
$credentials = $this->defaultCredentials();
User::factory()->create($credentials);
$this->postJson("/api/login", [
'username' => 'foo',
'password' => 'invalid',
'device_name' => 'test'
])->assertJsonValidationErrors('username');
}
/** @test */
public function login_when_credentials_are_not_provided()
{
$this->postJson("/api/login")
->assertStatus(422)
->assertJsonFragment([
'username' => [
trans('validation.required', ['attribute' => 'username'])
],
'password' => [
trans('validation.required', ['attribute' => 'password'])
]
]);
}
/** @test */
public function banned_user_cannot_log_in()
{
$credentials = $this->defaultCredentials();
$user = User::factory()->create(array_merge($credentials, [
'status' => UserStatus::BANNED
]));
$credentials['device_name'] = 'test';
$this->postJson("/api/login", $credentials)
->assertStatus(401)
->assertJson([
'message' => "Your account is banned by administrators."
]);
$this->assertDatabaseMissing('personal_access_tokens', ['tokenable_id' => $user->id]);
}
/** @test */
public function unconfirmed_user_can_log_in()
{
$credentials = $this->defaultCredentials();
User::factory()->create(array_merge($credentials, [
'status' => UserStatus::UNCONFIRMED
]));
$credentials['device_name'] = 'test';
$this->postJson("/api/login", $credentials)->assertOk();
}
/** @test */
public function logout()
{
$credentials = $this->defaultCredentials();
Carbon::setTestNow(Carbon::now());
$user = User::factory()->create($credentials);
$credentials['device_name'] = 'test';
$response = $this->postJson("/api/login", $credentials);
$token = $user->tokens()->first();
auth('sanctum')->user()->withAccessToken($token);
$this->postJson("/api/logout", [], [
'Authorization' => "Bearer {$response->original['token']}"
]);
$this->assertDatabaseMissing('personal_access_tokens', ['id' => $token->id]);
}
/** @test */
public function logout_if_token_is_not_provided()
{
$this->postJson("/api/logout")->assertStatus(401);
}
private function defaultCredentials(array $override = [])
{
return array_merge([
'username' => 'foo',
'password' => 'bar'
], $override);
}
}
@@ -0,0 +1,38 @@
<?php
namespace Tests\Feature\Api\Auth\Password;
use Mail;
use Tests\Feature\ApiTestCase;
use Vanguard\Mail\ResetPassword;
use Vanguard\User;
class RemindControllerTest extends ApiTestCase
{
/** @test */
public function send_password_reminder()
{
$this->setSettings(['forgot_password' => true]);
Mail::fake();
$user = User::factory()->create(['email' => 'test@test.com']);
$this->postJson('api/password/remind', ['email' => 'test@test.com'])
->assertOk();
Mail::assertQueued(ResetPassword::class, function ($mail) use ($user) {
return $mail->hasTo($user->email);
});
}
/** @test */
public function password_reminder_with_wrong_email()
{
$this->setSettings(['forgot_password' => true]);
$this->postJson('api/password/remind', ['email' => 'test@test.com'])
->assertStatus(422)
->assertJsonValidationErrors('email');
}
}
@@ -0,0 +1,97 @@
<?php
namespace Tests\Feature\Api\Auth\Password;
use Carbon\Carbon;
use DB;
use Hash;
use Illuminate\Support\Str;
use Tests\Feature\ApiTestCase;
use Vanguard\User;
class ResetControllerTest extends ApiTestCase
{
/** @test */
public function password_reset()
{
$this->setSettings(['forgot_password' => true]);
$user = User::factory()->create(['email' => 'test@test.com']);
$token = $this->createNewToken();
DB::table('password_resets')->insert([
'email' => $user->email,
'token' => Hash::make($token),
'created_at' => Carbon::now()
]);
$this->resetPassword($token, $user->email)
->assertOk();
$this->assertTrue(Hash::check('123123123', $user->fresh()->password));
}
/** @test */
public function password_reset_with_expired_token()
{
$this->setSettings(['forgot_password' => true]);
$user = User::factory()->create(['email' => 'test@test.com']);
$token = $this->createNewToken();
DB::table('password_resets')->insert([
'email' => $user->email,
'token' => Hash::make($token),
'created_at' => Carbon::now()->subHours(2)
]);
$this->resetPassword($token, $user->email)
->assertJson([
'message' => "This password reset token is invalid."
]);
}
/** @test */
public function password_reset_with_invalid_email()
{
$this->setSettings(['forgot_password' => true]);
$user = User::factory()->create(['email' => 'test@test.com']);
$token = $this->createNewToken();
DB::table('password_resets')->insert([
'email' => $user->email,
'token' => Hash::make($token),
'created_at' => Carbon::now()
]);
$this->resetPassword($token, 'foo@bar.com')
->assertJson([
'message' => "We can't find a user with that e-mail address."
]);
}
private function resetPassword($token, $email)
{
return $this->postJson('api/password/reset', [
'token' => $token,
'email' => $email,
'password' => '123123123',
'password_confirmation' => '123123123'
]);
}
private function createNewToken()
{
$key = $this->app['config']['app.key'];
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
return hash_hmac('sha256', Str::random(40), $key);
}
}
@@ -0,0 +1,104 @@
<?php
namespace Tests\Feature\Api\Auth;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Notification;
use Tests\Feature\ApiTestCase;
use Vanguard\User;
class RegistrationControllerTest extends ApiTestCase
{
/** @test */
public function register_user_when_registration_is_disabled()
{
$this->setSettings(['reg_enabled' => false]);
$this->postJson('api/register')->assertStatus(404);
}
/** @test */
public function register_user()
{
$this->setSettings([
'reg_enabled' => true,
'reg_email_confirmation' => false,
'registration.captcha.enabled' => false,
'tos' => false
]);
$data = [
'email' => 'john.doe@test.com',
'username' => 'john.doe',
'password' => '123123123',
'password_confirmation' => '123123123'
];
$expected = Arr::except($data, ['password', 'password_confirmation']);
$this->postJson("/api/register", $data)
->assertStatus(201)
->assertJson([
'requires_email_confirmation' => false
]);
$this->assertDatabaseHas('users', $expected);
}
/** @test */
public function register_user_with_email_confirmation()
{
$this->setSettings([
'reg_enabled' => true,
'reg_email_confirmation' => true,
'registration.captcha.enabled' => false,
'tos' => false
]);
Notification::fake();
$data = [
'email' => 'john.doe@test.com',
'username' => 'john.doe',
'password' => '123123123',
'password_confirmation' => '123123123'
];
$expected = Arr::except($data, ['password', 'password_confirmation']);
$this->postJson("/api/register", $data)
->assertStatus(201)
->assertJson(['requires_email_confirmation' => true]);
$this->assertDatabaseHas('users', $expected);
$user = User::where('email', $data['email'])->first();
Notification::assertSentTo($user, VerifyEmail::class);
}
/** @test */
public function register_with_tos()
{
$this->setSettings([
'reg_enabled' => true,
'reg_email_confirmation' => false,
'registration.captcha.enabled' => false,
'tos' => true
]);
$data = [
'email' => 'john.doe@test.com',
'username' => 'john.doe',
'password' => '123123123',
'password_confirmation' => '123123123'
];
$this->postJson("/api/register", $data)
->assertStatus(422)
->assertJsonFragment([
'tos' => ["You have to accept Terms of Service."]
]);
}
}
@@ -0,0 +1,165 @@
<?php
namespace Tests\Feature\Api\Auth;
use Carbon\Carbon;
use Laravel\Socialite\Contracts\User as SocialUserContract;
use Laravel\Socialite\Two\FacebookProvider;
use Mockery as m;
use Tests\Feature\ApiTestCase;
use Vanguard\Repositories\User\UserRepository;
use Vanguard\Support\Enum\UserStatus;
use Vanguard\User;
class SocialLoginControllerTest extends ApiTestCase
{
/** @test */
public function social_authentication_for_first_time()
{
$this->setSettings(['reg_enabled' => true]);
$socialUser = new StubSocialUser;
$this->mockFacebookProvider($socialUser);
$now = Carbon::now()->addHours(2);
Carbon::setTestNow($now);
$this->postJson("/api/login/social", $this->defaultParams())
->assertOk();
$user = User::whereEmail($socialUser->getEmail())->first();
$this->assertDatabaseHas('users', [
'first_name' => 'John',
'last_name' => 'Doe',
'email' => $socialUser->getEmail(),
'status' => UserStatus::ACTIVE,
'avatar' => $socialUser->getAvatar(),
'last_login' => $now
]);
$this->assertDatabaseHas('social_logins', [
'user_id' => $user->id,
'provider' => 'facebook',
'provider_id' => $socialUser->getId(),
'avatar' => $socialUser->getAvatar()
]);
}
/** @test */
public function associate_social_account_with_existing_user()
{
$this->setSettings(['reg_enabled' => true]);
$socialUser = new StubSocialUser;
$this->mockFacebookProvider($socialUser);
$user = User::factory()->create([
'email' => $socialUser->getEmail()
]);
$this->postJson("/api/login/social", $this->defaultParams())
->assertOk();
$this->assertDatabaseHas('social_logins', [
'user_id' => $user->id,
'provider' => 'facebook',
'provider_id' => $socialUser->getId(),
'avatar' => $socialUser->getAvatar()
]);
}
/** @test */
public function social_login_if_registration_is_disabled()
{
$this->setSettings(['reg_enabled' => false]);
$socialUser = new StubSocialUser;
$this->mockFacebookProvider($socialUser);
$this->postJson("/api/login/social", $this->defaultParams())
->assertForbidden()
->assertJson([
'message' => "Only users who already created an account can log in."
]);
}
/** @test */
public function social_login_with_invalid_provider()
{
$this->postJson("/api/login/social", $this->defaultParams(['network' => 'foo']))
->assertStatus(422)
->assertJsonValidationErrors('network');
}
/** @test */
public function social_login_for_banned_user()
{
$socialUser = new StubSocialUser;
$this->mockFacebookProvider($socialUser);
$user = User::factory()->create([
'email' => $socialUser->getEmail(),
'status' => UserStatus::BANNED
]);
app(UserRepository::class)->associateSocialAccountForUser($user->id, 'facebook', $socialUser);
$this->postJson("/api/login/social", $this->defaultParams())
->assertForbidden()
->assertJson([
'message' => 'Your account is banned by administrators.'
]);
}
private function defaultParams(array $overrides = [])
{
return array_merge([
'network' => 'facebook',
'social_token' => 'foo',
'device_name' => 'test',
], $overrides);
}
private function mockFacebookProvider($socialUser)
{
$provider = m::mock(FacebookProvider::class);
$provider->shouldReceive('userFromToken')->with('foo')->andReturn($socialUser);
\Socialite::shouldReceive('driver')->with('facebook')->andReturn($provider);
}
}
class StubSocialUser implements SocialUserContract
{
public $avatar_original = 'http://www.gravatar.com/avatar';
public function getId()
{
return '123';
}
public function getNickname()
{
return 'johndoe';
}
public function getName()
{
return 'John Doe';
}
public function getEmail()
{
return 'john@doe.com';
}
public function getAvatar()
{
return 'http://www.gravatar.com/avatar';
}
}
@@ -0,0 +1,157 @@
<?php
namespace Tests\Feature\Api\Authorization;
use Facades\Tests\Setup\UserFactory;
use Tests\Feature\ApiTestCase;
use Vanguard\Http\Resources\PermissionResource;
use Vanguard\Permission;
use Vanguard\User;
class PermissionsControllerTest extends ApiTestCase
{
/** @test */
public function unauthenticated()
{
$this->getJson('/api/permissions')->assertStatus(401);
}
/** @test */
public function get_users_without_permission()
{
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)
->getJson('/api/permissions')
->assertForbidden();
}
/** @test */
public function get_permissions()
{
Permission::factory()->times(3)->create();
$response = $this->actingAs($this->getUser(), self::API_GUARD)
->getJson("/api/permissions")
->assertOk();
// 7 default permissions + 3 newly created
$this->assertCount(10, $response->original);
}
/** @test */
public function get_permission()
{
$permission = Permission::factory()->create();
$this->actingAs($this->getUser(), self::API_GUARD)
->getJson("/api/permissions/{$permission->id}")
->assertOk()
->assertJson([
'data' => (new PermissionResource($permission))->toArray(request())
]);
}
/** @test */
public function create_permission()
{
$data = [
'name' => 'foo',
'display_name' => 'Foo Permission',
'description' => 'This is foo permission.'
];
$this->actingAs($this->getUser(), self::API_GUARD)
->postJson("/api/permissions", $data)
->assertStatus(201)
->assertJsonFragment($data);
$this->assertDatabaseHas('permissions', $data);
}
/** @test */
public function create_permission_with_invalid_name()
{
$this->actingAs($this->getUser(), self::API_GUARD)
->postJson("/api/permissions")
->assertStatus(422)
->assertJsonValidationErrors('name');
$existingPermission = Permission::first();
$this->postJson("/api/permissions", ['name' => $existingPermission->name])
->assertStatus(422)
->assertJsonValidationErrors('name');
$this->postJson("/api/permissions", ['name' => 'foo bar'])
->assertStatus(422)
->assertJsonValidationErrors('name');
}
/** @test */
public function partially_update_permission()
{
$this->getUser();
$permission = Permission::factory()->create();
$data = ['name' => 'foo'];
$expected = $data + ['id' => $permission->id];
$this->actingAs($this->getUser(), self::API_GUARD)
->patchJson("/api/permissions/{$permission->id}", $data)
->assertJsonFragment($expected);
$this->assertDatabaseHas('permissions', $expected);
}
/** @test */
public function update_permission()
{
$permission = Permission::factory()->create();
$data = [
'name' => 'foo',
'display_name' => 'Foo Role',
'description' => 'This is foo role.'
];
$expected = $data + ['id' => $permission->id];
$this->actingAs($this->getUser(), self::API_GUARD)
->patchJson("/api/permissions/{$permission->id}", $data)
->assertJsonFragment($expected);
$this->assertDatabaseHas('permissions', $expected);
}
/** @test */
public function remove_permission()
{
$permission = Permission::factory()->create(['removable' => true]);
$this->actingAs($this->getUser(), self::API_GUARD)
->deleteJson("/api/permissions/{$permission->id}")
->assertOk()
->assertJson(['success' => true]);
$this->assertDatabaseMissing('permissions', ['id' => $permission->id]);
}
/** @test */
public function remove_non_removable_permission()
{
$permission = Permission::factory()->create(['removable' => false]);
$this->actingAs($this->getUser(), self::API_GUARD)
->deleteJson("/api/permissions/{$permission->id}")
->assertStatus(403);
}
/**
* @return mixed
*/
private function getUser()
{
return UserFactory::user()->withPermissions('permissions.manage')->create();
}
}
@@ -0,0 +1,91 @@
<?php
namespace Tests\Feature\Api\Authorization;
use Facades\Tests\Setup\UserFactory;
use Tests\Feature\ApiTestCase;
use Vanguard\Http\Resources\PermissionResource;
use Vanguard\Permission;
use Vanguard\Role;
use Vanguard\User;
class RolePermissionsControllerTest extends ApiTestCase
{
/** @test */
public function unauthenticated()
{
$role = Role::factory()->create();
$this->getJson("/api/roles/{$role->id}/permissions")
->assertStatus(401);
}
/** @test */
public function get_settings_without_permission()
{
$role = Role::factory()->create();
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)
->getJson("/api/roles/{$role->id}/permissions")
->assertStatus(403);
}
/** @test */
public function get_role_permissions()
{
$role = Role::factory()->create();
$permission = Permission::factory()->create();
$role->attachPermission($permission);
$this->actingAs($this->getUser(), self::API_GUARD)
->getJson("/api/roles/{$role->id}/permissions")
->assertOk()
->assertJsonFragment(
PermissionResource::collection([$permission])->toArray(request())
);
}
/** @test */
public function update_role_permissions()
{
$role = Role::factory()->create();
$permissions1 = Permission::factory()->times(2)->create();
$permissions2 = Permission::factory()->times(3)->create();
$role->attachPermissions($permissions1);
$this->actingAs($this->getUser(), self::API_GUARD)
->putJson("/api/roles/{$role->id}/permissions", [
'permissions' => $permissions2->pluck('id')
])
->assertOk()
->assertJsonFragment(
(new PermissionResource($permissions2[0]))->toArray(null)
)
->assertJsonFragment(
(new PermissionResource($permissions2[1]))->toArray(null)
)
->assertJsonFragment(
(new PermissionResource($permissions2[2]))->toArray(null)
);
foreach ($permissions2 as $perm) {
$this->assertDatabaseHas('permission_role', [
'permission_id' => $perm->id,
'role_id' => $role->id
]);
}
}
/**
* @return mixed
*/
private function getUser()
{
return UserFactory::user()->withPermissions('permissions.manage')->create();
}
}
@@ -0,0 +1,162 @@
<?php
namespace Tests\Feature\Api\Authorization;
use Facades\Tests\Setup\RoleFactory;
use Facades\Tests\Setup\UserFactory;
use Tests\Feature\ApiTestCase;
use Vanguard\Http\Resources\RoleResource;
use Vanguard\Role;
use Vanguard\User;
class RolesControllerTest extends ApiTestCase
{
/** @test */
public function unauthenticated()
{
$this->getJson('/api/roles')
->assertStatus(401);
}
/** @test */
public function get_settings_without_permission()
{
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)
->getJson('/api/roles')
->assertStatus(403);
}
/** @test */
public function get_roles()
{
Role::factory()->times(4)->create();
$response = $this->actingAs($this->getUser(), self::API_GUARD)
->getJson("/api/roles")
->assertOk();
$this->assertCount(7, $response->original);
}
/** @test */
public function get_role()
{
$userRole = Role::whereName('User')->first();
$this->actingAs($this->getUser(), self::API_GUARD)
->getJson("/api/roles/{$userRole->id}")
->assertOk()
->assertJson([
'data' => (new RoleResource($userRole))->resolve()
]);
}
/** @test */
public function create_role()
{
$this->getUser();
$data = [
'name' => 'foo',
'display_name' => 'Foo Role',
'description' => 'This is foo role.'
];
$this->actingAs($this->getUser(), self::API_GUARD)
->postJson("/api/roles", $data)
->assertStatus(201)
->assertJsonFragment($data);
$this->assertDatabaseHas('roles', $data);
}
/** @test */
public function create_role_with_invalid_name()
{
$this->be($this->getUser(), self::API_GUARD);
$this->postJson("/api/roles")
->assertStatus(422)
->assertJsonValidationErrors('name');
$this->postJson("/api/roles", ['name' => 'User'])
->assertStatus(422)
->assertJsonValidationErrors('name');
$this->postJson("/api/roles", ['name' => 'foo bar'])
->assertStatus(422)
->assertJsonValidationErrors('name');
}
/** @test */
public function update_role()
{
$user = $this->getUser();
$data = ['name' => 'foo'];
$expected = $data + ['id' => $user->role_id];
$this->actingAs($user, self::API_GUARD)
->patchJson("/api/roles/{$user->role_id}", $data)
->assertOk()
->assertJsonFragment($expected);
$this->assertDatabaseHas('roles', $expected);
}
/** @test */
public function partially_update_role()
{
$user = $this->getUser();
$data = [
'name' => 'foo',
'display_name' => 'Foo Role',
'description' => 'This is foo role.'
];
$expected = $data + ['id' => $user->role_id];
$this->actingAs($user, self::API_GUARD)
->patchJson("/api/roles/{$user->role_id}", $data)
->assertOk()
->assertJsonFragment($expected);
$this->assertDatabaseHas('roles', $expected);
}
/** @test */
public function remove_role()
{
$userRole = Role::whereName('User')->first();
$role = RoleFactory::removable()->withPermissions('roles.manage')->create();
$user = UserFactory::role($role)->create();
$this->actingAs($user, self::API_GUARD)
->deleteJson("/api/roles/{$role->id}")
->assertOk()
->assertJson(['success' => true]);
$this->assertDatabaseMissing('roles', ['id' => $role->id]);
$this->assertEquals($userRole->id, $user->fresh()->role_id);
}
/** @test */
public function remove_non_removable_role()
{
$role = RoleFactory::withPermissions('roles.manage')->create();
$this->actingAs($this->getUser(), self::API_GUARD)
->deleteJson("/api/roles/{$role->id}")
->assertForbidden();
}
/**
* @return mixed
*/
private function getUser()
{
return UserFactory::user()->withPermissions('roles.manage')->create();
}
}
@@ -0,0 +1,28 @@
<?php
namespace Tests\Feature\Api;
use Tests\Feature\ApiTestCase;
use Vanguard\Country;
use Vanguard\Http\Resources\CountryResource;
class CountriesControllerTest extends ApiTestCase
{
/** @test */
public function unauthenticated()
{
$this->getJson('/api/countries')->assertStatus(401);
}
/** @test */
public function get_all_countries()
{
$this->login();
$this->getJson("/api/countries")
->assertOk()
->assertJson([
'data' => CountryResource::collection(Country::all())->resolve()
]);
}
}
@@ -0,0 +1,83 @@
<?php
namespace Tests\Feature\Api\Profile;
use Facades\Tests\Setup\UserFactory;
use Tests\Feature\ApiTestCase;
class AuthDetailsControllerTest extends ApiTestCase
{
/** @test */
public function user_can_update_his_authentication_details()
{
$user = $this->login();
$this->patch('/api/me/details/auth', [
'email' => 'foo@example.com',
'username' => 'john.doe',
'password' => '12345678',
'password_confirmation' => '12345678'
])->assertOk()
->assertJsonFragment(['email' => 'foo@example.com', 'username' => 'john.doe']);
$this->assertTrue(password_verify('12345678', $user->fresh()->password));
}
/** @test */
public function user_can_update_only_email_and_leave_other_fields_unchanged()
{
$user = $this->login();
$this->patch('/api/me/details/auth', [
'email' => 'foo@example.com',
])->assertOk()
->assertJsonFragment(['email' => 'foo@example.com']);
$this->assertEquals($user->username, $user->fresh()->username);
$this->assertEquals($user->password, $user->fresh()->password);
}
/** @test */
public function email_field_is_required()
{
$this->login();
$this->patch('/api/me/details/auth')
->assertJsonValidationErrors('email');
}
/** @test */
public function email_field_must_be_valid_email()
{
$this->login();
$this->patch('/api/me/details/auth', [
'email' => 'invalid email'
])->assertJsonValidationErrors('email');
}
/** @test */
public function email_field_must_be_unique()
{
$this->login();
UserFactory::email('john.doe@test.com')->create();
$this->patch('/api/me/details/auth', [
'email' => 'john.doe@test.com',
])->assertJsonValidationErrors('email');
}
/** @test */
public function username_field_must_be_unique()
{
$this->login();
UserFactory::withCredentials('john.doe', '123123')->create();
$this->patch('/api/me/details/auth', [
'email' => 'john.doe@test.com',
'username' => 'john.doe'
])->assertJsonValidationErrors('username');
}
}
@@ -0,0 +1,97 @@
<?php
namespace Tests\Feature\Api\Profile;
use Illuminate\Http\UploadedFile;
use Storage;
use Tests\Feature\ApiTestCase;
class AvatarControllerTest extends ApiTestCase
{
/** @test */
public function only_authenticated_user_can_update_avatar()
{
$this->post('/api/me/avatar')->assertStatus(401);
}
/** @test */
public function upload_avatar_image()
{
$this->login();
Storage::fake('public');
$file = UploadedFile::fake()->image('avatar.png', 500, 500);
$response = $this->post('api/me/avatar', [
'file' => $file
]);
$this->assertNotNull($response->json('data.avatar'));
$uploadedFile = str_replace(url(''), '', $response->json('data.avatar'));
$uploadedFile = ltrim($uploadedFile, "/");
Storage::disk('public')->assertExists($uploadedFile);
list($width, $height) = getimagesizefromstring(
Storage::disk('public')->get($uploadedFile)
);
$this->assertEquals(160, $width);
$this->assertEquals(160, $height);
}
/** @test */
public function upload_invalid_image()
{
$this->login();
Storage::fake('public');
$file = UploadedFile::fake()->create('avatar.txt', 500);
$this->post('/api/me/avatar', ['file' => $file])
->assertStatus(422)
->assertJsonFragment([
'file' => [
trans('validation.image', ['attribute' => 'file'])
]
]);
}
/** @test */
public function update_avatar_from_external_source()
{
$this->login();
$url = 'http://google.com';
$this->putJson('/api/me/avatar/external', ['url' => $url])
->assertOk()
->assertJsonFragment(['avatar' => $url]);
}
/** @test */
public function update_avatar_with_invalid_external_source()
{
$this->login();
$this->putJson('/api/me/avatar/external', ['url' => 'foo'])
->assertStatus(422);
}
/** @test */
public function delete_avatar()
{
$user = $this->login();
$user->forceFill(['avatar' => 'http://google.com'])->save();
$this->deleteJson("api/me/avatar")
->assertOk()
->assertJsonFragment([
'avatar' => url('assets/img/profile.png') // default profile image
]);
}
}
@@ -0,0 +1,121 @@
<?php
namespace Tests\Feature\Api\Profile;
use Carbon\Carbon;
use Tests\Feature\ApiTestCase;
use Vanguard\Http\Resources\UserResource;
class DetailsControllerTest extends ApiTestCase
{
/** @test */
public function get_user_profile_unauthenticated()
{
$this->getJson('/api/me')->assertStatus(401);
}
/** @test */
public function get_user_profile()
{
$user = $this->login();
$this->getJson('/api/me')
->assertOk()
->assertJson(['data' => (new UserResource($user))->resolve()]);
}
/** @test */
public function update_user_profile_unauthenticated()
{
$this->patchJson('/api/me/details')->assertStatus(401);
}
/** @test */
public function update_user_profile()
{
$user = $this->login();
$data = $this->getData();
$response = $this->patchJson("/api/me/details", $data);
$transformed = (new UserResource($user->fresh()))->resolve();
$response->assertJsonFragment($transformed);
$this->assertDatabaseHas('users', array_merge($data, ['id' => $user->id]));
}
/** @test */
public function partially_update_user_details()
{
$user = $this->login();
$data = [
'first_name' => 'John',
'last_name' => 'Doe'
];
$response = $this->patchJson("/api/me/details", $data);
$transformed = (new UserResource($user->fresh()))->resolve();
$response->assertJsonFragment($transformed);
$this->assertDatabaseHas('users', array_merge($data, [
'id' => $user->id,
'birthday' => $user->birthday->format('Y-m-d'),
'phone' => $user->phone,
'address' => $user->address,
'country_id' => $user->country_id,
]));
}
/** @test */
public function update_without_country_id()
{
$user = $this->login();
$data = $this->getData();
unset($data['country_id']);
$response = $this->patchJson("/api/me/details", $data);
$transformed = (new UserResource($user->fresh()))->resolve();
$response->assertJsonFragment($transformed);
$this->assertDatabaseHas('users', array_merge($data, ['id' => $user->id]));
}
/** @test */
public function update_with_invalid_date_format()
{
$this->login();
$this->patchJson("/api/me/details", ['birthday' => 'foo'])
->assertStatus(422)
->assertJsonFragment([
'birthday' => [
trans('validation.date', ['attribute' => 'birthday'])
]
]);
}
/**
* @param array $attrs
* @return array
*/
private function getData(array $attrs = [])
{
return array_merge([
'first_name' => 'John',
'last_name' => 'Doe',
'birthday' => Carbon::now()->subYears(25)->format('Y-m-d'),
'phone' => '(123) 456 789',
'address' => 'some address 1',
'country_id' => 688,
], $attrs);
}
}
@@ -0,0 +1,66 @@
<?php
namespace Tests\Feature\Api\Profile;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Tests\Feature\ApiTestCase;
use Vanguard\Http\Resources\SessionResource;
use Vanguard\Repositories\Session\SessionRepository;
use Vanguard\User;
class SessionsControllerTest extends ApiTestCase
{
/** @test */
public function get_user_sessions_unauthenticated()
{
$this->getJson('/api/me/sessions')->assertStatus(401);
}
/** @test */
public function get_sessions_if_non_database_driver_is_used()
{
config(['session.driver' => 'array']);
$this->login();
$this->getJson('/api/me/sessions')->assertStatus(404);
}
/** @test */
public function get_user_sessions()
{
config(['session.driver' => 'database']);
$user = $this->login();
$sessions = $this->generateNonExpiredSessions($user);
$this->getJson('/api/me/sessions')
->assertOk()
->assertJsonFragment([
'data' => SessionResource::collection($sessions)->resolve()
]);
}
private function generateNonExpiredSessions(User $user, $count = 5)
{
$sessions = [];
$faker = $this->app->make(\Faker\Generator::class);
for ($i = 0; $i < $count; $i++) {
array_push($sessions, [
'id' => Str::random(40),
'user_id' => $user->id,
'ip_address' => $faker->ipv4,
'user_agent' => $faker->userAgent,
'payload' => Str::random(),
'last_activity' => Carbon::now()->subMinute()->timestamp
]);
}
\DB::table('sessions')->insert($sessions);
return app(SessionRepository::class)->getUserSessions($user->id);
}
}
@@ -0,0 +1,163 @@
<?php
namespace Tests\Feature\Api\Profile;
use Authy;
use Event;
use Mockery;
use Tests\Feature\ApiTestCase;
use Vanguard\Events\User\TwoFactorEnabled;
use Vanguard\Http\Resources\UserResource;
use Vanguard\User;
class TwoFactorControllerTest extends ApiTestCase
{
/** @test */
public function update_2fa_unathenticated()
{
$this->setSettings(['2fa.enabled' => true]);
User::factory()->create();
$this->putJson("api/me/2fa")
->assertStatus(401);
}
/** @test */
public function enable_two_factor_auth()
{
$this->setSettings(['2fa.enabled' => true]);
$this->withoutExceptionHandling();
Event::fake([
TwoFactorEnabled::class,
]);
$user = $this->login();
Authy::shouldReceive('isEnabled')->andReturn(false);
Authy::shouldReceive('register')->andReturnNull();
Authy::shouldReceive('sendTwoFactorVerificationToken');
$data = ['country_code' => '1', 'phone_number' => '123'];
$this->putJson("api/me/2fa", $data)
->assertOk()
->assertJson(['message' => 'Verification token sent.']);
$this->assertDatabaseHas('users', [
'id' => $user->id,
'two_factor_country_code' => $data['country_code'],
'two_factor_phone' => $data['phone_number']
]);
Event::assertNotDispatched(TwoFactorEnabled::class);
}
/** @test */
public function verify_user_phone_with_correct_token()
{
$this->setSettings(['2fa.enabled' => true]);
Event::fake([
TwoFactorEnabled::class,
]);
$user = $this->login();
Authy::shouldReceive('isEnabled')->andReturn(false);
Authy::shouldReceive('tokenIsValid')->with(Mockery::any(), '123123')->andReturn(true);
$response = $this->postJson("api/me/2fa/verify", ['token' => '123123']);
$updatedUser = (new UserResource($user->fresh()))->resolve();
$response->assertOk()
->assertJsonFragment($updatedUser);
$this->assertDatabaseHas('users', [
'id' => $user->id,
'two_factor_options' => '{"enabled":true}'
]);
Event::assertDispatched(TwoFactorEnabled::class);
}
/** @test */
public function verify_user_phone_with_invalid_token()
{
$this->setSettings(['2fa.enabled' => true]);
$user = $this->login();
Authy::shouldReceive('isEnabled')->andReturn(false);
Authy::shouldReceive('tokenIsValid')->andReturn(false);
$this->postJson("api/me/2fa/verify", ['token' => '123123'])
->assertStatus(422)
->assertJson(['message' => 'Invalid 2FA token.']);
$this->assertDatabaseMissing('users', [
'id' => $user->id,
'two_factor_options' => '{"enabled":true}'
]);
}
/** @test */
public function enable_two_factor_auth_when_it_is_already_enabled()
{
$this->setSettings(['2fa.enabled' => true]);
$this->login();
Authy::shouldReceive('isEnabled')->andReturn(true);
$data = ['country_code' => '1', 'phone_number' => '123'];
$this->putJson("api/me/2fa", $data)
->assertStatus(422)
->assertJson([
'message' => '2FA is already enabled for this user.'
]);
}
/** @test */
public function disable_two_factor_auth()
{
$this->setSettings(['2fa.enabled' => true]);
$user = User::factory()->create([
'two_factor_country_code' => '1',
'two_factor_phone' => '123'
]);
$this->be($user, self::API_GUARD);
Authy::shouldReceive('isEnabled')->andReturn(true);
Authy::shouldReceive('delete')->andReturnNull();
$response = $this->deleteJson("api/me/2fa");
$user = (new UserResource($user->fresh()))->resolve();
$response->assertOk()
->assertJsonFragment($user);
}
/** @test */
public function disable_2fa_when_it_is_already_disabled()
{
$this->setSettings(['2fa.enabled' => true]);
$this->login();
Authy::shouldReceive('isEnabled')->andReturn(false);
$this->deleteJson("api/me/2fa")
->assertStatus(422)
->assertJson([
'message' => '2FA is not enabled for this user.'
]);
}
}
@@ -0,0 +1,113 @@
<?php
namespace Tests\Feature\Api;
use Carbon\Carbon;
use Facades\Tests\Setup\UserFactory;
use Illuminate\Support\Str;
use Tests\Feature\ApiTestCase;
use Vanguard\Http\Resources\SessionResource;
use Vanguard\Repositories\Session\SessionRepository;
use Vanguard\User;
class SessionsControllerTest extends ApiTestCase
{
protected function setUp(): void
{
parent::setUp();
config(['session.driver' => 'database']);
}
/** @test */
public function unauthenticated()
{
$user = User::factory()->create();
$session = $this->createSession($user);
$this->getJson("/api/sessions/{$session->id}")
->assertStatus(401);
}
/** @test */
public function get_session_which_belongs_to_other_user()
{
$this->login();
$user2 = User::factory()->create();
$session = $this->createSession($user2);
$this->getJson("/api/sessions/{$session->id}")
->assertStatus(403);
}
/** @test */
public function get_session()
{
$user = $this->login();
$session = $this->createSession($user);
$this->getJson("/api/sessions/{$session->id}")
->assertStatus(200)
->assertJson([
'data' => (new SessionResource($session))->resolve()
]);
}
/** @test */
public function invalidate_his_own_session()
{
$user = $this->login();
$session = $this->createSession($user);
$this->deleteJson("/api/sessions/{$session->id}")
->assertStatus(200)
->assertJson(['success' => true]);
}
/** @test */
public function invalidate_session_for_other_user()
{
$user = UserFactory::withPermissions('users.manage')->create();
$user2 = User::factory()->create();
$session = $this->createSession($user2);
$this->actingAs($user, self::API_GUARD)
->deleteJson("/api/sessions/{$session->id}")
->assertOk()
->assertJson(['success' => true]);
}
/** @test */
public function invalidate_session_for_other_user_without_permission()
{
$this->login();
$user2 = User::factory()->create();
$session = $this->createSession($user2);
$this->deleteJson("/api/sessions/{$session->id}")
->assertStatus(403);
}
private function createSession(User $user)
{
$sessionId = Str::random(40);
$data = [
'id' => $sessionId,
'user_id' => $user->id,
'ip_address' => "127.0.0.1",
'user_agent' => 'foo',
'payload' => Str::random(),
'last_activity' => Carbon::now()->timestamp
];
\DB::table('sessions')->insert($data);
return app(SessionRepository::class)->find($sessionId);
}
}
@@ -0,0 +1,38 @@
<?php
namespace Tests\Feature\Api;
use Facades\Tests\Setup\UserFactory;
use Setting;
use Tests\Feature\ApiTestCase;
use Vanguard\User;
class SettingsControllerTest extends ApiTestCase
{
/** @test */
public function only_authenticated_users_can_view_app_settings()
{
$this->getJson('/api/settings')->assertStatus(401);
}
/** @test */
public function get_settings_without_permission()
{
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)
->getJson('/api/settings')
->assertStatus(403);
}
/** @test */
public function get_settings()
{
$user = UserFactory::withPermissions('settings.general')->create();
$this->actingAs($user, self::API_GUARD)
->getJson("/api/settings")
->assertOk()
->assertJson(Setting::all());
}
}
+73
View File
@@ -0,0 +1,73 @@
<?php
namespace Tests\Feature\Api;
use Carbon\Carbon;
use Tests\Feature\ApiTestCase;
use Vanguard\Http\Resources\UserResource;
use Vanguard\Repositories\User\UserRepository;
use Vanguard\Role;
use Vanguard\Support\Enum\UserStatus;
use Vanguard\User;
class StatsControllerTest extends ApiTestCase
{
/** @test */
public function unauthenticated()
{
$this->getJson('/api/stats')->assertStatus(401);
}
/** @test */
public function get_stats_as_admin()
{
\DB::table('users')->delete();
$adminRole = Role::whereName('Admin')->first();
$user = User::factory()->create(['role_id' => $adminRole->id]);
$this->be($user, self::API_GUARD);
Carbon::setTestNow(Carbon::now()->startOfYear());
User::factory()->times(4)->create(['status' => UserStatus::ACTIVE]);
Carbon::setTestNow(null);
User::factory()->times(2)->create(['status' => UserStatus::BANNED]);
User::factory()->times(7)->create(['status' => UserStatus::UNCONFIRMED]);
$users = app(UserRepository::class);
$response = $this->getJson("/api/stats");
$usersPerMonth = $users->countOfNewUsersPerMonth(
now()->subYear()->startOfMonth(),
now()->endOfMonth()
);
$latestRegistrations = $users->latest(7);
$response->assertOk()
->assertJson([
'users_per_month' => $usersPerMonth,
'users_per_status' => [
'total' => 14,
'new' => $users->newUsersCount(),
'banned' => 2,
'unconfirmed' => 7
],
'latest_registrations' => UserResource::collection($latestRegistrations)->resolve()
]);
}
/** @test */
public function non_admin_users_cannot_get_user_stats()
{
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)->getJson("/api/stats")->assertForbidden();
}
}
@@ -0,0 +1,131 @@
<?php
namespace Tests\Feature\Api\Users;
use Facades\Tests\Setup\UserFactory;
use Illuminate\Http\UploadedFile;
use Storage;
use Tests\Feature\ApiTestCase;
use Vanguard\Events\User\TwoFactorEnabledByAdmin;
use Vanguard\Events\User\UpdatedByAdmin;
use Vanguard\User;
class AvatarControllerTest extends ApiTestCase
{
/** @test */
public function upload_user_avatar_unauthenticated()
{
$user = User::factory()->create();
$this->post("/api/users/{$user->id}/avatar")
->assertStatus(401);
}
/** @test */
public function upload_avatar_without_permission()
{
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)
->post("/api/users/{$user->id}/avatar")
->assertForbidden();
}
/** @test */
public function upload_avatar_image()
{
\Event::fake([UpdatedByAdmin::class]);
Storage::fake('public');
$user = UserFactory::withPermissions('users.manage')->create();
$file = UploadedFile::fake()->image('avatar.png', 500, 500);
$response = $this->actingAs($user, self::API_GUARD)
->post("/api/users/{$user->id}/avatar", ['file' => $file])
->assertOk();
$avatar = $response->json('data.avatar');
$this->assertNotNull($avatar);
$uploadedFile = str_replace(url(''), '', $avatar);
$uploadedFile = ltrim($uploadedFile, "/");
Storage::disk('public')->assertExists($uploadedFile);
list($width, $height) = getimagesizefromstring(
Storage::disk('public')->get($uploadedFile)
);
$this->assertEquals(160, $width);
$this->assertEquals(160, $height);
\Event::assertDispatched(UpdatedByAdmin::class);
}
/** @test */
public function upload_invalid_image()
{
$user = UserFactory::withPermissions('users.manage')->create();
Storage::fake('public');
$file = UploadedFile::fake()->create('avatar.txt', 500);
$this->actingAs($user, self::API_GUARD)
->post("/api/users/{$user->id}/avatar", ['file' => $file])
->assertStatus(422)
->assertJsonFragment([
'file' => [
trans('validation.image', ['attribute' => 'file'])
]
]);
}
/** @test */
public function update_avatar_from_external_source()
{
\Event::fake([UpdatedByAdmin::class]);
$user = UserFactory::withPermissions('users.manage')->create();
$url = 'http://google.com';
$this->actingAs($user, self::API_GUARD)
->putJson("/api/users/{$user->id}/avatar/external", ['url' => $url])
->assertOk()
->assertJsonFragment(['avatar' => $url]);
\Event::assertDispatched(UpdatedByAdmin::class);
}
/** @test */
public function update_avatar_with_invalid_external_source()
{
$user = UserFactory::withPermissions('users.manage')->create();
$this->actingAs($user, self::API_GUARD)
->putJson("/api/users/{$user->id}/avatar/external", ['url' => 'foo'])
->assertStatus(422);
}
/** @test */
public function delete_user_avatar()
{
\Event::fake([UpdatedByAdmin::class]);
$user = UserFactory::withPermissions('users.manage')->create();
$user->forceFill(['avatar' => 'http://google.com'])->save();
$this->actingAs($user, self::API_GUARD)
->deleteJson("api/users/{$user->id}/avatar")
->assertOk()
->assertJsonFragment([
'avatar' => url('assets/img/profile.png') // default profile image
]);
\Event::assertDispatched(UpdatedByAdmin::class);
}
}
@@ -0,0 +1,70 @@
<?php
namespace Tests\Feature\Api\Users;
use Facades\Tests\Setup\UserFactory;
use Illuminate\Support\Str;
use Tests\Feature\ApiTestCase;
use Vanguard\Http\Resources\SessionResource;
use Vanguard\Repositories\Session\SessionRepository;
use Vanguard\User;
class SessionsControllerTest extends ApiTestCase
{
/** @test */
public function get_sessions_unauthenticated()
{
$user = User::factory()->create();
$this->getJson("/api/users/{$user->id}/sessions")->assertStatus(401);
}
/** @test */
public function get_user_sessions_without_permission()
{
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)
->getJson("/api/users/{$user->id}/sessions")
->assertForbidden();
}
/** @test */
public function get_user_sessions()
{
config(['session.driver' => 'database']);
$user = UserFactory::withPermissions('users.manage')->create();
$sessions = $this->generateNonExpiredSessions($user);
$this->actingAs($user, self::API_GUARD)
->getJson("/api/users/{$user->id}/sessions")
->assertOk()
->assertJson([
'data' => SessionResource::collection($sessions)->resolve()
]);
}
private function generateNonExpiredSessions(User $user, $count = 5)
{
$sessions = [];
$faker = $this->app->make(\Faker\Generator::class);
$lifetime = config('session.lifetime') - 1;
for ($i = 0; $i < $count; $i++) {
array_push($sessions, [
'id' => Str::random(40),
'user_id' => $user->id,
'ip_address' => $faker->ipv4,
'user_agent' => $faker->userAgent,
'payload' => Str::random(),
'last_activity' => $faker->dateTimeBetween("-{$lifetime} minutes")->getTimestamp()
]);
}
\DB::table('sessions')->insert($sessions);
return app(SessionRepository::class)->getUserSessions($user->id);
}
}
@@ -0,0 +1,174 @@
<?php
namespace Tests\Feature\Api\Users;
use Authy;
use Facades\Tests\Setup\UserFactory;
use Mockery;
use Tests\Feature\ApiTestCase;
use Vanguard\Events\User\TwoFactorDisabledByAdmin;
use Vanguard\Events\User\TwoFactorEnabledByAdmin;
use Vanguard\Http\Resources\UserResource;
use Vanguard\User;
class TwoFactorControllerTest extends ApiTestCase
{
/** @test */
public function update_2fa_unathenticated()
{
$this->setSettings(['2fa.enabled' => true]);
$user = User::factory()->create();
$this->putJson("api/users/{$user->id}/2fa")
->assertStatus(401);
}
/** @test */
public function update_2fa_without_permission()
{
$this->setSettings(['2fa.enabled' => true]);
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)
->putJson("api/users/{$user->id}/2fa")
->assertForbidden();
}
/** @test */
public function enable_two_factor_auth_for_user()
{
$this->setSettings(['2fa.enabled' => true]);
\Event::fake([TwoFactorEnabledByAdmin::class]);
$user = UserFactory::withPermissions('users.manage')->create();
Authy::shouldReceive('isEnabled')->andReturn(false);
Authy::shouldReceive('register')->andReturnNull();
Authy::shouldReceive('sendTwoFactorVerificationToken');
$data = ['country_code' => '1', 'phone_number' => '123'];
$this->actingAs($user, self::API_GUARD)->putJson("api/users/{$user->id}/2fa", $data)
->assertOk()
->assertJson(['message' => 'Verification token sent.']);
$this->assertDatabaseHas('users', [
'id' => $user->id,
'two_factor_country_code' => $data['country_code'],
'two_factor_phone' => $data['phone_number']
]);
\Event::assertNotDispatched(TwoFactorEnabledByAdmin::class);
}
/** @test */
public function verify_user_phone_with_correct_token()
{
$this->setSettings(['2fa.enabled' => true]);
\Event::fake([TwoFactorEnabledByAdmin::class]);
$user = UserFactory::withPermissions('users.manage')->create();
Authy::shouldReceive('isEnabled')->andReturn(false);
Authy::shouldReceive('tokenIsValid')->with(Mockery::any(), '123123')->andReturn(true);
$response = $this->actingAs($user, self::API_GUARD)
->postJson("api/users/{$user->id}/2fa/verify", ['token' => '123123']);
$updatedUser = (new UserResource($user->fresh()))->resolve();
$response->assertOk()
->assertJsonFragment($updatedUser);
$this->assertTrue($user->fresh()->getTwoFactorAuthProviderOptions()['enabled']);
\Event::assertDispatched(TwoFactorEnabledByAdmin::class);
}
/** @test */
public function verify_user_phone_with_invalid_token()
{
$this->setSettings(['2fa.enabled' => true]);
$user = UserFactory::withPermissions('users.manage')->create();
Authy::shouldReceive('isEnabled')->andReturn(false);
Authy::shouldReceive('tokenIsValid')->andReturn(false);
$this->actingAs($user, self::API_GUARD)
->postJson("api/users/{$user->id}/2fa/verify", ['token' => '123123'])
->assertStatus(422)
->assertJson([
'message' => 'Invalid 2FA token.'
]);
$this->assertDatabaseMissing('users', [
'id' => $user->id,
'two_factor_options' => '{"enabled":true}'
]);
}
/** @test */
public function enable_two_factor_auth_for_user_when_it_is_already_enabled()
{
$this->setSettings(['2fa.enabled' => true]);
$user = UserFactory::withPermissions('users.manage')->create();
Authy::shouldReceive('isEnabled')->andReturn(true);
$data = ['country_code' => '1', 'phone_number' => '123'];
$this->actingAs($user, self::API_GUARD)
->putJson("api/users/{$user->id}/2fa", $data)
->assertStatus(422)
->assertJson([
'message' => '2FA is already enabled for this user.'
]);
}
/** @test */
public function disable_two_factor_auth_for_user()
{
$this->setSettings(['2fa.enabled' => true]);
\Event::fake([TwoFactorDisabledByAdmin::class]);
$user = UserFactory::withPermissions('users.manage')->twoFactor('1', '123')->create();
$this->be($user, self::API_GUARD);
Authy::shouldReceive('isEnabled')->andReturn(true);
Authy::shouldReceive('delete')->andReturnNull();
$response = $this->deleteJson("api/users/{$user->id}/2fa");
$user = (new UserResource($user->fresh()))->resolve();
$response->assertOk()
->assertJsonFragment($user);
\Event::assertDispatched(TwoFactorDisabledByAdmin::class);
}
/** @test */
public function disable_2fa_for_user_when_it_is_already_disabled()
{
$this->setSettings(['2fa.enabled' => true]);
$user = UserFactory::withPermissions('users.manage')->create();
Authy::shouldReceive('isEnabled')->andReturn(false);
$this->actingAs($user, self::API_GUARD)
->deleteJson("api/users/{$user->id}/2fa")
->assertStatus(422)
->assertJson([
'message' => '2FA is not enabled for this user.'
]);
}
}
@@ -0,0 +1,260 @@
<?php
namespace Tests\Feature\Api\Users;
use Event;
use Facades\Tests\Setup\UserFactory;
use Illuminate\Support\Arr;
use Tests\Feature\ApiTestCase;
use Vanguard\Country;
use Vanguard\Events\User\Deleted;
use Vanguard\Events\User\UpdatedByAdmin;
use Vanguard\Http\Resources\UserResource;
use Vanguard\Role;
use Vanguard\Support\Enum\UserStatus;
use Vanguard\User;
class UsersControllerTest extends ApiTestCase
{
/** @test */
public function only_authenticated_users_can_list_all_users()
{
$this->getJson('/api/users')->assertStatus(401);
}
/** @test */
public function get_users_without_permission()
{
$user = User::factory()->create();
$this->actingAs($user, self::API_GUARD)
->getJson('/api/users')
->assertStatus(403);
}
/** @test */
public function paginate_all_users()
{
\DB::table('users')->delete();
$user = $this->login();
$users = User::factory()->times(20)->create();
$users->push($user);
$response = $this->getJson('/api/users');
$transformed = UserResource::collection($users->sortBy('id')->take(20))->resolve();
$this->assertEquals($response->json('data'), $transformed);
}
/** @test */
public function paginate_users_with_country_included()
{
$this->login();
$country = Country::factory()->create();
User::factory()->create(['country_id' => null]);
User::factory()->create(['country_id' => $country->id]);
$response = $this->getJson('/api/users?include=country')
->assertOk()
->json();
$this->assertNull($response['data'][0]['country']);
$this->assertNotNull($response['data'][1]['country_id']);
}
/** @test */
public function paginate_users_by_status()
{
$this->login();
User::factory()->times(2)->create(['status' => UserStatus::ACTIVE]);
User::factory()->times(5)->create(['status' => UserStatus::BANNED]);
$response = $this->getJson('/api/users?filter[status]=' . UserStatus::BANNED);
$this->assertCount(5, $response->json('data'));
}
/** @test */
public function paginate_users_on_search()
{
$user = $this->login();
$user1 = User::factory()->create([
'first_name' => 'John',
'last_name' => 'Doe',
'email' => 'john.doe@vanguardapp.io'
]);
$user2 = User::factory()->create([
'first_name' => 'Jane',
'last_name' => 'Doe',
'email' => 'jane.doe@vanguardapp.io'
]);
$user3 = User::factory()->create([
'first_name' => 'Brad',
'last_name' => 'Pitt',
'email' => 'b.pitt@vanguardapp.io'
]);
$response = $this->getJson('/api/users?filter[search]=doe');
$this->assertCount(2, $response->json('data'));
}
/** @test */
public function create_user()
{
$this->login();
$newUser = User::factory()->make();
$data = array_merge($newUser->toArray(), [
'birthday' => $newUser->birthday->format('Y-m-d'),
'role' => $newUser->role_id,
'password' => '123123',
'password_confirmation' => '123123'
]);
$response = $this->postJson('api/users', $data);
$expected = [
'first_name' => $newUser->first_name,
'last_name' => $newUser->last_name,
'email' => $newUser->email,
'username' => $newUser->username,
'country_id' => $newUser->country_id,
'birthday' => $newUser->birthday->format('Y-m-d'),
'phone' => $newUser->phone,
'address' => $newUser->address,
'status' => UserStatus::ACTIVE,
'role_id' => $newUser->role_id
];
$response->assertStatus(201)
->assertJsonFragment($expected);
$this->assertDatabaseHas('users', $expected);
}
/** @test */
public function get_user()
{
$user = $this->login();
$this->getJson("api/users/{$user->id}")
->assertOk()
->assertJson([
'data' => (new UserResource($user->fresh()))->resolve()
]);
}
/** @test */
public function get_user_which_does_not_exist()
{
$this->login();
$this->getJson("api/users/222")->assertStatus(404);
}
/** @test */
public function update_user()
{
Event::fake([UpdatedByAdmin::class]);
$user = $this->login();
$data = [
'email' => 'john.doe@test.com',
'username' => 'john.doe',
'password' => '123123',
'password_confirmation' => '123123',
'first_name' => 'John',
'last_name' => 'Doe',
'phone' => '+38123456789',
'address' => 'Some random address',
'country_id' => Country::first()->id,
'birthday' => '1990-10-18',
'status' => UserStatus::BANNED,
'role_id' => Role::whereName('User')->first()->id
];
$expected = Arr::except($data, ['password', 'password_confirmation']);
$expected += ['id' => $user->id];
$this->patchJson("api/users/{$user->id}", $data)
->assertOk()
->assertJsonFragment($expected);
$this->assertDatabaseHas('users', $expected);
Event::assertDispatched(UpdatedByAdmin::class);
}
/** @test */
public function update_only_specific_field()
{
Event::fake([UpdatedByAdmin::class]);
$user = $this->login();
$data = ['email' => 'john.doe@test.com'];
$expected = array_merge(
$user->toArray(),
$data,
['birthday' => $user->birthday->format('Y-m-d')]
);
$expected = Arr::except($expected, ['created_at', 'updated_at', 'avatar', 'role']);
$this->patchJson("api/users/{$user->id}", $data)
->assertOk()
->assertJsonFragment($expected);
$this->assertDatabaseHas('users', $expected);
Event::assertDispatched(UpdatedByAdmin::class);
}
/** @test */
public function delete_user()
{
Event::fake([Deleted::class]);
$user = $this->login();
$user2 = User::factory()->create();
$this->deleteJson("api/users/{$user2->id}")
->assertOk()
->assertJson(['success' => true]);
Event::assertDispatched(Deleted::class);
}
/** @test */
public function delete_yourself()
{
$user = $this->login();
$this->deleteJson("api/users/{$user->id}")
->assertStatus(403)
->assertJson(['message' => "You cannot delete yourself."]);
}
protected function login()
{
$user = UserFactory::withPermissions('users.manage')->create();
$this->be($user, self::API_GUARD);
return $user;
}
}