migrant-web/tests/Feature/AutomatedReminderTest.php

282 lines
9.4 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\User;
use App\Models\Worker;
use App\Models\Sponsor;
use App\Models\WorkerDocument;
use App\Models\EmployerProfile;
use App\Models\JobPost;
use App\Models\JobApplication;
use App\Models\JobOffer;
use App\Models\ReminderLog;
use App\Notifications\DocumentExpiryNotification;
use App\Notifications\HireConfirmationNotification;
use App\Notifications\JoiningConfirmationNotification;
use App\Notifications\PendingConfirmationNotification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Artisan;
use Tests\TestCase;
class AutomatedReminderTest extends TestCase
{
use RefreshDatabase;
private function createTestWorker(array $overrides = []): Worker
{
return Worker::create(array_merge([
'name' => 'John Worker',
'email' => 'worker@example.com',
'password' => bcrypt('password'),
'phone' => '971500000001',
'nationality' => 'Indian',
'status' => 'active',
'age' => 25,
'salary' => 2000,
'availability' => 'Immediate',
'experience' => '2 Years',
'religion' => 'Christian',
'bio' => 'Helper info',
'passport_status' => 'valid',
], $overrides));
}
public function test_document_expiry_reminders()
{
Notification::fake();
// 1. Create a Worker with a document expiring in exactly 7 days
$worker = $this->createTestWorker();
$doc = WorkerDocument::create([
'worker_id' => $worker->id,
'type' => 'passport',
'number' => 'PASS123',
'expiry_date' => now()->addDays(7)->toDateString(),
]);
// 2. Create an Employer (User) with Emirates ID expiring in exactly 3 days
$employer = User::create([
'name' => 'Alice Employer',
'email' => 'employer@example.com',
'password' => bcrypt('password'),
'role' => 'employer',
]);
$employerProfile = EmployerProfile::create([
'user_id' => $employer->id,
'phone' => '971500000002',
'address' => 'Dubai',
'emirates_id_expiry' => now()->addDays(3)->toDateString(),
]);
// 3. Create a Sponsor with Emirates ID expiring in exactly 1 day
$sponsor = Sponsor::create([
'full_name' => 'Sponsor Bob',
'email' => 'sponsor@example.com',
'mobile' => '971500000003',
'password' => bcrypt('password'),
'emirates_id_expiry' => now()->addDays(1)->toDateString(),
]);
// Run the command
Artisan::call('app:send-reminders');
// Assert Worker got Passport expiry 7 days notification
Notification::assertSentTo(
$worker,
DocumentExpiryNotification::class,
function ($notification) {
return $notification->documentType === 'Passport' &&
$notification->daysRemaining === 7 &&
$notification->reminderLevel === '7_days';
}
);
// Assert Employer got Emirates ID expiry 3 days notification
Notification::assertSentTo(
$employer,
DocumentExpiryNotification::class,
function ($notification) {
return $notification->documentType === 'Emirates ID' &&
$notification->daysRemaining === 3 &&
$notification->reminderLevel === '3_days';
}
);
// Assert Sponsor got Emirates ID expiry 1 day notification
Notification::assertSentTo(
$sponsor,
DocumentExpiryNotification::class,
function ($notification) {
return $notification->documentType === 'Emirates ID' &&
$notification->daysRemaining === 1 &&
$notification->reminderLevel === '1_day';
}
);
// Assert reminder logs were created
$this->assertDatabaseHas('reminder_logs', [
'user_type' => get_class($worker),
'user_id' => $worker->id,
'event_type' => 'document_expiry',
'reminder_level' => '7_days',
]);
$this->assertDatabaseHas('reminder_logs', [
'user_type' => get_class($employer),
'user_id' => $employer->id,
'event_type' => 'document_expiry',
'reminder_level' => '3_days',
]);
$this->assertDatabaseHas('reminder_logs', [
'user_type' => get_class($sponsor),
'user_id' => $sponsor->id,
'event_type' => 'document_expiry_emirates',
'reminder_level' => '1_day',
]);
// Run the command again to ensure duplicate is prevented
Notification::fake();
Artisan::call('app:send-reminders');
Notification::assertNothingSent();
}
public function test_hire_and_joining_confirmations_reminders()
{
Notification::fake();
// Create Employer
$employer = User::create([
'name' => 'Alice Employer',
'email' => 'employer@example.com',
'password' => bcrypt('password'),
'role' => 'employer',
]);
// Create Worker
$worker = $this->createTestWorker();
// Create a Job Post starting in 7 days
$job = JobPost::create([
'employer_id' => $employer->id,
'title' => 'Housekeeper',
'location' => 'Dubai',
'salary' => 2000,
'workers_needed' => 1,
'job_type' => 'Full Time',
'start_date' => now()->addDays(7)->toDateString(),
'description' => 'Test job',
'status' => 'active',
]);
// Create a Job Application with status 'selected' (needs Hire Confirmation)
$appSelected = JobApplication::create([
'job_id' => $job->id,
'worker_id' => $worker->id,
'status' => 'selected',
]);
// Create another Job Post starting in 3 days
$jobHired = JobPost::create([
'employer_id' => $employer->id,
'title' => 'Nanny',
'location' => 'Dubai',
'salary' => 2500,
'workers_needed' => 1,
'job_type' => 'Full Time',
'start_date' => now()->addDays(3)->toDateString(),
'description' => 'Test job hired',
'status' => 'active',
]);
// Create a Job Application with status 'hired' (needs Joining Confirmation)
$appHired = JobApplication::create([
'job_id' => $jobHired->id,
'worker_id' => $worker->id,
'status' => 'hired',
]);
// Run the command
Artisan::call('app:send-reminders');
// Assert Employer got Hire Confirmation 7 days notification
Notification::assertSentTo(
$employer,
HireConfirmationNotification::class,
function ($notification) use ($appSelected) {
return $notification->jobTitle === 'Housekeeper' &&
$notification->workerName === 'John Worker' &&
$notification->daysRemaining === 7 &&
$notification->applicationId === $appSelected->id;
}
);
// Assert Worker got Joining Confirmation 3 days notification
Notification::assertSentTo(
$worker,
JoiningConfirmationNotification::class,
function ($notification) use ($appHired) {
return $notification->jobTitle === 'Nanny' &&
$notification->employerName === 'Alice Employer' &&
$notification->daysRemaining === 3 &&
$notification->applicationId === $appHired->id;
}
);
// Verify duplicate prevention
Notification::fake();
Artisan::call('app:send-reminders');
Notification::assertNothingSent();
}
public function test_pending_direct_job_offer_reminders()
{
Notification::fake();
// Create Employer
$employer = User::create([
'name' => 'Alice Employer',
'email' => 'employer@example.com',
'password' => bcrypt('password'),
'role' => 'employer',
]);
// Create Worker
$worker = $this->createTestWorker();
// Create pending direct Job Offer starting in 1 day
$offer = JobOffer::create([
'employer_id' => $employer->id,
'worker_id' => $worker->id,
'work_date' => now()->addDays(1)->toDateString(),
'location' => 'Dubai Marina',
'salary' => 3000,
'status' => 'pending',
]);
// Run the command
Artisan::call('app:send-reminders');
// Assert Worker got Pending Direct Job Offer 1 day notification
Notification::assertSentTo(
$worker,
PendingConfirmationNotification::class,
function ($notification) use ($offer) {
return $notification->actionType === 'accept_offer' &&
$notification->daysRemaining === 1 &&
$notification->entityId === $offer->id;
}
);
// Verify duplicate prevention
Notification::fake();
Artisan::call('app:send-reminders');
Notification::assertNothingSent();
}
}