Teren-app/tests/Feature/SmsProfileTest.php
Simon Pocrnjič 930ac83604 SMS service
2025-10-24 21:39:10 +02:00

121 lines
3.8 KiB
PHP

<?php
use App\Jobs\SendSmsJob;
use App\Models\Permission;
use App\Models\Role;
use App\Models\SmsLog;
use App\Models\SmsProfile;
use App\Models\SmsSender;
use App\Models\User;
use App\Services\Sms\SmsClient;
use App\Services\Sms\SmsMessage;
use App\Services\Sms\SmsResult;
use Illuminate\Support\Facades\Http;
function adminUserForSms(): User
{
$user = User::factory()->create();
// Ensure admin role & manage-settings permission exist
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Admin']);
$permission = Permission::firstOrCreate(['slug' => 'manage-settings'], ['name' => 'Manage Settings']);
$user->roles()->syncWithoutDetaching([$role->id]);
if (method_exists($user, 'givePermissionTo')) {
$user->givePermissionTo('manage-settings');
}
return $user;
}
it('creates an sms profile and encrypts password', function () {
$user = adminUserForSms();
test()->actingAs($user);
$resp = test()->postJson(route('admin.sms-profiles.store'), [
'name' => 'Primary SMS',
'active' => true,
'api_username' => 'testuser',
'api_password' => 'super-secret',
]);
$resp->assertCreated();
$resp->assertJsonStructure(['profile' => ['id', 'uuid', 'name', 'active', 'api_username', 'created_at', 'updated_at']]);
$profile = SmsProfile::first();
expect($profile)->not->toBeNull();
// Attribute is hidden, but verify decrypt roundtrip via model method
expect($profile->decryptApiPassword())->toBe('super-secret');
});
it('queues a job to send sms and logs as sent', function () {
$user = adminUserForSms();
test()->actingAs($user);
$profile = SmsProfile::factory()->create([
'api_username' => 'apiuser',
'api_password' => 'apipass',
]);
$sender = SmsSender::factory()->create(['profile_id' => $profile->id]);
// Bind a fake client that always returns sent with provider id
app()->instance(SmsClient::class, new class implements SmsClient
{
public function send(App\Models\SmsProfile $profile, SmsMessage $message): SmsResult
{
return new SmsResult('sent', '123456');
}
public function getCreditBalance(App\Models\SmsProfile $profile): int
{
return 0;
}
public function getPriceQuotes(App\Models\SmsProfile $profile): array
{
return [];
}
});
// Run the job synchronously
(new SendSmsJob(
profileId: $profile->id,
to: '+38640111222',
content: 'Hello from test',
senderId: null,
countryCode: null,
deliveryReport: true,
clientReference: null,
))->handle(app(\App\Services\Sms\SmsService::class));
$log = SmsLog::first();
expect($log)->not->toBeNull();
expect($log->status)->toBe('sent');
expect($log->provider_message_id)->toBe('123456');
});
it('returns balance and price quotes', function () {
$user = adminUserForSms();
test()->actingAs($user);
$profile = SmsProfile::factory()->create([
'api_username' => 'apiuser',
'api_password' => 'apipass',
]);
$base = config('services.sms.providers.smsapi_si.base_url');
$creditsUrl = rtrim($base, '/').config('services.sms.providers.smsapi_si.credits_endpoint', '/preveri-stanje-kreditov');
$priceUrl = rtrim($base, '/').config('services.sms.providers.smsapi_si.price_endpoint', '/dobi-ceno');
Http::fake([
$creditsUrl => Http::response('42', 200),
$priceUrl => Http::response('0.05 EUR##0.07 EUR', 200),
]);
test()->postJson(route('admin.sms-profiles.balance', $profile))
->assertSuccessful()
->assertJson(['balance' => '42']);
test()->postJson(route('admin.sms-profiles.price', $profile))
->assertSuccessful()
->assertJson(['quotes' => ['0.05 EUR', '0.07 EUR']]);
});