'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(); } }