661 lines
24 KiB
PHP
661 lines
24 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Sponsor;
|
|
use App\Models\User;
|
|
use App\Models\EmployerProfile;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Tests\TestCase;
|
|
|
|
class SponsorAuthApiTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
/**
|
|
* Test a pure Sponsor can register with simple info and a license file upload.
|
|
*/
|
|
public function test_sponsor_can_register_with_license()
|
|
{
|
|
$response = $this->postJson('/api/sponsors/register', [
|
|
'full_name' => 'Test Sponsor Organization',
|
|
'mobile' => '+971509990001',
|
|
'password' => 'securepassword',
|
|
'license' => [
|
|
'license_number' => '123456',
|
|
'organization_name' => 'Charity Co',
|
|
'expiry_date' => '2028-06-12',
|
|
],
|
|
'emirates_id' => [
|
|
'emirates_id_number' => '784-1988-5310327-2',
|
|
'name' => 'Ahmad Bin Ahmed',
|
|
'date_of_birth' => '1990-01-01',
|
|
'nationality' => 'Emirati',
|
|
'issue_date' => '2023-04-11',
|
|
'expiry_date' => '2028-04-11',
|
|
'employer' => 'Federal Authority',
|
|
'issue_place' => 'Abu Dhabi',
|
|
'occupation' => 'Manager'
|
|
],
|
|
'organization_name' => 'Charity Co',
|
|
'email' => 'test.sponsor@example.com',
|
|
'nationality' => 'Emirati',
|
|
'city' => 'Abu Dhabi',
|
|
'address' => 'Villa 45, Street 12',
|
|
'country_code' => '+971',
|
|
'license_expiry' => '2028-06-12',
|
|
]);
|
|
|
|
$response->assertStatus(201)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'message',
|
|
'data' => [
|
|
'sponsor' => [
|
|
'id',
|
|
'full_name',
|
|
'mobile',
|
|
'organization_name',
|
|
'nationality',
|
|
'city',
|
|
'license_file',
|
|
'emirates_id_file',
|
|
'emirates_id',
|
|
'license_expiry',
|
|
],
|
|
'token',
|
|
]
|
|
]);
|
|
|
|
$this->assertDatabaseHas('sponsors', [
|
|
'mobile' => '+971509990001',
|
|
'full_name' => 'Test Sponsor Organization',
|
|
'license_expiry' => '2028-06-12 00:00:00',
|
|
'emirates_id_name' => 'Ahmad Bin Ahmed',
|
|
'emirates_id_dob' => '1990-01-01',
|
|
'emirates_id_issue_date' => '2023-04-11',
|
|
'emirates_id_expiry' => '2028-04-11',
|
|
'emirates_id_employer' => 'Federal Authority',
|
|
'emirates_id_issue_place' => 'Abu Dhabi',
|
|
'emirates_id_occupation' => 'Manager',
|
|
]);
|
|
|
|
$sponsor = Sponsor::where('mobile', '+971509990001')->first();
|
|
$this->assertEquals('784-1988-5310327-2', $sponsor->emirates_id);
|
|
$this->assertNull($sponsor->emirates_id_file);
|
|
$this->assertNull($sponsor->license_file);
|
|
}
|
|
|
|
/**
|
|
* Test both Sponsor and Employer can log in using the unified login endpoint.
|
|
*/
|
|
public function test_unified_login_returns_correct_role_and_data()
|
|
{
|
|
// 1. Create a pure Sponsor (no User record)
|
|
$sponsorUser = Sponsor::create([
|
|
'full_name' => 'Sponsor User',
|
|
'email' => 'sponsor@example.com',
|
|
'mobile' => '+971509991111',
|
|
'password' => Hash::make('password123'),
|
|
'license_file' => 'uploads/licenses/fake.pdf',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// 2. Create an Employer (has both User and Sponsor records, legacy setup)
|
|
$employerUser = User::create([
|
|
'name' => 'Employer User',
|
|
'email' => 'employer@example.com',
|
|
'password' => Hash::make('password123'),
|
|
'role' => 'employer',
|
|
'api_token' => 'old_token',
|
|
]);
|
|
|
|
EmployerProfile::create([
|
|
'user_id' => $employerUser->id,
|
|
'company_name' => 'Employer Corp',
|
|
'phone' => '+971509992222',
|
|
'country' => 'United Arab Emirates',
|
|
'verification_status' => 'approved',
|
|
]);
|
|
|
|
Sponsor::create([
|
|
'full_name' => 'Employer User',
|
|
'email' => 'employer@example.com',
|
|
'mobile' => '+971509992222',
|
|
'password' => $employerUser->password,
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// --- Test Sponsor Login via /api/employers/login ---
|
|
$responseSponsor = $this->postJson('/api/employers/login', [
|
|
'mobile' => '+971509991111',
|
|
'password' => 'password123',
|
|
]);
|
|
|
|
$responseSponsor->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'role' => 'sponsor',
|
|
])
|
|
->assertJsonStructure([
|
|
'data' => [
|
|
'sponsor',
|
|
'token',
|
|
]
|
|
]);
|
|
|
|
// --- Test Employer Login via /api/employers/login ---
|
|
$responseEmployer = $this->postJson('/api/employers/login', [
|
|
'mobile' => '+971509992222',
|
|
'password' => 'password123',
|
|
]);
|
|
|
|
$responseEmployer->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'role' => 'employer',
|
|
])
|
|
->assertJsonStructure([
|
|
'data' => [
|
|
'employer' => [
|
|
'id',
|
|
'name',
|
|
'email',
|
|
'employer_profile',
|
|
],
|
|
'token',
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test that pure sponsors can only access their limited routes.
|
|
*/
|
|
public function test_sponsor_restricted_access()
|
|
{
|
|
$sponsor = Sponsor::create([
|
|
'full_name' => 'Pure Sponsor',
|
|
'email' => 'pure_sponsor@example.com',
|
|
'mobile' => '+971509993333',
|
|
'password' => Hash::make('password123'),
|
|
'api_token' => 'sponsor_token_abc',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// Access dashboard successfully
|
|
$responseDash = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor_token_abc',
|
|
])->getJson('/api/sponsors/dashboard');
|
|
|
|
$responseDash->assertStatus(200);
|
|
|
|
// Try to access employer protected route (should get blocked as they don't have employer token/role)
|
|
$responseEmployerRoute = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor_token_abc',
|
|
])->getJson('/api/employers/profile');
|
|
|
|
$responseEmployerRoute->assertStatus(401);
|
|
}
|
|
|
|
/**
|
|
* Test that a sponsor can post a charity event.
|
|
*/
|
|
public function test_sponsor_can_post_charity_event()
|
|
{
|
|
$sponsor = Sponsor::create([
|
|
'full_name' => 'Test Sponsor',
|
|
'organization_name' => 'Save the Children',
|
|
'email' => 'tsponsor@example.com',
|
|
'mobile' => '+971509994444',
|
|
'password' => Hash::make('password123'),
|
|
'api_token' => 'sponsor_token_xyz',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor_token_xyz',
|
|
])->postJson('/api/sponsors/charity-events', [
|
|
'title' => 'Community Ramadan Iftar',
|
|
'body' => 'Join us for a free community Iftar gathering at the center.',
|
|
'type' => 'charity',
|
|
'event_date' => '2026-06-15',
|
|
'start_time' => '09:00 AM',
|
|
'end_time' => '04:00 PM',
|
|
'provided_items' => 'Free Iftar meals, Water, Dates',
|
|
'location_details' => 'Al Quoz Community Center, Dubai',
|
|
'location_pin' => 'https://maps.app.goo.gl/xyz',
|
|
]);
|
|
|
|
$response->assertStatus(201)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Charity event posted successfully.',
|
|
'data' => [
|
|
'title' => 'Community Ramadan Iftar',
|
|
'body' => 'Join us for a free community Iftar gathering at the center.',
|
|
'type' => 'charity',
|
|
'posted_by' => 'Test Sponsor',
|
|
'organization' => 'Save the Children',
|
|
'charity_details' => [
|
|
'type' => 'Charity',
|
|
'provided_items' => 'Free Iftar meals, Water, Dates',
|
|
'event_date' => '2026-06-15',
|
|
'event_time' => '09:00 AM - 04:00 PM',
|
|
'location_details' => 'Al Quoz Community Center, Dubai',
|
|
'location_pin' => 'https://maps.app.goo.gl/xyz',
|
|
'content' => 'Join us for a free community Iftar gathering at the center.',
|
|
]
|
|
]
|
|
])
|
|
->assertJsonStructure([
|
|
'data' => [
|
|
'id',
|
|
'title',
|
|
'body',
|
|
'type',
|
|
'posted_by',
|
|
'organization',
|
|
'created_at',
|
|
'charity_details' => [
|
|
'type',
|
|
'provided_items',
|
|
'event_date',
|
|
'event_time',
|
|
'location_details',
|
|
'location_pin',
|
|
'content',
|
|
]
|
|
]
|
|
]);
|
|
|
|
$this->assertDatabaseHas('announcements', [
|
|
'title' => 'Community Ramadan Iftar',
|
|
'sponsor_id' => $sponsor->id,
|
|
'status' => 'pending',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test that a sponsor can list charity events showing both employer and sponsor events.
|
|
*/
|
|
public function test_sponsor_can_list_charity_events()
|
|
{
|
|
$sponsor = Sponsor::create([
|
|
'full_name' => 'Test Sponsor',
|
|
'organization_name' => 'Save the Children',
|
|
'email' => 'tsponsor@example.com',
|
|
'mobile' => '+971509994444',
|
|
'password' => Hash::make('password123'),
|
|
'api_token' => 'sponsor_token_xyz',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// Post a sponsor announcement
|
|
\App\Models\Announcement::create([
|
|
'title' => 'Sponsor Event',
|
|
'body' => 'Body of sponsor event',
|
|
'type' => 'charity',
|
|
'sponsor_id' => $sponsor->id,
|
|
'status' => 'approved',
|
|
]);
|
|
|
|
// Post an employer announcement
|
|
$employer = User::create([
|
|
'name' => 'Employer User',
|
|
'email' => 'employer@example.com',
|
|
'password' => Hash::make('password123'),
|
|
'role' => 'employer',
|
|
]);
|
|
EmployerProfile::create([
|
|
'user_id' => $employer->id,
|
|
'company_name' => 'Employer Co',
|
|
'phone' => '+971509995555',
|
|
'country' => 'United Arab Emirates',
|
|
]);
|
|
\App\Models\Announcement::create([
|
|
'title' => 'Employer Event',
|
|
'body' => 'Body of employer event',
|
|
'type' => 'charity',
|
|
'employer_id' => $employer->id,
|
|
'status' => 'approved',
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor_token_xyz',
|
|
])->getJson('/api/sponsors/charity-events');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
]);
|
|
|
|
$events = $response->json('data.events');
|
|
$this->assertCount(2, $events);
|
|
|
|
// Verify sponsor event details
|
|
$this->assertEquals('Sponsor Event', $events[0]['title']);
|
|
$this->assertEquals('Test Sponsor', $events[0]['posted_by']);
|
|
$this->assertEquals('Save the Children', $events[0]['organization']);
|
|
|
|
// Verify employer event details
|
|
$this->assertEquals('Employer Event', $events[1]['title']);
|
|
$this->assertEquals('Employer User', $events[1]['posted_by']);
|
|
$this->assertEquals('Employer Co', $events[1]['organization']);
|
|
}
|
|
|
|
/**
|
|
* Test that sponsor dashboard returns correct employer and worker counts.
|
|
*/
|
|
public function test_sponsor_dashboard_returns_stats()
|
|
{
|
|
$sponsor = Sponsor::create([
|
|
'full_name' => 'Test Sponsor',
|
|
'organization_name' => 'Save the Children',
|
|
'email' => 'tsponsor@example.com',
|
|
'mobile' => '+971509994444',
|
|
'password' => Hash::make('password123'),
|
|
'api_token' => 'sponsor_token_xyz',
|
|
'status' => 'active',
|
|
'license_expiry' => now()->addYear()->toDateString(),
|
|
]);
|
|
|
|
// Create some employers (Users with role = employer)
|
|
User::create([
|
|
'name' => 'Emp 1',
|
|
'email' => 'emp1@example.com',
|
|
'password' => Hash::make('password123'),
|
|
'role' => 'employer',
|
|
'subscription_status' => 'active',
|
|
]);
|
|
User::create([
|
|
'name' => 'Emp 2',
|
|
'email' => 'emp2@example.com',
|
|
'password' => Hash::make('password123'),
|
|
'role' => 'employer',
|
|
'subscription_status' => 'none',
|
|
]);
|
|
|
|
// Create some workers
|
|
\App\Models\Worker::create([
|
|
'name' => 'Worker 1',
|
|
'email' => 'w1@example.com',
|
|
'phone' => '+971509998881',
|
|
'password' => Hash::make('password123'),
|
|
'status' => 'active',
|
|
'language' => 'en',
|
|
'nationality' => 'Indian',
|
|
'city' => 'Dubai',
|
|
'age' => 25,
|
|
'salary' => 1500,
|
|
'experience' => 'None',
|
|
'religion' => 'Christian',
|
|
'bio' => 'Test',
|
|
'availability' => 'Immediate',
|
|
]);
|
|
\App\Models\Worker::create([
|
|
'name' => 'Worker 2',
|
|
'email' => 'w2@example.com',
|
|
'phone' => '+971509998882',
|
|
'password' => Hash::make('password123'),
|
|
'status' => 'hidden',
|
|
'language' => 'en',
|
|
'nationality' => 'Indian',
|
|
'city' => 'Dubai',
|
|
'age' => 25,
|
|
'salary' => 1500,
|
|
'experience' => 'None',
|
|
'religion' => 'Christian',
|
|
'bio' => 'Test',
|
|
'availability' => 'Immediate',
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor_token_xyz',
|
|
])->getJson('/api/sponsors/dashboard');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'data' => [
|
|
'sponsor' => [
|
|
'license_expiry' => now()->addYear()->toDateString(),
|
|
'validity' => 'Valid',
|
|
],
|
|
'employer_stats' => [
|
|
'total' => 2,
|
|
'active' => 1,
|
|
],
|
|
'worker_stats' => [
|
|
'total' => 2,
|
|
'active' => 1,
|
|
],
|
|
],
|
|
]);
|
|
|
|
$profileResponse = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor_token_xyz',
|
|
])->getJson('/api/sponsors/profile');
|
|
|
|
$profileResponse->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'data' => [
|
|
'sponsor' => [
|
|
'license_expiry' => now()->addYear()->toDateString(),
|
|
'validity' => 'Valid',
|
|
]
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test that sponsor can retrieve their own pending charity events.
|
|
*/
|
|
public function test_sponsor_can_list_own_pending_charity_event()
|
|
{
|
|
$sponsor = Sponsor::create([
|
|
'full_name' => 'Test Sponsor',
|
|
'organization_name' => 'Save the Children',
|
|
'email' => 'tsponsor@example.com',
|
|
'mobile' => '+971509994444',
|
|
'password' => Hash::make('password123'),
|
|
'api_token' => 'sponsor_token_xyz',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// Post a sponsor announcement (pending)
|
|
\App\Models\Announcement::create([
|
|
'title' => 'Sponsor Pending Event',
|
|
'body' => 'Body of sponsor event',
|
|
'type' => 'charity',
|
|
'sponsor_id' => $sponsor->id,
|
|
'status' => 'pending',
|
|
]);
|
|
|
|
// Post another sponsor announcement (approved)
|
|
\App\Models\Announcement::create([
|
|
'title' => 'Sponsor Approved Event',
|
|
'body' => 'Body of sponsor event 2',
|
|
'type' => 'charity',
|
|
'sponsor_id' => $sponsor->id,
|
|
'status' => 'approved',
|
|
]);
|
|
|
|
// Post another sponsor announcement (pending but from different sponsor - should NOT be returned)
|
|
$otherSponsor = Sponsor::create([
|
|
'full_name' => 'Other Sponsor',
|
|
'organization_name' => 'Other Org',
|
|
'email' => 'other@example.com',
|
|
'mobile' => '+971509990000',
|
|
'password' => Hash::make('password123'),
|
|
'status' => 'active',
|
|
]);
|
|
\App\Models\Announcement::create([
|
|
'title' => 'Other Sponsor Pending Event',
|
|
'body' => 'Body of other sponsor event',
|
|
'type' => 'charity',
|
|
'sponsor_id' => $otherSponsor->id,
|
|
'status' => 'pending',
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor_token_xyz',
|
|
])->getJson('/api/sponsors/charity-events');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
]);
|
|
|
|
$events = $response->json('data.events');
|
|
$this->assertCount(2, $events);
|
|
|
|
// Sort or check for titles
|
|
$titles = collect($events)->pluck('title');
|
|
$this->assertTrue($titles->contains('Sponsor Pending Event'));
|
|
$this->assertTrue($titles->contains('Sponsor Approved Event'));
|
|
$this->assertFalse($titles->contains('Other Sponsor Pending Event'));
|
|
}
|
|
|
|
/**
|
|
* Test registering Sponsor with explicit emirates_id, and uploading license separately.
|
|
*/
|
|
public function test_sponsor_registration_with_emirates_id_and_separate_license()
|
|
{
|
|
// 1. Register Sponsor with emirates_id in payload
|
|
$response = $this->postJson('/api/sponsors/register', [
|
|
'full_name' => 'Test Sponsor Sep',
|
|
'mobile' => '+971509990901',
|
|
'password' => 'securepassword',
|
|
'organization_name' => 'Charity Sep',
|
|
'email' => 'test.sponsor.sep@example.com',
|
|
'nationality' => 'Emirati',
|
|
'city' => 'Abu Dhabi',
|
|
'address' => 'Villa 45, Street 12',
|
|
'country_code' => '+971',
|
|
'emirates_id' => [
|
|
'emirates_id_number' => '784-1988-5310327-2',
|
|
],
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
|
|
$sponsor = Sponsor::where('email', 'test.sponsor.sep@example.com')->first();
|
|
$this->assertNotNull($sponsor);
|
|
$this->assertEquals('784-1988-5310327-2', $sponsor->emirates_id);
|
|
$this->assertNull($sponsor->license_expiry);
|
|
|
|
// 2. Upload License File
|
|
$licenseFile = UploadedFile::fake()->create('license.pdf', 500, 'application/pdf');
|
|
$responseLicense = $this->postJson('/api/sponsors/register/license', [
|
|
'email' => 'test.sponsor.sep@example.com',
|
|
'license_file' => $licenseFile,
|
|
]);
|
|
|
|
$responseLicense->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'License uploaded and processed successfully.',
|
|
])
|
|
->assertJsonStructure([
|
|
'ocr_extracted_data' => [
|
|
'expiry_date',
|
|
'license_number',
|
|
'organization_name',
|
|
]
|
|
]);
|
|
|
|
// Reload sponsor and verify license_expiry is set
|
|
$sponsor->refresh();
|
|
$this->assertEquals('2028-06-12 00:00:00', $sponsor->license_expiry->toDateTimeString());
|
|
}
|
|
|
|
/**
|
|
* Test worker forgot password user not found error.
|
|
*/
|
|
public function test_worker_forgot_password_user_not_found()
|
|
{
|
|
$response = $this->postJson('/api/workers/forgot-password', [
|
|
'phone' => '+971501111111',
|
|
]);
|
|
|
|
$response->assertStatus(404)
|
|
->assertJson([
|
|
'success' => false,
|
|
'message' => 'user not found this mobile number',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test sponsor forgot password user not found error.
|
|
*/
|
|
public function test_sponsor_forgot_password_user_not_found()
|
|
{
|
|
$response = $this->postJson('/api/sponsors/forgot-password', [
|
|
'email' => 'nonexistent.sponsor@example.com',
|
|
]);
|
|
|
|
$response->assertStatus(404)
|
|
->assertJson([
|
|
'success' => false,
|
|
'message' => 'user not found this email id',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test sponsor can change password successfully.
|
|
*/
|
|
public function test_sponsor_can_change_password()
|
|
{
|
|
$sponsor = Sponsor::create([
|
|
'full_name' => 'Sponsor Changer',
|
|
'email' => 'changer.sponsor@example.com',
|
|
'mobile' => '+971509997788',
|
|
'password' => Hash::make('Password@123'),
|
|
'api_token' => 'sponsor-changer-token',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// Sync with corresponding employer user record to test sync
|
|
$user = User::create([
|
|
'name' => 'Sponsor Changer',
|
|
'email' => 'changer.sponsor@example.com',
|
|
'password' => Hash::make('Password@123'),
|
|
'role' => 'employer',
|
|
]);
|
|
|
|
// 1. Try with wrong current password
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor-changer-token',
|
|
])->postJson('/api/sponsors/change-password', [
|
|
'current_password' => 'WrongPassword',
|
|
'new_password' => 'NewPassword@123',
|
|
'new_password_confirmation' => 'NewPassword@123',
|
|
]);
|
|
|
|
$response->assertStatus(422)
|
|
->assertJsonValidationErrors(['current_password']);
|
|
|
|
// 2. Try with correct current password
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer sponsor-changer-token',
|
|
])->postJson('/api/sponsors/change-password', [
|
|
'current_password' => 'Password@123',
|
|
'new_password' => 'NewPassword@123',
|
|
'new_password_confirmation' => 'NewPassword@123',
|
|
]);
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Password changed successfully.'
|
|
]);
|
|
|
|
// Verify password is updated for both Sponsor and User
|
|
$this->assertTrue(Hash::check('NewPassword@123', $sponsor->fresh()->password));
|
|
$this->assertTrue(Hash::check('NewPassword@123', $user->fresh()->password));
|
|
}
|
|
}
|