Initialer Laravel Commit für BetiX
This commit is contained in:
20
tests/CreatesApplication.php
Normal file
20
tests/CreatesApplication.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
|
||||
trait CreatesApplication
|
||||
{
|
||||
/**
|
||||
* Creates the application.
|
||||
*/
|
||||
public function createApplication()
|
||||
{
|
||||
$app = require __DIR__.'/../bootstrap/app.php';
|
||||
|
||||
$app->make(Kernel::class)->bootstrap();
|
||||
|
||||
return $app;
|
||||
}
|
||||
}
|
||||
90
tests/Feature/Auth/AuthenticationTest.php
Normal file
90
tests/Feature/Auth/AuthenticationTest.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Laravel\Fortify\Features;
|
||||
|
||||
test('login screen can be rendered', function () {
|
||||
$response = $this->get(route('login'));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('users can authenticate using the login screen', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->post(route('login'), [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
});
|
||||
|
||||
test('users with two factor enabled are redirected to two factor challenge', function () {
|
||||
if (! Features::canManageTwoFactorAuthentication()) {
|
||||
$this->markTestSkipped('Two-factor authentication is not enabled.');
|
||||
}
|
||||
|
||||
Features::twoFactorAuthentication([
|
||||
'confirm' => true,
|
||||
'confirmPassword' => true,
|
||||
]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$user->forceFill([
|
||||
'two_factor_secret' => encrypt('test-secret'),
|
||||
'two_factor_recovery_codes' => encrypt(json_encode(['code1', 'code2'])),
|
||||
'two_factor_confirmed_at' => now(),
|
||||
])->save();
|
||||
|
||||
$response = $this->post(route('login'), [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('two-factor.login'));
|
||||
$response->assertSessionHas('login.id', $user->id);
|
||||
$this->assertGuest();
|
||||
});
|
||||
|
||||
test('users can not authenticate with invalid password', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post(route('login'), [
|
||||
'email' => $user->email,
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$this->assertGuest();
|
||||
});
|
||||
|
||||
test('users can logout', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->post(route('logout'));
|
||||
|
||||
$this->assertGuest();
|
||||
$response->assertRedirect(route('home'));
|
||||
});
|
||||
|
||||
test('users are rate limited', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$this->post(route('login'), [
|
||||
'email' => $user->email,
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
}
|
||||
|
||||
$response = $this->post(route('login'), [
|
||||
'email' => $user->email,
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$response->assertStatus(302);
|
||||
$response->assertSessionHasErrors('email');
|
||||
});
|
||||
95
tests/Feature/Auth/EmailVerificationTest.php
Normal file
95
tests/Feature/Auth/EmailVerificationTest.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
test('email verification screen can be rendered', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get(route('verification.notice'));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('email can be verified', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1($user->email)]
|
||||
);
|
||||
|
||||
$response = $this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
Event::assertDispatched(Verified::class);
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
|
||||
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
|
||||
});
|
||||
|
||||
test('email is not verified with invalid hash', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1('wrong-email')]
|
||||
);
|
||||
|
||||
$this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
Event::assertNotDispatched(Verified::class);
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeFalse();
|
||||
});
|
||||
|
||||
test('email is not verified with invalid user id', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => 123, 'hash' => sha1($user->email)]
|
||||
);
|
||||
|
||||
$this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
Event::assertNotDispatched(Verified::class);
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeFalse();
|
||||
});
|
||||
|
||||
test('verified user is redirected to dashboard from verification prompt', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$response = $this->actingAs($user)->get(route('verification.notice'));
|
||||
|
||||
Event::assertNotDispatched(Verified::class);
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
});
|
||||
|
||||
test('already verified user visiting verification link is redirected without firing event again', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1($user->email)]
|
||||
);
|
||||
|
||||
$this->actingAs($user)->get($verificationUrl)
|
||||
->assertRedirect(route('dashboard', absolute: false).'?verified=1');
|
||||
|
||||
Event::assertNotDispatched(Verified::class);
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
|
||||
});
|
||||
22
tests/Feature/Auth/PasswordConfirmationTest.php
Normal file
22
tests/Feature/Auth/PasswordConfirmationTest.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
|
||||
test('confirm password screen can be rendered', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get(route('password.confirm'));
|
||||
|
||||
$response->assertOk();
|
||||
|
||||
$response->assertInertia(fn (Assert $page) => $page
|
||||
->component('auth/ConfirmPassword')
|
||||
);
|
||||
});
|
||||
|
||||
test('password confirmation requires authentication', function () {
|
||||
$response = $this->get(route('password.confirm'));
|
||||
|
||||
$response->assertRedirect(route('login'));
|
||||
});
|
||||
76
tests/Feature/Auth/PasswordResetTest.php
Normal file
76
tests/Feature/Auth/PasswordResetTest.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
use App\Notifications\ResetPassword;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
test('reset password link screen can be rendered', function () {
|
||||
$response = $this->get(route('password.request'));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('reset password link can be requested', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Notification::fake();
|
||||
|
||||
$this->post(route('password.email'), ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class);
|
||||
});
|
||||
|
||||
test('reset password screen can be rendered', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Notification::fake();
|
||||
|
||||
$this->post(route('password.email'), ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class, function ($notification) {
|
||||
$response = $this->get(route('password.reset', [
|
||||
'token' => $notification->token,
|
||||
'email' => 'test@example.com' // Any email works for rendering
|
||||
]));
|
||||
|
||||
$response->assertOk();
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
test('password can be reset with valid token', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Notification::fake();
|
||||
|
||||
$this->post(route('password.email'), ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) {
|
||||
$response = $this->post(route('password.update'), [
|
||||
'token' => $notification->token,
|
||||
'email' => $user->email,
|
||||
'password' => 'new-password',
|
||||
'password_confirmation' => 'new-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('login'));
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
test('password cannot be reset with invalid token', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->post(route('password.update'), [
|
||||
'token' => 'invalid-token',
|
||||
'email' => $user->email,
|
||||
'password' => 'newpassword123',
|
||||
'password_confirmation' => 'newpassword123',
|
||||
]);
|
||||
|
||||
$response->assertSessionHasErrors('email');
|
||||
});
|
||||
41
tests/Feature/Auth/RegistrationTest.php
Normal file
41
tests/Feature/Auth/RegistrationTest.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
test('registration screen can be rendered', function () {
|
||||
$response = $this->get(route('register'));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('new users can register', function () {
|
||||
$response = $this->post('/register', [
|
||||
'username' => 'Dolo',
|
||||
'first_name' => 'Kevin',
|
||||
'last_name' => 'Geiger',
|
||||
'email' => 'laynox9@gmail.com',
|
||||
'birthdate' => '2004-01-23',
|
||||
'gender' => 'male',
|
||||
'phone' => '+4915112350255',
|
||||
'country' => 'DE',
|
||||
'address_line1' => 'Siedlerstr. 15',
|
||||
'address_line2' => '',
|
||||
'city' => 'Türkheim',
|
||||
'postal_code' => '86842',
|
||||
'currency' => 'EUR',
|
||||
'password' => 'Geheim123!',
|
||||
'password_confirmation' => 'Geheim123!',
|
||||
'is_adult' => true,
|
||||
'terms_accepted' => true
|
||||
]);
|
||||
|
||||
if ($response->status() !== 302) {
|
||||
// Log errors to see what's failing if it's not a redirect
|
||||
$errors = session('errors');
|
||||
if ($errors) {
|
||||
fwrite(STDERR, print_r($errors->getMessages(), true));
|
||||
}
|
||||
}
|
||||
|
||||
$response->assertStatus(302);
|
||||
$this->assertAuthenticated('web');
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
});
|
||||
45
tests/Feature/Auth/TwoFactorChallengeTest.php
Normal file
45
tests/Feature/Auth/TwoFactorChallengeTest.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
use Laravel\Fortify\Features;
|
||||
|
||||
test('two factor challenge redirects to login when not authenticated', function () {
|
||||
if (! Features::canManageTwoFactorAuthentication()) {
|
||||
$this->markTestSkipped('Two-factor authentication is not enabled.');
|
||||
}
|
||||
|
||||
$response = $this->get(route('two-factor.login'));
|
||||
|
||||
$response->assertRedirect(route('login'));
|
||||
});
|
||||
|
||||
test('two factor challenge can be rendered', function () {
|
||||
if (! Features::canManageTwoFactorAuthentication()) {
|
||||
$this->markTestSkipped('Two-factor authentication is not enabled.');
|
||||
}
|
||||
|
||||
Features::twoFactorAuthentication([
|
||||
'confirm' => true,
|
||||
'confirmPassword' => true,
|
||||
]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$user->forceFill([
|
||||
'two_factor_secret' => encrypt('test-secret'),
|
||||
'two_factor_recovery_codes' => encrypt(json_encode(['code1', 'code2'])),
|
||||
'two_factor_confirmed_at' => now(),
|
||||
])->save();
|
||||
|
||||
$this->post(route('login'), [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->get(route('two-factor.login'))
|
||||
->assertOk()
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('auth/TwoFactorChallenge')
|
||||
);
|
||||
});
|
||||
29
tests/Feature/Auth/VerificationNotificationTest.php
Normal file
29
tests/Feature/Auth/VerificationNotificationTest.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use App\Notifications\VerifyEmail;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
test('sends verification notification', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
Notification::fake();
|
||||
|
||||
$this->actingAs($user)
|
||||
->post(route('verification.send'))
|
||||
->assertRedirect(route('dashboard'));
|
||||
|
||||
Notification::assertSentTo($user, VerifyEmail::class);
|
||||
});
|
||||
|
||||
test('does not send verification notification if email is verified', function () {
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->post(route('verification.send'))
|
||||
->assertRedirect(route('dashboard'));
|
||||
|
||||
Notification::assertNothingSent();
|
||||
});
|
||||
16
tests/Feature/DashboardTest.php
Normal file
16
tests/Feature/DashboardTest.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
test('guests can visit the dashboard', function () {
|
||||
$response = $this->get(route('dashboard'));
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('authenticated users can visit the dashboard', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('dashboard'));
|
||||
$response->assertOk();
|
||||
});
|
||||
7
tests/Feature/ExampleTest.php
Normal file
7
tests/Feature/ExampleTest.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
test('returns a successful response', function () {
|
||||
$response = $this->get(route('home'));
|
||||
|
||||
$response->assertRedirect(route('dashboard'));
|
||||
});
|
||||
69
tests/Feature/Gateway/AdminControllerTest.php
Normal file
69
tests/Feature/Gateway/AdminControllerTest.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AdminControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string { return rtrim((string) config('services.backend.base'), '/'); }
|
||||
|
||||
private function adminUser()
|
||||
{
|
||||
return User::factory()->create([
|
||||
'username' => 'admin',
|
||||
'role' => 'Admin',
|
||||
'email_verified_at' => now()
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_index_renders_for_admin()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/admin/overview' => Http::response([
|
||||
'users' => [ ['id'=>1,'username'=>'u1','balance'=>0] ],
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->adminUser(), 'web')->get('/admin/casino');
|
||||
$res->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_update_user_success_sets_flash()
|
||||
{
|
||||
$userToUpdate = User::factory()->create();
|
||||
|
||||
Http::fake([
|
||||
$this->base() . '/admin/users/' . $userToUpdate->id => Http::response(['message' => 'User aktualisiert.'], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->adminUser(), 'web')
|
||||
->post('/admin/users/' . $userToUpdate->id, [
|
||||
'username' => 'newname',
|
||||
'email' => 'new@example.com',
|
||||
'vip_level' => 2
|
||||
]);
|
||||
|
||||
$res->assertSessionHas('success');
|
||||
}
|
||||
|
||||
public function test_update_user_client_error_sets_error()
|
||||
{
|
||||
$userToUpdate = User::factory()->create();
|
||||
|
||||
Http::fake([
|
||||
$this->base() . '/admin/users/' . $userToUpdate->id => Http::response(['message' => 'Invalid'], 400),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->adminUser(), 'web')
|
||||
->post('/admin/users/' . $userToUpdate->id, [
|
||||
'username' => 'newname',
|
||||
'email' => 'invalid-email',
|
||||
'vip_level' => 999
|
||||
]);
|
||||
|
||||
$res->assertSessionHasErrors();
|
||||
}
|
||||
}
|
||||
59
tests/Feature/Gateway/AdminSupportAdminControllerTest.php
Normal file
59
tests/Feature/Gateway/AdminSupportAdminControllerTest.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AdminSupportAdminControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string { return rtrim((string) config('services.backend.base'), '/'); }
|
||||
|
||||
private function adminUser()
|
||||
{
|
||||
if (class_exists(User::class) && method_exists(User::class, 'factory')) {
|
||||
return User::factory()->make(['id' => 1201, 'username' => 'admin', 'role' => 'Admin', 'email_verified_at' => now()]);
|
||||
}
|
||||
return new class { public $id=1201; public $username='admin'; public $role='Admin'; };
|
||||
}
|
||||
|
||||
public function test_index_renders_with_threads()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/admin/support' => Http::response([
|
||||
'enabled' => true,
|
||||
'threads' => [ ['id' => 't-1', 'status' => 'ai'] ],
|
||||
'ollama' => ['healthy' => true],
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->adminUser())->get('/admin/support');
|
||||
$res->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_settings_success_sets_flash()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/admin/support/settings' => Http::response(['message' => 'OK'], 200),
|
||||
]);
|
||||
$res = $this->actingAs($this->adminUser())->post('/admin/support/settings', ['enabled' => true]);
|
||||
$res->assertSessionHas('success');
|
||||
}
|
||||
|
||||
public function test_reply_and_close_success_set_flash()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/admin/support/threads/t-1/message' => Http::response(['message' => 'Sent'], 200),
|
||||
$this->base() . '/admin/support/threads/t-1/close' => Http::response(['message' => 'Closed'], 200),
|
||||
]);
|
||||
|
||||
$this->actingAs($this->adminUser())
|
||||
->post('/admin/support/threads/t-1/message', ['text' => 'hi'])
|
||||
->assertSessionHas('success');
|
||||
|
||||
$this->actingAs($this->adminUser())
|
||||
->post('/admin/support/threads/t-1/close')
|
||||
->assertSessionHas('success');
|
||||
}
|
||||
}
|
||||
64
tests/Feature/Gateway/BonusesControllerTest.php
Normal file
64
tests/Feature/Gateway/BonusesControllerTest.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class BonusesControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
return User::factory()->create(['username' => 'bonususer', 'email_verified_at' => now()]);
|
||||
}
|
||||
|
||||
public function test_app_index_success_normalizes_fields()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/bonuses/app*' => Http::response([
|
||||
'available' => [
|
||||
[
|
||||
'id' => 1,
|
||||
'title' => 'Welcome Bonus',
|
||||
'type' => 'deposit_match',
|
||||
'amount_value' => 100,
|
||||
'amount_unit' => '%',
|
||||
'min_deposit' => 10,
|
||||
'max_amount' => 200,
|
||||
'currency' => 'USD',
|
||||
'code' => 'WELCOME100',
|
||||
'starts_at' => now()->subDay()->toIso8601String(),
|
||||
'expires_at' => now()->addDay()->toIso8601String(),
|
||||
'description' => 'Match bonus',
|
||||
],
|
||||
],
|
||||
'active' => [],
|
||||
'history' => [],
|
||||
'now' => now()->toIso8601String(),
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/api/bonuses/app');
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJsonStructure([
|
||||
'available' => [ [ 'id','title','type','amount_value','amount_unit','currency','code','starts_at','expires_at','description' ] ],
|
||||
'active', 'history', 'now',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_app_index_server_error_maps_to_503()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/bonuses/app*' => Http::response(['message' => 'Down'], 500),
|
||||
]);
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/api/bonuses/app');
|
||||
$res->assertStatus(503)->assertJson(['error' => 'service_unavailable']);
|
||||
}
|
||||
}
|
||||
166
tests/Feature/Gateway/ChatControllerTest.php
Normal file
166
tests/Feature/Gateway/ChatControllerTest.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ChatControllerTest extends TestCase
|
||||
{
|
||||
// use RefreshDatabase; // Not required for proxy tests; uncomment if your auth relies on DB
|
||||
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
return User::factory()->create(['username' => 'tester', 'email_verified_at' => now()]);
|
||||
}
|
||||
|
||||
public function test_get_chat_success_maps_messages_and_last_id()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/chat*' => Http::response([
|
||||
'messages' => [
|
||||
[
|
||||
'id' => 1,
|
||||
'user_id' => 12,
|
||||
'username' => 'dolo',
|
||||
'avatar' => 'http://a/1.png',
|
||||
'message' => 'hi',
|
||||
'reply_to_id' => null,
|
||||
'reactions' => ['🔥' => 2, '😂' => 1],
|
||||
'created_at' => now()->toIso8601String(),
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'user_id' => 13,
|
||||
'username' => 'sara',
|
||||
'avatar' => null,
|
||||
'message' => 'yo',
|
||||
'reply_to_id' => 1,
|
||||
'reactions' => [],
|
||||
'created_at' => now()->toIso8601String(),
|
||||
],
|
||||
],
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->get('/api/chat?limit=2');
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJsonStructure([
|
||||
'data' => [
|
||||
['id', 'user_id', 'message', 'reply_to_id', 'created_at', 'user' => ['id', 'username', 'avatar_url'], 'reactions_agg'],
|
||||
],
|
||||
'last_id',
|
||||
]);
|
||||
|
||||
$json = $res->json();
|
||||
$this->assertEquals(2, $json['last_id']);
|
||||
$this->assertCount(2, $json['data']);
|
||||
$this->assertEquals('dolo', $json['data'][0]['user']['username']);
|
||||
}
|
||||
|
||||
public function test_get_chat_client_error_is_mapped()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/chat*' => Http::response(['message' => 'Invalid request'], 422),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->get('/api/chat?limit=0');
|
||||
|
||||
$res->assertStatus(422)
|
||||
->assertJson([
|
||||
'error' => 'client_error',
|
||||
'message' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_get_chat_server_error_maps_to_503()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/chat*' => Http::response(['message' => 'Upstream failed'], 500),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->get('/api/chat?limit=50');
|
||||
|
||||
$res->assertStatus(503)
|
||||
->assertJson([
|
||||
'error' => 'service_unavailable',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_get_chat_timeout_maps_to_502()
|
||||
{
|
||||
Http::fake(function () {
|
||||
throw new \Illuminate\Http\Client\ConnectionException('timeout');
|
||||
});
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->get('/api/chat?limit=50');
|
||||
|
||||
$res->assertStatus(502)
|
||||
->assertJson([
|
||||
'error' => 'bad_gateway',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_post_chat_success_returns_minimal_message()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/chat' => Http::response(['success' => true, 'message_id' => 123], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->postJson('/api/chat', [
|
||||
'message' => 'Hello world',
|
||||
]);
|
||||
|
||||
$res->assertStatus(201)
|
||||
->assertJsonStructure(['data' => ['id', 'user_id', 'message', 'created_at', 'user' => ['id', 'username', 'avatar_url'], 'reactions_agg']]);
|
||||
|
||||
$this->assertEquals(123, data_get($res->json(), 'data.id'));
|
||||
$this->assertEquals('Hello world', data_get($res->json(), 'data.message'));
|
||||
}
|
||||
|
||||
public function test_post_chat_client_error_is_mapped()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/chat' => Http::response(['message' => 'Too long'], 422),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->postJson('/api/chat', [
|
||||
'message' => str_repeat('x', 400),
|
||||
]);
|
||||
|
||||
$res->assertStatus(422)
|
||||
->assertJson([
|
||||
'error' => 'client_error',
|
||||
'message' => 'Too long',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_react_success_returns_200()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/chat/55/react' => Http::response(['ok' => true], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->postJson('/api/chat/55/react', [ 'emoji' => '🔥' ]);
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJson([
|
||||
'data' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
69
tests/Feature/Gateway/GuildActionControllerTest.php
Normal file
69
tests/Feature/Gateway/GuildActionControllerTest.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class GuildActionControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
if (class_exists(User::class) && method_exists(User::class, 'factory')) {
|
||||
return User::factory()->make(['id' => 802, 'username' => 'guilduser', 'email_verified_at' => now()]);
|
||||
}
|
||||
return new class {
|
||||
public $id = 802; public $username = 'guilduser'; public $role = 'User';
|
||||
};
|
||||
}
|
||||
|
||||
public function test_store_success()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/guilds' => Http::response([
|
||||
'data' => ['id' => 1, 'name' => 'NewGuild', 'invite_code' => 'ABCDEF']
|
||||
], 201),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser())
|
||||
->postJson('/guilds', [
|
||||
'name' => 'NewGuild',
|
||||
'tag' => 'ABCD',
|
||||
]);
|
||||
|
||||
$res->assertStatus(201)
|
||||
->assertJsonStructure(['data']);
|
||||
}
|
||||
|
||||
public function test_join_success()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/guilds/join' => Http::response(['success' => true], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser())
|
||||
->postJson('/guilds/join', [ 'invite_code' => 'AAAAAA' ]);
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJson(['success' => true]);
|
||||
}
|
||||
|
||||
public function test_update_client_error_maps_to_client_error()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/guilds' => Http::response(['message' => 'Forbidden'], 403),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser())
|
||||
->patchJson('/guilds', [ 'name' => 'x' ]);
|
||||
|
||||
$res->assertStatus(403)
|
||||
->assertJson(['message' => 'Forbidden']);
|
||||
}
|
||||
}
|
||||
53
tests/Feature/Gateway/GuildControllerTest.php
Normal file
53
tests/Feature/Gateway/GuildControllerTest.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class GuildControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
if (class_exists(User::class) && method_exists(User::class, 'factory')) {
|
||||
return User::factory()->make(['id' => 801, 'username' => 'guilduser']);
|
||||
}
|
||||
return new class {
|
||||
public $id = 801; public $username = 'guilduser'; public $role = 'User';
|
||||
};
|
||||
}
|
||||
|
||||
public function test_index_renders_with_upstream_data()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/guilds' => Http::response([
|
||||
'guild' => ['id' => 1, 'name' => 'Testers'],
|
||||
'myRole' => 'member',
|
||||
'canManage' => false,
|
||||
'invite' => 'AAAAAA',
|
||||
'wager' => ['value' => 0],
|
||||
'topPlayers' => [],
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser())->get('/guilds');
|
||||
$res->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_top_renders_list()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/guilds/top' => Http::response([
|
||||
'guilds' => [ ['id' => 1, 'name' => 'A'], ['id' => 2, 'name' => 'B'] ],
|
||||
], 200),
|
||||
]);
|
||||
$res = $this->actingAs($this->actingUser())->get('/guilds/top');
|
||||
$res->assertStatus(200);
|
||||
}
|
||||
}
|
||||
52
tests/Feature/Gateway/PromoControllerTest.php
Normal file
52
tests/Feature/Gateway/PromoControllerTest.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PromoControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
return User::factory()->create(['username' => 'promouser', 'email_verified_at' => now()]);
|
||||
}
|
||||
|
||||
public function test_apply_success_passes_message()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/promos/apply' => Http::response([
|
||||
'success' => true,
|
||||
'message' => 'Applied',
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->postJson('/api/promos/apply', ['code' => 'WELCOME']);
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJson([
|
||||
'success' => true,
|
||||
'message' => 'Applied',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_apply_client_error_maps_to_client_error()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/promos/apply' => Http::response(['message' => 'Invalid code'], 400),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')
|
||||
->postJson('/api/promos/apply', ['code' => 'bad!']);
|
||||
|
||||
$res->assertStatus(400)
|
||||
->assertJson(['error' => 'client_error']);
|
||||
}
|
||||
}
|
||||
59
tests/Feature/Gateway/SocialControllerTest.php
Normal file
59
tests/Feature/Gateway/SocialControllerTest.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SocialControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser($overrides = [])
|
||||
{
|
||||
return User::factory()->create(array_merge(['username' => 'socialuser', 'role' => 'User', 'email_verified_at' => now()], $overrides));
|
||||
}
|
||||
|
||||
public function test_search_success_normalizes_minimal_fields()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/users/search*' => Http::response([
|
||||
'users' => [
|
||||
['id' => 1, 'username' => 'do', 'avatar_url' => null, 'vip_level' => 3],
|
||||
['id' => 2, 'username' => 'dolo', 'avatar' => 'http://a/av.png'],
|
||||
],
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/api/users/search?q=do');
|
||||
$res->assertStatus(200)
|
||||
->assertJsonStructure([
|
||||
[ 'id','username','avatar','vip_level' ]
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_profile_show_404_is_forwarded()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/users/unknown' => Http::response(['message' => 'User not found.'], 404),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/profile/unknown');
|
||||
$res->assertStatus(404);
|
||||
}
|
||||
|
||||
public function test_tip_client_error_is_mapped_to_errors_bag()
|
||||
{
|
||||
$user = $this->actingUser(['balance' => 0.0]); // Set balance to 0 to trigger local error
|
||||
$target = User::factory()->create();
|
||||
|
||||
$res = $this->actingAs($user, 'web')->post("/profile/{$target->id}/tip", [
|
||||
'currency' => 'USD', 'amount' => 1.0
|
||||
]);
|
||||
$res->assertSessionHasErrors(['amount']);
|
||||
}
|
||||
}
|
||||
116
tests/Feature/Gateway/SupportChatControllerTest.php
Normal file
116
tests/Feature/Gateway/SupportChatControllerTest.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SupportChatControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
return User::factory()->create(['email_verified_at' => now()]);
|
||||
}
|
||||
|
||||
public function test_status_success_passthrough()
|
||||
{
|
||||
$user = $this->actingUser();
|
||||
Http::fake([
|
||||
$this->base() . '/support/status' => Http::response([
|
||||
'thread_id' => 't-1',
|
||||
'status' => 'ai',
|
||||
'messages' => [],
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($user, 'web')->get('/api/support/status');
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJson([
|
||||
'thread_id' => 't-1',
|
||||
'status' => 'ai',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_status_client_error_maps_to_client_error()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/support/status' => Http::response(['message' => 'Invalid'], 400),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/api/support/status');
|
||||
$res->assertStatus(400)
|
||||
->assertJson([
|
||||
'error' => 'client_error',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_status_server_error_maps_to_503()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/support/status' => Http::response(['message' => 'Oops'], 500),
|
||||
]);
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/api/support/status');
|
||||
$res->assertStatus(503)
|
||||
->assertJson([
|
||||
'error' => 'service_unavailable',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_start_success()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/support/start' => Http::response([
|
||||
'thread_id' => 't-2',
|
||||
'status' => 'ai',
|
||||
], 200),
|
||||
]);
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->postJson('/api/support/start', ['topic' => 'Konto']);
|
||||
$res->assertStatus(200)->assertJson([
|
||||
'thread_id' => 't-2',
|
||||
'status' => 'ai',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_message_success()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/support/message' => Http::response(['ok' => true], 200),
|
||||
]);
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->postJson('/api/support/message', ['text' => 'Hallo']);
|
||||
$res->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_stop_handoff_close_success()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/support/stop' => Http::response(['success' => true], 200),
|
||||
$this->base() . '/support/handoff' => Http::response(['success' => true], 200),
|
||||
$this->base() . '/support/close' => Http::response(['success' => true], 200),
|
||||
]);
|
||||
|
||||
$this->actingAs($this->actingUser(), 'web')->postJson('/api/support/stop')->assertStatus(200);
|
||||
$this->actingAs($this->actingUser(), 'web')->postJson('/api/support/handoff')->assertStatus(200);
|
||||
$this->actingAs($this->actingUser(), 'web')->postJson('/api/support/close')->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_stream_failure_maps_to_503()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/support/stream' => Http::response(['message' => 'Down'], 500),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/api/support/stream');
|
||||
|
||||
$res->assertStatus(503)
|
||||
->assertJson([
|
||||
'error' => 'service_unavailable',
|
||||
]);
|
||||
}
|
||||
}
|
||||
55
tests/Feature/Gateway/UserBonusControllerTest.php
Normal file
55
tests/Feature/Gateway/UserBonusControllerTest.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UserBonusControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
return User::factory()->create(['username' => 'bonususer', 'email_verified_at' => now()]);
|
||||
}
|
||||
|
||||
public function test_index_success_normalizes_data()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/users/me/bonuses' => Http::response([
|
||||
'bonuses' => [
|
||||
[
|
||||
'id' => 9,
|
||||
'amount' => 12.5,
|
||||
'wager_required' => 100,
|
||||
'wager_progress' => 40,
|
||||
'expires_at' => now()->addDay()->toIso8601String(),
|
||||
'is_active' => true,
|
||||
'promo' => [ 'code' => 'WELCOME', 'wager_multiplier' => 40 ],
|
||||
],
|
||||
],
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/api/user/bonuses');
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJsonStructure(['data' => [[
|
||||
'id','amount','wager_required','wager_progress','expires_at','is_active','completed_at','promo'
|
||||
]]]);
|
||||
}
|
||||
|
||||
public function test_index_server_error_maps_to_503()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/users/me/bonuses' => Http::response(['message' => 'Down'], 500),
|
||||
]);
|
||||
$res = $this->actingAs($this->actingUser(), 'web')->get('/api/user/bonuses');
|
||||
$res->assertStatus(503)->assertJson(['error' => 'service_unavailable']);
|
||||
}
|
||||
}
|
||||
89
tests/Feature/Gateway/VaultControllerTest.php
Normal file
89
tests/Feature/Gateway/VaultControllerTest.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class VaultControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
return User::factory()->create([
|
||||
'username' => 'vaultuser',
|
||||
'email_verified_at' => now(),
|
||||
'balance' => 11.0000,
|
||||
'vault_balance' => 5.0000,
|
||||
'vault_pin_hash' => \Illuminate\Support\Facades\Hash::make('1234'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_show_success_maps_shape()
|
||||
{
|
||||
$user = $this->actingUser();
|
||||
\App\Models\WalletTransfer::create([
|
||||
'user_id' => $user->id,
|
||||
'type' => 'deposit',
|
||||
'amount' => 1.00,
|
||||
'currency' => 'BTX',
|
||||
'balance_before' => 12.00,
|
||||
'balance_after' => 11.00,
|
||||
'vault_before' => 4.00,
|
||||
'vault_after' => 5.00,
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($user, 'web')->get('/api/wallet/vault');
|
||||
$res->assertStatus(200)
|
||||
->assertJson([
|
||||
'balance' => '11.0000',
|
||||
'vault_balance' => '5.0000',
|
||||
'currency' => 'BTX',
|
||||
])
|
||||
->assertJsonStructure(['transfers', 'now']);
|
||||
}
|
||||
|
||||
public function test_show_client_error_not_applicable_for_local_show()
|
||||
{
|
||||
// Der lokale VaultController->show() wirft keinen 400er Client-Fehler wie der Proxy
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function test_show_server_error_not_applicable_for_local_show()
|
||||
{
|
||||
// Der lokale VaultController->show() wirft keinen 503er Service-Fehler wie der Proxy
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function test_deposit_success_maps_balances()
|
||||
{
|
||||
$user = $this->actingUser();
|
||||
|
||||
$res = $this->actingAs($user, 'web')
|
||||
->postJson('/api/wallet/vault/deposit', [ 'amount' => '1.0000', 'pin' => '1234' ]);
|
||||
|
||||
$res->assertStatus(201)
|
||||
->assertJson([
|
||||
'balances' => [ 'balance' => '10.0000', 'vault_balance' => '6.0000' ],
|
||||
])
|
||||
->assertJsonStructure(['data', 'balances']);
|
||||
}
|
||||
|
||||
public function test_withdraw_success_maps_balances()
|
||||
{
|
||||
$user = $this->actingUser();
|
||||
|
||||
$res = $this->actingAs($user, 'web')
|
||||
->postJson('/api/wallet/vault/withdraw', [ 'amount' => '1.0000', 'pin' => '1234' ]);
|
||||
|
||||
$res->assertStatus(201)
|
||||
->assertJson([
|
||||
'balances' => [ 'balance' => '12.0000', 'vault_balance' => '4.0000' ],
|
||||
]);
|
||||
}
|
||||
}
|
||||
50
tests/Feature/Gateway/VaultPinControllerTest.php
Normal file
50
tests/Feature/Gateway/VaultPinControllerTest.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class VaultPinControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string
|
||||
{
|
||||
return rtrim((string) config('services.backend.base'), '/');
|
||||
}
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
return User::factory()->create([
|
||||
'username' => 'pinuser',
|
||||
'email_verified_at' => now(),
|
||||
'vault_pin_hash' => \Illuminate\Support\Facades\Hash::make('4321'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_set_success()
|
||||
{
|
||||
$user = $this->actingUser();
|
||||
// Da ein PIN gesetzt ist, müssen wir current_pin mitsenden
|
||||
$res = $this->actingAs($user, 'web')
|
||||
->postJson('/api/wallet/vault/pin/set', [ 'pin' => '1234', 'current_pin' => '4321' ]);
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJson([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_verify_success()
|
||||
{
|
||||
$user = $this->actingUser();
|
||||
// Der actingUser() hat PIN 4321
|
||||
$res = $this->actingAs($user, 'web')
|
||||
->postJson('/api/wallet/vault/pin/verify', [ 'pin' => '4321' ]);
|
||||
|
||||
$res->assertStatus(200)
|
||||
->assertJson([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
44
tests/Feature/Gateway/VipControllerTest.php
Normal file
44
tests/Feature/Gateway/VipControllerTest.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class VipControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string { return rtrim((string) config('services.backend.base'), '/'); }
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
if (class_exists(User::class) && method_exists(User::class, 'factory')) {
|
||||
return User::factory()->make(['id' => 1001, 'username' => 'vipuser']);
|
||||
}
|
||||
return new class { public $id=1001; public $username='vipuser'; public $role='User'; };
|
||||
}
|
||||
|
||||
public function test_index_renders()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/vip-levels' => Http::response([
|
||||
'claimedLevels' => [1,2],
|
||||
'rewards' => [],
|
||||
'stats' => ['wagered' => 0],
|
||||
'vip_level' => 3,
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$res = $this->actingAs($this->actingUser())->get('/vip-levels');
|
||||
$res->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_claim_success_sets_flash()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/vip-levels/claim' => Http::response(['message' => 'Reward claimed successfully!'], 200),
|
||||
]);
|
||||
$res = $this->actingAs($this->actingUser())->post('/vip-levels/claim', ['level' => 2]);
|
||||
$res->assertSessionHas('success');
|
||||
}
|
||||
}
|
||||
32
tests/Feature/Gateway/WalletControllerTest.php
Normal file
32
tests/Feature/Gateway/WalletControllerTest.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Gateway;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WalletControllerTest extends TestCase
|
||||
{
|
||||
private function base(): string { return rtrim((string) config('services.backend.base'), '/'); }
|
||||
|
||||
private function actingUser()
|
||||
{
|
||||
if (class_exists(User::class) && method_exists(User::class, 'factory')) {
|
||||
return User::factory()->make(['id' => 901, 'username' => 'walletuser']);
|
||||
}
|
||||
return new class { public $id=901; public $username='walletuser'; public $role='User'; };
|
||||
}
|
||||
|
||||
public function test_index_renders_with_upstream_data()
|
||||
{
|
||||
Http::fake([
|
||||
$this->base() . '/wallet' => Http::response([
|
||||
'wallets' => [ ['code' => 'USD', 'balance' => 10] ],
|
||||
'btxBalance' => 10,
|
||||
], 200),
|
||||
]);
|
||||
$res = $this->actingAs($this->actingUser())->get('/wallet');
|
||||
$res->assertStatus(200);
|
||||
}
|
||||
}
|
||||
50
tests/Feature/Settings/PasswordUpdateTest.php
Normal file
50
tests/Feature/Settings/PasswordUpdateTest.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
test('password update page is displayed', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->get(route('user-password.edit'));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('password can be updated', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from(route('user-password.edit'))
|
||||
->put(route('user-password.update'), [
|
||||
'current_password' => 'password',
|
||||
'password' => 'new-password',
|
||||
'password_confirmation' => 'new-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('user-password.edit'));
|
||||
|
||||
expect(Hash::check('new-password', $user->refresh()->password))->toBeTrue();
|
||||
});
|
||||
|
||||
test('correct password must be provided to update password', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from(route('user-password.edit'))
|
||||
->put(route('user-password.update'), [
|
||||
'current_password' => 'wrong-password',
|
||||
'password' => 'new-password',
|
||||
'password_confirmation' => 'new-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasErrors('current_password')
|
||||
->assertRedirect(route('user-password.edit'));
|
||||
});
|
||||
85
tests/Feature/Settings/ProfileUpdateTest.php
Normal file
85
tests/Feature/Settings/ProfileUpdateTest.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
test('profile page is displayed', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->get(route('profile.edit'));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('profile information can be updated', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->patch(route('profile.update'), [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('profile.edit'));
|
||||
|
||||
$user->refresh();
|
||||
|
||||
expect($user->name)->toBe('Test User');
|
||||
expect($user->email)->toBe('test@example.com');
|
||||
expect($user->email_verified_at)->toBeNull();
|
||||
});
|
||||
|
||||
test('email verification status is unchanged when the email address is unchanged', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->patch(route('profile.update'), [
|
||||
'name' => 'Test User',
|
||||
'email' => $user->email,
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('profile.edit'));
|
||||
|
||||
expect($user->refresh()->email_verified_at)->not->toBeNull();
|
||||
});
|
||||
|
||||
test('user can delete their account', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->delete(route('profile.destroy'), [
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('home'));
|
||||
|
||||
$this->assertGuest();
|
||||
expect($user->fresh())->toBeNull();
|
||||
});
|
||||
|
||||
test('correct password must be provided to delete account', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from(route('profile.edit'))
|
||||
->delete(route('profile.destroy'), [
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasErrors('password')
|
||||
->assertRedirect(route('profile.edit'));
|
||||
|
||||
expect($user->fresh())->not->toBeNull();
|
||||
});
|
||||
79
tests/Feature/Settings/TwoFactorAuthenticationTest.php
Normal file
79
tests/Feature/Settings/TwoFactorAuthenticationTest.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
use Laravel\Fortify\Features;
|
||||
|
||||
test('two factor settings page can be rendered', function () {
|
||||
if (! Features::canManageTwoFactorAuthentication()) {
|
||||
$this->markTestSkipped('Two-factor authentication is not enabled.');
|
||||
}
|
||||
|
||||
Features::twoFactorAuthentication([
|
||||
'confirm' => true,
|
||||
'confirmPassword' => true,
|
||||
]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession(['auth.password_confirmed_at' => time()])
|
||||
->get(route('two-factor.show'))
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('settings/TwoFactor')
|
||||
->where('twoFactorEnabled', false)
|
||||
);
|
||||
});
|
||||
|
||||
test('two factor settings page requires password confirmation when enabled', function () {
|
||||
if (! Features::canManageTwoFactorAuthentication()) {
|
||||
$this->markTestSkipped('Two-factor authentication is not enabled.');
|
||||
}
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
Features::twoFactorAuthentication([
|
||||
'confirm' => true,
|
||||
'confirmPassword' => true,
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get(route('two-factor.show'));
|
||||
|
||||
$response->assertRedirect(route('password.confirm'));
|
||||
});
|
||||
|
||||
test('two factor settings page does not requires password confirmation when disabled', function () {
|
||||
if (! Features::canManageTwoFactorAuthentication()) {
|
||||
$this->markTestSkipped('Two-factor authentication is not enabled.');
|
||||
}
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
Features::twoFactorAuthentication([
|
||||
'confirm' => true,
|
||||
'confirmPassword' => false,
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('two-factor.show'))
|
||||
->assertOk()
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('settings/TwoFactor')
|
||||
);
|
||||
});
|
||||
|
||||
test('two factor settings page returns forbidden response when two factor is disabled', function () {
|
||||
if (! Features::canManageTwoFactorAuthentication()) {
|
||||
$this->markTestSkipped('Two-factor authentication is not enabled.');
|
||||
}
|
||||
|
||||
config(['fortify.features' => []]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession(['auth.password_confirmed_at' => time()])
|
||||
->get(route('two-factor.show'))
|
||||
->assertForbidden();
|
||||
});
|
||||
47
tests/Pest.php
Normal file
47
tests/Pest.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Test Case
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The closure you provide to your test functions is always bound to a specific PHPUnit test
|
||||
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
|
||||
| need to change it using the "pest()" function to bind a different classes or traits.
|
||||
|
|
||||
*/
|
||||
|
||||
pest()->extend(Tests\TestCase::class)
|
||||
->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
|
||||
->in('Feature');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expectations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When you're writing tests, you often need to check that values meet certain conditions. The
|
||||
| "expect()" function gives you access to a set of "expectations" methods that you can use
|
||||
| to assert different things. Of course, you may extend the Expectation API at any time.
|
||||
|
|
||||
*/
|
||||
|
||||
expect()->extend('toBeOne', function () {
|
||||
return $this->toBe(1);
|
||||
});
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Functions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
|
||||
| project that you don't want to repeat in every file. Here you can also expose helpers as
|
||||
| global functions to help you to reduce the number of lines of code in your test files.
|
||||
|
|
||||
*/
|
||||
|
||||
function something()
|
||||
{
|
||||
// ..
|
||||
}
|
||||
26
tests/TestCase.php
Normal file
26
tests/TestCase.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\CreatesApplication;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
use CreatesApplication, RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Global disable for tests
|
||||
$this->withoutMiddleware([
|
||||
\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
|
||||
\App\Http\Middleware\CheckBanned::class,
|
||||
\App\Http\Middleware\EnforceRestriction::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
5
tests/Unit/ExampleTest.php
Normal file
5
tests/Unit/ExampleTest.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
test('that true is true', function () {
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
Reference in New Issue
Block a user