Files
daragt-coupon/tests/Feature/SmsBroadcastServiceTest.php

155 lines
4.4 KiB
PHP

<?php
namespace Tests\Feature;
use App\Enums\SmsSendStatus;
use App\Jobs\SendSmsToCouponJob;
use App\Models\Coupon;
use App\Models\SmsCampaign;
use App\Models\SmsSendLog;
use App\Models\User;
use App\Services\SmsBroadcastService;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
class SmsBroadcastServiceTest extends TestCase
{
use LazilyRefreshDatabase;
private SmsBroadcastService $service;
protected function setUp(): void
{
parent::setUp();
Http::fake([
config('services.sms.url') => Http::response('ok', 200),
]);
$this->service = app(SmsBroadcastService::class);
}
public function test_resolve_recipients_for_all_excluding_ids(): void
{
$included = Coupon::factory()->count(2)->create();
$excluded = Coupon::factory()->create();
$recipients = $this->service->resolveRecipients(
sendToAll: true,
excludedIds: [$excluded->id],
);
$this->assertCount(2, $recipients);
$this->assertTrue($recipients->pluck('id')->contains($included->first()->id));
$this->assertFalse($recipients->pluck('id')->contains($excluded->id));
}
public function test_resolve_recipients_for_selected_only(): void
{
$selected = Coupon::factory()->create();
Coupon::factory()->create();
$recipients = $this->service->resolveRecipients(
sendToAll: false,
selectedIds: [$selected->id],
);
$this->assertCount(1, $recipients);
$this->assertSame($selected->id, $recipients->first()->id);
}
public function test_start_campaign_queues_chain_and_creates_logs(): void
{
Bus::fake();
$admin = User::factory()->create();
$coupons = Coupon::factory()->count(2)->create();
$campaign = $this->service->startCampaign(
admin: $admin,
message: 'Test broadcast',
sendToAll: false,
selectedIds: $coupons->pluck('id')->all(),
);
$this->assertSame(2, $campaign->recipient_count);
$this->assertDatabaseCount(SmsSendLog::class, 2);
$this->assertDatabaseHas(SmsSendLog::class, [
'sms_campaign_id' => $campaign->id,
'status' => SmsSendStatus::Pending->value,
]);
Bus::assertChained([
SendSmsToCouponJob::class,
SendSmsToCouponJob::class,
]);
}
public function test_invalid_phone_is_skipped_without_queue_job(): void
{
Bus::fake();
$admin = User::factory()->create();
$invalid = Coupon::factory()->create(['phone' => '81234567']);
$valid = Coupon::factory()->create();
$campaign = $this->service->startCampaign(
admin: $admin,
message: 'Test',
sendToAll: false,
selectedIds: [$invalid->id, $valid->id],
);
$this->assertSame(2, $campaign->recipient_count);
$this->assertSame(1, $campaign->skipped_count);
$this->assertDatabaseHas(SmsSendLog::class, [
'coupon_id' => $invalid->id,
'status' => SmsSendStatus::SkippedInvalid->value,
]);
Bus::assertChained([
SendSmsToCouponJob::class,
]);
}
public function test_send_job_marks_success_and_completes_campaign(): void
{
Queue::fake();
$admin = User::factory()->create();
$coupon = Coupon::factory()->create(['phone' => '61929248']);
$campaign = SmsCampaign::factory()->create([
'message' => 'Queued hello',
'recipient_count' => 1,
'created_by' => $admin->id,
]);
SmsSendLog::factory()->create([
'sms_campaign_id' => $campaign->id,
'coupon_id' => $coupon->id,
'phone' => $coupon->phone,
'message' => $campaign->message,
'status' => SmsSendStatus::Pending,
]);
$job = new SendSmsToCouponJob($campaign, $coupon);
$job->handle();
Http::assertSentCount(1);
$campaign->refresh();
$this->assertSame(1, $campaign->sent_count);
$this->assertNotNull($campaign->completed_at);
$this->assertDatabaseHas(SmsSendLog::class, [
'sms_campaign_id' => $campaign->id,
'status' => SmsSendStatus::Sent->value,
]);
}
}