Skip to content

Commit

Permalink
Add Unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickrobrecht committed Mar 6, 2025
1 parent f7956b7 commit db99724
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;

class SendPaymentReminders extends Command
class SendPaymentRemindersCommand extends Command
{
protected $signature = 'app:send-payment-reminders
{--dry-run : If set the reminders are only listed, but not actually sent.}';
Expand Down Expand Up @@ -40,7 +40,7 @@ public function handle(): int
->get();

if ($bookingOptions->isEmpty()) {
$this->info('There are no booking options with overdue bookings.');
$this->info('There are no booking options with unpaid bookings to check.');
return self::SUCCESS;
}

Expand Down
1 change: 1 addition & 0 deletions database/factories/BookingFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public function definition(): array
'phone' => fake()->phoneNumber(),
'email' => sprintf('%s.%s@%s', Str::slug($firstName), Str::slug($lastName), fake()->unique()->domainName()),
'date_of_birth' => fake()->date(),
'booked_at' => $this->faker->dateTime(),
];
}

Expand Down
73 changes: 73 additions & 0 deletions tests/Feature/Console/Commands/SendPaymentRemindersCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace Tests\Feature\Console\Commands;

use App\Console\Commands\SendPaymentRemindersCommand;
use App\Models\Booking;
use App\Notifications\PaymentReminderNotification;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Notifications\AnonymousNotifiable;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use PHPUnit\Framework\Attributes\CoversClass;
use Tests\TestCase;
use Tests\Traits\GeneratesTestData;

#[CoversClass(Booking::class)]
#[CoversClass(PaymentReminderNotification::class)]
#[CoversClass(SendPaymentRemindersCommand::class)]
class SendPaymentRemindersCommandTest extends TestCase
{
use GeneratesTestData;
use RefreshDatabase;

public function testCommandRunsWithNoOverdueBookings(): void
{
$this->artisan('app:send-payment-reminders')
->expectsOutput('There are no booking options with unpaid bookings to check.')
->assertSuccessful();
}

public function testCommandSendsPaymentReminders(): void
{
Notification::fake();
Log::shouldReceive('info')->once();

$booking = $this->fakeUnpaidBooking();

$this->artisan('app:send-payment-reminders')
->expectsOutputToContain("Sent reminder to {$booking->email} for booking {$booking->id}.")
->assertSuccessful();
Notification::assertSentTo(new AnonymousNotifiable(), PaymentReminderNotification::class, static function ($notification) use ($booking) {
return str_contains($notification->toMail($booking->bookedByUser)->render(), $booking->bookedByUser->greeting);
});
Notification::assertCount(1);
}

public function testCommandOutputsLogDataDuringDryRun(): void
{
Notification::fake();
Log::shouldReceive('info')->once();

$booking = $this->fakeUnpaidBooking();

$this->artisan('app:send-payment-reminders --dry-run')
->expectsOutputToContain("Reminder to {$booking->email} for booking {$booking->id} not sent because it's a dry run.")
->assertSuccessful();
Notification::assertNothingSent();
}

private function fakeUnpaidBooking(): Booking
{
$bookingOption = self::createBookingOptionForEvent(attributes: [
'price' => 5,
'payment_due_days' => 10,
]);
return self::createBooking($bookingOption, [
'paid_at' => null,
'deleted_at' => null,
'booked_at' => Carbon::today()->subWeekDays(11),
]);
}
}
13 changes: 8 additions & 5 deletions tests/Traits/GeneratesTestData.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,15 @@ public static function visibilityProvider(): array
return array_map(static fn (Visibility $method) => [$method], Visibility::cases());
}

protected static function createBooking(?BookingOption $bookingOption = null): Booking
protected static function createBooking(?BookingOption $bookingOption = null, array $attributes = []): Booking
{
$booking = Booking::factory()
->for($bookingOption ?? self::createBookingOptionForEvent(Visibility::Public))
->has(User::factory(), 'bookedByUser')
->create();
->for(User::factory(), 'bookedByUser')
->create([
...$attributes,
'price' => $bookingOption?->price,
]);

if (isset($bookingOption) && $bookingOption->formFields->isNotEmpty()) {
foreach ($bookingOption->formFields as $formField) {
Expand Down Expand Up @@ -95,11 +98,11 @@ protected static function createBookingsForUser(BookingOption $bookingOption, Us
]);
}

protected static function createBookingOptionForEvent(?Visibility $visibility = null): BookingOption
protected static function createBookingOptionForEvent(?Visibility $visibility = null, array $attributes = []): BookingOption
{
return BookingOption::factory()
->for(self::createEvent($visibility))
->create();
->create($attributes);
}

protected static function createBookingOptionForEventWithCustomFormFields(?Visibility $visibility = null): BookingOption
Expand Down

0 comments on commit db99724

Please sign in to comment.