'John Worker', 'email' => 'worker@example.com', 'password' => bcrypt('password'), 'phone' => '971500000001', 'nationality' => 'Indian', 'status' => 'active', 'api_token' => 'worker_api_token', 'age' => 25, 'salary' => 2000, 'availability' => 'Immediate', 'experience' => '2 Years', 'religion' => 'Christian', 'bio' => 'Helper info', 'passport_status' => 'valid', ], $overrides)); } private function createTestEmployer(array $overrides = []): User { return User::create(array_merge([ 'name' => 'Alice Employer', 'email' => 'employer@example.com', 'password' => bcrypt('password'), 'role' => 'employer', 'api_token' => 'employer_api_token', 'subscription_status' => 'active', ], $overrides)); } public function test_worker_can_list_notifications_with_filters() { $worker = $this->createTestWorker(); // Send two notifications $worker->notify(new DocumentExpiryNotification('Passport', '2026-12-31', 30, '30_days')); $worker->notify(new DocumentExpiryNotification('Visa', '2026-12-31', 7, '7_days')); // Mark the Passport notification as read deterministically $passportNotification = $worker->unreadNotifications()->where('data->document_type', 'Passport')->first(); $passportNotification->markAsRead(); // 1. Fetch all notifications $response = $this->getJson('/api/workers/notifications', [ 'Authorization' => 'Bearer worker_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $response->assertJsonCount(2, 'data.notifications'); // 2. Fetch unread notifications $response = $this->getJson('/api/workers/notifications?filter=unread', [ 'Authorization' => 'Bearer worker_api_token' ]); $response->assertStatus(200); $response->assertJsonCount(1, 'data.notifications'); $response->assertJsonPath('data.notifications.0.data.document_type', 'Visa'); // 3. Fetch read notifications $response = $this->getJson('/api/workers/notifications?filter=read', [ 'Authorization' => 'Bearer worker_api_token' ]); $response->assertStatus(200); $response->assertJsonCount(1, 'data.notifications'); $response->assertJsonPath('data.notifications.0.data.document_type', 'Passport'); } public function test_worker_can_mark_single_and_all_notifications_as_read() { $worker = $this->createTestWorker(); // Send two notifications $worker->notify(new DocumentExpiryNotification('Passport', '2026-12-31', 30, '30_days')); $worker->notify(new DocumentExpiryNotification('Visa', '2026-12-31', 7, '7_days')); $unread = $worker->unreadNotifications; $this->assertEquals(2, $unread->count()); // 1. Mark single notification as read $notificationId = $unread->first()->id; $response = $this->putJson("/api/workers/notifications/{$notificationId}/read", [], [ 'Authorization' => 'Bearer worker_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $this->assertEquals(1, $worker->fresh()->unreadNotifications->count()); // 2. Mark all notifications as read $response = $this->putJson('/api/workers/notifications/read', [], [ 'Authorization' => 'Bearer worker_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $this->assertEquals(0, $worker->fresh()->unreadNotifications->count()); } public function test_worker_can_delete_single_and_all_notifications() { $worker = $this->createTestWorker(); // Send two notifications $worker->notify(new DocumentExpiryNotification('Passport', '2026-12-31', 30, '30_days')); $worker->notify(new DocumentExpiryNotification('Visa', '2026-12-31', 7, '7_days')); $this->assertEquals(2, $worker->notifications()->count()); // 1. Delete single notification $notificationId = $worker->notifications->first()->id; $response = $this->deleteJson("/api/workers/notifications/{$notificationId}", [], [ 'Authorization' => 'Bearer worker_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $this->assertEquals(1, $worker->fresh()->notifications()->count()); // 2. Delete all notifications $response = $this->deleteJson('/api/workers/notifications', [], [ 'Authorization' => 'Bearer worker_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $this->assertEquals(0, $worker->fresh()->notifications()->count()); } public function test_employer_can_list_notifications_with_filters() { $employer = $this->createTestEmployer(); // Send two notifications $employer->notify(new DocumentExpiryNotification('Emirates ID', '2026-12-31', 30, '30_days')); $employer->notify(new DocumentExpiryNotification('Trade License', '2026-12-31', 7, '7_days')); // Mark the Emirates ID notification as read deterministically $emiratesIdNotification = $employer->unreadNotifications()->where('data->document_type', 'Emirates ID')->first(); $emiratesIdNotification->markAsRead(); // 1. Fetch all notifications $response = $this->getJson('/api/employers/notifications', [ 'Authorization' => 'Bearer employer_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $response->assertJsonCount(2, 'data.notifications'); // 2. Fetch unread notifications $response = $this->getJson('/api/employers/notifications?filter=unread', [ 'Authorization' => 'Bearer employer_api_token' ]); $response->assertStatus(200); $response->assertJsonCount(1, 'data.notifications'); $response->assertJsonPath('data.notifications.0.data.document_type', 'Trade License'); // 3. Fetch read notifications $response = $this->getJson('/api/employers/notifications?filter=read', [ 'Authorization' => 'Bearer employer_api_token' ]); $response->assertStatus(200); $response->assertJsonCount(1, 'data.notifications'); $response->assertJsonPath('data.notifications.0.data.document_type', 'Emirates ID'); } public function test_employer_can_mark_single_and_all_notifications_as_read() { $employer = $this->createTestEmployer(); // Send two notifications $employer->notify(new DocumentExpiryNotification('Emirates ID', '2026-12-31', 30, '30_days')); $employer->notify(new DocumentExpiryNotification('Trade License', '2026-12-31', 7, '7_days')); $unread = $employer->unreadNotifications; $this->assertEquals(2, $unread->count()); // 1. Mark single notification as read $notificationId = $unread->first()->id; $response = $this->putJson("/api/employers/notifications/{$notificationId}/read", [], [ 'Authorization' => 'Bearer employer_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $this->assertEquals(1, $employer->fresh()->unreadNotifications->count()); // 2. Mark all notifications as read $response = $this->putJson('/api/employers/notifications/read', [], [ 'Authorization' => 'Bearer employer_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $this->assertEquals(0, $employer->fresh()->unreadNotifications->count()); } public function test_employer_can_delete_single_and_all_notifications() { $employer = $this->createTestEmployer(); // Send two notifications $employer->notify(new DocumentExpiryNotification('Emirates ID', '2026-12-31', 30, '30_days')); $employer->notify(new DocumentExpiryNotification('Trade License', '2026-12-31', 7, '7_days')); $this->assertEquals(2, $employer->notifications()->count()); // 1. Delete single notification $notificationId = $employer->notifications->first()->id; $response = $this->deleteJson("/api/employers/notifications/{$notificationId}", [], [ 'Authorization' => 'Bearer employer_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $this->assertEquals(1, $employer->fresh()->notifications()->count()); // 2. Delete all notifications $response = $this->deleteJson('/api/employers/notifications', [], [ 'Authorization' => 'Bearer employer_api_token' ]); $response->assertStatus(200); $response->assertJsonPath('success', true); $this->assertEquals(0, $employer->fresh()->notifications()->count()); } public function test_push_notification_sent_when_job_status_changes() { $worker = $this->createTestWorker(); $employer = $this->createTestEmployer(); $jobPost = \App\Models\JobPost::create([ 'employer_id' => $employer->id, 'title' => 'Test Maid Job', 'main_profession' => 'Housekeeper', 'workers_needed' => 1, 'job_type' => 'Full Time', 'location' => 'Dubai', 'salary' => 2000, 'start_date' => now()->addDays(7), 'description' => 'Test description', 'status' => 'active', ]); \App\Models\JobApplication::create([ 'worker_id' => $worker->id, 'job_id' => $jobPost->id, 'status' => 'applied' ]); $this->assertEquals(0, $worker->notifications()->count()); // Update JobPost status $jobPost->update(['status' => 'closed']); $notifications = $worker->fresh()->notifications; $this->assertEquals(1, $notifications->count()); $notification = $notifications->first(); $this->assertEquals('Job Status Changed', $notification->data['title']); $this->assertEquals('job_status_change', $notification->data['type']); $this->assertEquals($jobPost->id, $notification->data['job_id']); $this->assertEquals('active', $notification->data['old_status']); $this->assertEquals('closed', $notification->data['new_status']); } public function test_push_notification_sent_when_worker_status_changes() { $worker = $this->createTestWorker([ 'status' => 'active' ]); $this->assertEquals(0, $worker->notifications()->count()); // Update Worker status $worker->update(['status' => 'Hired']); $notifications = $worker->fresh()->notifications; $this->assertEquals(1, $notifications->count()); $notification = $notifications->first(); $this->assertEquals('Profile Status Update', $notification->data['title']); $this->assertEquals('worker_status_change', $notification->data['type']); $this->assertEquals($worker->id, $notification->data['worker_id']); $this->assertEquals('active', $notification->data['old_status']); $this->assertEquals('Hired', $notification->data['new_status']); } }