migrant-web/tests/Feature/WorkerEmployersApiTest.php

606 lines
22 KiB
PHP

<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\Models\Worker;
use App\Models\WorkerDocument;
use App\Models\User;
use App\Models\JobOffer;
use App\Models\EmployerProfile;
class WorkerEmployersApiTest extends TestCase
{
use RefreshDatabase;
public function test_worker_dashboard_current_employer_detail()
{
// Create worker
$worker = Worker::create([
'name' => 'Rahul Sharma',
'email' => 'rahul@example.com',
'phone' => '+971501234567',
'language' => 'HI',
'password' => bcrypt('password'),
'nationality' => 'Indian',
'age' => 25,
'salary' => 1500,
'availability' => 'Immediate',
'experience' => 'Not Specified',
'religion' => 'Not Specified',
'bio' => 'Test',
'verified' => true,
'status' => 'active',
'api_token' => 'worker-test-token',
]);
// Create passport document to prevent pending 404
WorkerDocument::create([
'worker_id' => $worker->id,
'type' => 'passport',
'number' => '123456',
'file_path' => 'passports/test.pdf',
]);
// Create an employer
$employer = User::create([
'name' => 'Employer One',
'email' => 'emp1@example.com',
'password' => bcrypt('password'),
'role' => 'employer',
]);
EmployerProfile::create([
'user_id' => $employer->id,
'company_name' => 'Ahmad Tech Ltd',
'nationality' => 'UAE',
'city' => 'Dubai',
]);
// Create an accepted job offer (current employer)
JobOffer::create([
'employer_id' => $employer->id,
'worker_id' => $worker->id,
'work_date' => now()->subDays(10),
'location' => 'Dubai',
'salary' => 2500,
'status' => 'accepted',
'notes' => 'Current Active Job',
]);
// Hit the worker dashboard API
$response = $this->withHeaders([
'Authorization' => 'Bearer worker-test-token',
])->getJson('/api/workers/dashboard');
$response->assertStatus(200)
->assertJson([
'success' => true,
'data' => [
'current_employer' => [
'id' => $employer->id,
'name' => 'Employer One',
'company_name' => 'Ahmad Tech Ltd',
'city' => 'Dubai',
'nationality' => 'UAE',
],
'currently_working_sponsor' => [
'id' => $employer->id,
'name' => 'Employer One',
'company_name' => 'Ahmad Tech Ltd',
'city' => 'Dubai',
'nationality' => 'UAE',
]
]
]);
}
public function test_worker_employers_list_pagination_and_sorting()
{
// Create worker
$worker = Worker::create([
'name' => 'Rahul Sharma',
'email' => 'rahul@example.com',
'phone' => '+971501234567',
'language' => 'HI',
'password' => bcrypt('password'),
'nationality' => 'Indian',
'age' => 25,
'salary' => 1500,
'availability' => 'Immediate',
'experience' => 'Not Specified',
'religion' => 'Not Specified',
'bio' => 'Test',
'verified' => true,
'status' => 'active',
'api_token' => 'worker-test-token',
]);
WorkerDocument::create([
'worker_id' => $worker->id,
'type' => 'passport',
'number' => '123456',
'file_path' => 'passports/test.pdf',
]);
// Create 3 employers
$emp1 = User::create([
'name' => 'Employer One',
'email' => 'emp1@example.com',
'password' => bcrypt('password'),
'role' => 'employer'
]);
EmployerProfile::create(['user_id' => $emp1->id, 'company_name' => 'Tech One']);
$emp2 = User::create([
'name' => 'Employer Two',
'email' => 'emp2@example.com',
'password' => bcrypt('password'),
'role' => 'employer'
]);
EmployerProfile::create(['user_id' => $emp2->id, 'company_name' => 'Tech Two']);
$emp3 = User::create([
'name' => 'Employer Three',
'email' => 'emp3@example.com',
'password' => bcrypt('password'),
'role' => 'employer'
]);
EmployerProfile::create(['user_id' => $emp3->id, 'company_name' => 'Tech Three']);
// Create JobOffers:
// Offer 1: Completed status, joining 20 days ago
JobOffer::create([
'employer_id' => $emp1->id,
'worker_id' => $worker->id,
'work_date' => now()->subDays(20),
'location' => 'Abu Dhabi',
'salary' => 2000,
'status' => 'completed',
'notes' => 'Past job',
]);
// Offer 2: Cancelled status, joining 30 days ago
JobOffer::create([
'employer_id' => $emp2->id,
'worker_id' => $worker->id,
'work_date' => now()->subDays(30),
'location' => 'Sharjah',
'salary' => 1800,
'status' => 'cancelled',
'notes' => 'Cancelled job',
]);
// Offer 3: Accepted (Active) status, joining 10 days ago
JobOffer::create([
'employer_id' => $emp3->id,
'worker_id' => $worker->id,
'work_date' => now()->subDays(10),
'location' => 'Dubai',
'salary' => 3000,
'status' => 'accepted',
'notes' => 'Active job',
]);
// List all employers (should return 3)
// With Active employer at the top, then previous employers sorted by work_date desc:
// 1st: Emp 3 (Active)
// 2nd: Emp 1 (Completed, 20 days ago)
// 3rd: Emp 2 (Cancelled, 30 days ago)
$response = $this->withHeaders([
'Authorization' => 'Bearer worker-test-token',
])->getJson('/api/workers/employers');
$response->assertStatus(200);
$data = $response->json('data.employers');
$this->assertCount(3, $data);
$this->assertEquals('Active', $data[0]['status']);
$this->assertEquals('Employer Three', $data[0]['employer']['name']);
$this->assertEquals('Completed', $data[1]['status']);
$this->assertEquals('Employer One', $data[1]['employer']['name']);
$this->assertEquals('Cancelled', $data[2]['status']);
$this->assertEquals('Employer Two', $data[2]['employer']['name']);
// Test filtering by status Completed
$responseFiltered = $this->withHeaders([
'Authorization' => 'Bearer worker-test-token',
])->getJson('/api/workers/employers?status=completed');
$responseFiltered->assertStatus(200);
$filteredData = $responseFiltered->json('data.employers');
$this->assertCount(1, $filteredData);
$this->assertEquals('Completed', $filteredData[0]['status']);
$this->assertEquals('Employer One', $filteredData[0]['employer']['name']);
// Test filtering by status Active
$responseActive = $this->withHeaders([
'Authorization' => 'Bearer worker-test-token',
])->getJson('/api/workers/employers?status=active');
$responseActive->assertStatus(200);
$activeData = $responseActive->json('data.employers');
$this->assertCount(1, $activeData);
$this->assertEquals('Active', $activeData[0]['status']);
$this->assertEquals('Employer Three', $activeData[0]['employer']['name']);
// Test pagination
$responsePaginated = $this->withHeaders([
'Authorization' => 'Bearer worker-test-token',
])->getJson('/api/workers/employers?per_page=2');
$responsePaginated->assertStatus(200);
$paginatedData = $responsePaginated->json('data.employers');
$this->assertCount(2, $paginatedData);
$this->assertEquals(3, $responsePaginated->json('data.pagination.total'));
$this->assertEquals(2, $responsePaginated->json('data.pagination.per_page'));
}
public function test_worker_can_view_employer_profile_with_permissions_and_reviews()
{
// Create worker
$worker = Worker::create([
'name' => 'Rahul Sharma',
'email' => 'rahul@example.com',
'phone' => '+971501234567',
'language' => 'HI',
'password' => bcrypt('password'),
'nationality' => 'Indian',
'age' => 25,
'salary' => 1500,
'availability' => 'Immediate',
'experience' => 'Not Specified',
'religion' => 'Not Specified',
'bio' => 'Test',
'verified' => true,
'status' => 'active',
'api_token' => 'worker-test-token',
]);
WorkerDocument::create([
'worker_id' => $worker->id,
'type' => 'passport',
'number' => '123456',
'file_path' => 'passports/test.pdf',
]);
// Create an employer
$employer = User::create([
'name' => 'Employer One',
'email' => 'emp1@example.com',
'password' => bcrypt('password'),
'role' => 'employer',
]);
EmployerProfile::create([
'user_id' => $employer->id,
'company_name' => 'Ahmad Tech Ltd',
'phone' => '+971500000001',
'nationality' => 'UAE',
'city' => 'Dubai',
'accommodation' => 'Provided',
'language' => 'English',
]);
// Create active job post
\App\Models\JobPost::create([
'employer_id' => $employer->id,
'title' => 'Housekeeper Needed',
'location' => 'Dubai Marina',
'salary' => 2500,
'workers_needed' => 1,
'job_type' => 'Full Time',
'start_date' => now()->addDays(5)->toDateString(),
'description' => 'Clean house',
'status' => 'active',
]);
// Create an accepted job offer (connection exists)
JobOffer::create([
'employer_id' => $employer->id,
'worker_id' => $worker->id,
'work_date' => now()->subDays(10),
'location' => 'Dubai',
'salary' => 2500,
'status' => 'accepted',
]);
// Create a review submitted by another worker
$otherWorker = Worker::create([
'name' => 'John Doe',
'email' => 'john@example.com',
'phone' => '+971501234568',
'password' => bcrypt('password'),
'nationality' => 'Filipino',
'age' => 25,
'salary' => 1500,
'availability' => 'Immediate',
'experience' => 'Not Specified',
'religion' => 'Not Specified',
'bio' => 'Test',
'passport_status' => 'valid',
]);
\App\Models\EmployerReview::create([
'worker_id' => $otherWorker->id,
'employer_id' => $employer->id,
'rating' => 5,
'title' => 'Excellent sponsor',
'comment' => 'Very polite and pays on time.',
]);
// Hit the new API endpoint
$response = $this->withHeaders([
'Authorization' => 'Bearer worker-test-token',
])->getJson("/api/workers/employers/{$employer->id}");
$response->assertStatus(200);
$response->assertJsonPath('success', true);
$response->assertJsonPath('data.employer.name', 'Employer One');
$response->assertJsonPath('data.employer.email', 'emp1@example.com'); // Contact info visible because of JobOffer connection
$response->assertJsonPath('data.employer.phone', '+971500000001');
$response->assertJsonPath('data.employer.company_name', 'Ahmad Tech Ltd');
$response->assertJsonPath('data.employer.rating', 5);
$response->assertJsonPath('data.employer.reviews_count', 1);
$response->assertJsonPath('data.employer.review_summary.stars.5', 1);
$response->assertJsonCount(1, 'data.employer.active_jobs');
$response->assertJsonPath('data.employer.active_jobs.0.title', 'Housekeeper Needed');
$response->assertJsonCount(1, 'data.reviews.data');
$response->assertJsonPath('data.reviews.data.0.worker.name', 'John Doe');
$response->assertJsonPath('data.reviews.data.0.title', 'Excellent sponsor');
}
public function test_worker_can_view_employer_profile_without_permissions_masks_contact()
{
// Create worker
$worker = Worker::create([
'name' => 'Rahul Sharma',
'email' => 'rahul@example.com',
'phone' => '+971501234567',
'language' => 'HI',
'password' => bcrypt('password'),
'nationality' => 'Indian',
'age' => 25,
'salary' => 1500,
'availability' => 'Immediate',
'experience' => 'Not Specified',
'religion' => 'Not Specified',
'bio' => 'Test',
'verified' => true,
'status' => 'active',
'api_token' => 'worker-test-token',
]);
WorkerDocument::create([
'worker_id' => $worker->id,
'type' => 'passport',
'number' => '123456',
'file_path' => 'passports/test.pdf',
]);
// Create an employer
$employer = User::create([
'name' => 'Employer One',
'email' => 'emp1@example.com',
'password' => bcrypt('password'),
'role' => 'employer',
]);
EmployerProfile::create([
'user_id' => $employer->id,
'company_name' => 'Ahmad Tech Ltd',
'phone' => '+971500000001',
]);
// Hit the API (no connection exists)
$response = $this->withHeaders([
'Authorization' => 'Bearer worker-test-token',
])->getJson("/api/workers/employers/{$employer->id}");
$response->assertStatus(200);
$response->assertJsonPath('success', true);
$response->assertJsonPath('data.employer.name', 'Employer One');
$response->assertJsonPath('data.employer.email', null); // Masked/null since no connection exists
$response->assertJsonPath('data.employer.phone', null);
}
public function test_worker_hired_via_job_application_appears_in_employers_list()
{
// 1. Create a worker
$worker = Worker::create([
'name' => 'Hired Worker',
'email' => 'hiredworker@example.com',
'phone' => '+971501234567',
'language' => 'HI',
'password' => bcrypt('password'),
'nationality' => 'Indian',
'age' => 25,
'salary' => 1500,
'availability' => 'Immediate',
'experience' => 'Not Specified',
'religion' => 'Not Specified',
'bio' => 'Test',
'verified' => true,
'status' => 'active',
'api_token' => 'worker-hired-token',
]);
WorkerDocument::create([
'worker_id' => $worker->id,
'type' => 'passport',
'number' => '123456',
'file_path' => 'passports/test.pdf',
]);
// 2. Create employer with active subscription
$employer = User::create([
'name' => 'Premium Employer',
'email' => 'premium_emp@example.com',
'password' => bcrypt('password'),
'role' => 'employer',
'subscription_status' => 'active',
'api_token' => 'premium_employer_token',
]);
EmployerProfile::create([
'user_id' => $employer->id,
'company_name' => 'Premium Corp Ltd',
'nationality' => 'UAE',
'city' => 'Abu Dhabi',
]);
\App\Models\Subscription::create([
'user_id' => $employer->id,
'plan_id' => 'premium',
'amount_aed' => 100.00,
'starts_at' => now(),
'expires_at' => now()->addDays(30),
'status' => 'active',
]);
// 3. Create a JobPost
$job = \App\Models\JobPost::create([
'employer_id' => $employer->id,
'title' => 'Housekeeper Needed',
'workers_needed' => 1,
'location' => 'Abu Dhabi',
'salary' => 2000,
'job_type' => 'Full Time',
'start_date' => now()->addDays(5),
'description' => 'Test job',
'requirements' => 'None',
'status' => 'active',
]);
// 4. Create JobApplication
$application = \App\Models\JobApplication::create([
'job_id' => $job->id,
'worker_id' => $worker->id,
'status' => 'applied',
'notes' => 'Looking forward to work',
]);
// Verify employer list is empty for the worker initially
$response = $this->withHeaders([
'Authorization' => 'Bearer worker-hired-token',
])->getJson('/api/workers/employers');
$response->assertStatus(200);
$response->assertJsonCount(0, 'data.employers');
// 5. Employer hires candidate via API
$response = $this->postJson("/api/employers/applications/{$application->id}/status", [
'status' => 'hired',
'notes' => 'Hired and approved'
], [
'Authorization' => 'Bearer premium_employer_token'
]);
$response->assertStatus(200);
// Worker confirms the hire
$response = $this->postJson("/api/workers/applied-jobs/{$application->id}/confirm-hire", [], [
'Authorization' => 'Bearer worker-hired-token'
]);
$response->assertStatus(200);
// Verify that the JobOffer with accepted status has been created
$this->assertDatabaseHas('job_offers', [
'employer_id' => $employer->id,
'worker_id' => $worker->id,
'status' => 'accepted',
]);
// 6. Hit the worker employers API and assert that the employer is now listed
$response = $this->withHeaders([
'Authorization' => 'Bearer worker-hired-token',
])->getJson('/api/workers/employers');
$response->assertStatus(200);
$response->assertJsonCount(1, 'data.employers');
$response->assertJsonPath('data.employers.0.employer.name', 'Premium Employer');
$response->assertJsonPath('data.employers.0.employer.company_name', 'Premium Corp Ltd');
$response->assertJsonPath('data.employers.0.status', 'Active');
}
public function test_worker_hired_via_job_application_appears_without_job_offer()
{
// 1. Create a worker
$worker = Worker::create([
'name' => 'Hired Worker Legacy',
'email' => 'legacyworker@example.com',
'phone' => '+971501234560',
'language' => 'HI',
'password' => bcrypt('password'),
'nationality' => 'Indian',
'age' => 25,
'salary' => 1500,
'availability' => 'Immediate',
'experience' => 'Not Specified',
'religion' => 'Not Specified',
'bio' => 'Test',
'verified' => true,
'status' => 'active',
'api_token' => 'worker-legacy-token',
]);
WorkerDocument::create([
'worker_id' => $worker->id,
'type' => 'passport',
'number' => '123456',
'file_path' => 'passports/test.pdf',
]);
// 2. Create employer
$employer = User::create([
'name' => 'Legacy Employer',
'email' => 'legacy_emp@example.com',
'password' => bcrypt('password'),
'role' => 'employer',
'subscription_status' => 'active',
'api_token' => 'legacy_employer_token',
]);
EmployerProfile::create([
'user_id' => $employer->id,
'company_name' => 'Legacy Corp Ltd',
'nationality' => 'UAE',
'city' => 'Dubai',
]);
// 3. Create a JobPost
$job = \App\Models\JobPost::create([
'employer_id' => $employer->id,
'title' => 'Housekeeper Needed Legacy',
'workers_needed' => 1,
'location' => 'Dubai',
'salary' => 2000,
'job_type' => 'Full Time',
'start_date' => now()->addDays(5),
'description' => 'Test job',
'requirements' => 'None',
'status' => 'active',
]);
// 4. Create JobApplication with status 'hired' directly, and NO JobOffer
$application = \App\Models\JobApplication::create([
'job_id' => $job->id,
'worker_id' => $worker->id,
'status' => 'hired',
'notes' => 'Hired directly in DB previously',
]);
// 5. Hit the worker employers API and assert that the employer is listed
$response = $this->withHeaders([
'Authorization' => 'Bearer worker-legacy-token',
])->getJson('/api/workers/employers');
$response->assertStatus(200);
$response->assertJsonCount(1, 'data.employers');
$response->assertJsonPath('data.employers.0.employer.name', 'Legacy Employer');
$response->assertJsonPath('data.employers.0.employer.company_name', 'Legacy Corp Ltd');
$response->assertJsonPath('data.employers.0.status', 'Active');
}
}