551 lines
20 KiB
PHP
551 lines
20 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Announcement;
|
|
use App\Models\User;
|
|
use App\Models\EmployerProfile;
|
|
use App\Models\Worker;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class AnnouncementApiTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected $worker;
|
|
protected $employer;
|
|
protected $workerToken;
|
|
protected $employerToken;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// Create worker with API token
|
|
$this->workerToken = 'worker-token-xyz';
|
|
$this->worker = Worker::create([
|
|
'name' => 'Jane Helper',
|
|
'email' => 'jane@example.com',
|
|
'phone' => '+971500000001',
|
|
'password' => bcrypt('password'),
|
|
'api_token' => $this->workerToken,
|
|
'status' => 'Available',
|
|
'nationality' => 'Indian',
|
|
'age' => 25,
|
|
'salary' => 1600.00,
|
|
'availability' => 'Immediate',
|
|
'experience' => '3 Years',
|
|
'religion' => 'Hindu',
|
|
'bio' => 'Experienced helper ready to work.',
|
|
]);
|
|
|
|
// Create employer with API token
|
|
$this->employerToken = 'employer-token-abc';
|
|
$this->employer = User::create([
|
|
'name' => 'Employer One',
|
|
'email' => 'emp1@example.com',
|
|
'password' => bcrypt('password'),
|
|
'role' => 'employer',
|
|
'api_token' => $this->employerToken,
|
|
]);
|
|
|
|
EmployerProfile::create([
|
|
'user_id' => $this->employer->id,
|
|
'company_name' => 'Elite Services',
|
|
'phone' => '+971500000002',
|
|
'country' => 'United Arab Emirates',
|
|
'verification_status' => 'approved',
|
|
'language' => 'English',
|
|
'notifications' => true,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test worker can retrieve all announcements.
|
|
*/
|
|
public function test_worker_can_get_announcements()
|
|
{
|
|
// Create announcement
|
|
Announcement::create([
|
|
'title' => 'Important Update',
|
|
'body' => 'Please keep your profile details updated.',
|
|
'type' => 'info',
|
|
'employer_id' => $this->employer->id,
|
|
'status' => 'approved',
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->workerToken,
|
|
])->getJson('/api/workers/announcements');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'data' => [
|
|
'announcements' => [
|
|
'*' => [
|
|
'id',
|
|
'title',
|
|
'body',
|
|
'type',
|
|
'employer_name',
|
|
'company_name',
|
|
'created_at',
|
|
'time_ago',
|
|
]
|
|
]
|
|
]
|
|
]);
|
|
|
|
$this->assertEquals('Important Update', $response->json('data.announcements.0.title'));
|
|
$this->assertEquals('Elite Services', $response->json('data.announcements.0.company_name'));
|
|
}
|
|
|
|
/**
|
|
* Test employer can get only their posted announcements via my-announcements.
|
|
*/
|
|
public function test_employer_can_get_my_announcements()
|
|
{
|
|
// Announcement by this employer
|
|
Announcement::create([
|
|
'title' => 'Employer Ann',
|
|
'body' => 'Employer specific message.',
|
|
'type' => 'success',
|
|
'employer_id' => $this->employer->id,
|
|
]);
|
|
|
|
// Announcement by another employer
|
|
$otherEmployer = User::create([
|
|
'name' => 'Employer Two',
|
|
'email' => 'emp2@example.com',
|
|
'password' => bcrypt('password'),
|
|
'role' => 'employer',
|
|
]);
|
|
Announcement::create([
|
|
'title' => 'Other Ann',
|
|
'body' => 'Other specific message.',
|
|
'type' => 'warning',
|
|
'employer_id' => $otherEmployer->id,
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->employerToken,
|
|
])->getJson('/api/employers/my-announcements');
|
|
|
|
$response->assertStatus(200);
|
|
$this->assertCount(1, $response->json('data.announcements'));
|
|
$this->assertEquals('Employer Ann', $response->json('data.announcements.0.title'));
|
|
}
|
|
|
|
/**
|
|
* Test employer can get all approved announcements.
|
|
*/
|
|
public function test_employer_can_get_all_approved_announcements()
|
|
{
|
|
// Approved announcement by this employer
|
|
Announcement::create([
|
|
'title' => 'Approved Ann 1',
|
|
'body' => 'Message 1',
|
|
'type' => 'info',
|
|
'employer_id' => $this->employer->id,
|
|
'status' => 'approved',
|
|
]);
|
|
|
|
// Pending announcement by this employer
|
|
Announcement::create([
|
|
'title' => 'Pending Ann 1',
|
|
'body' => 'Message 2',
|
|
'type' => 'info',
|
|
'employer_id' => $this->employer->id,
|
|
'status' => 'pending',
|
|
]);
|
|
|
|
// Approved announcement by another sponsor
|
|
$sponsor = \App\Models\Sponsor::create([
|
|
'full_name' => 'Sponsor Name',
|
|
'email' => 'sponsor@example.com',
|
|
'mobile' => '+971501112233',
|
|
'organization_name' => 'Charity Org',
|
|
'address' => 'Dubai',
|
|
'role' => 'sponsor',
|
|
'password' => bcrypt('password'),
|
|
]);
|
|
Announcement::create([
|
|
'title' => 'Approved Ann 2',
|
|
'body' => 'Message 3',
|
|
'type' => 'info',
|
|
'sponsor_id' => $sponsor->id,
|
|
'status' => 'approved',
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->employerToken,
|
|
])->getJson('/api/employers/announcements');
|
|
|
|
$response->assertStatus(200);
|
|
$this->assertCount(2, $response->json('data.announcements'));
|
|
$titles = collect($response->json('data.announcements'))->pluck('title');
|
|
$this->assertTrue($titles->contains('Approved Ann 1'));
|
|
$this->assertTrue($titles->contains('Approved Ann 2'));
|
|
$this->assertFalse($titles->contains('Pending Ann 1'));
|
|
}
|
|
|
|
/**
|
|
* Test employer can create a new announcement.
|
|
*/
|
|
public function test_employer_can_create_announcement()
|
|
{
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->employerToken,
|
|
])->postJson('/api/employers/announcements', [
|
|
'title' => 'Holiday Notice',
|
|
'body' => 'Office will be closed tomorrow.',
|
|
'type' => 'warning'
|
|
]);
|
|
|
|
$response->assertStatus(201)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'message',
|
|
'data' => [
|
|
'announcement' => [
|
|
'id',
|
|
'title',
|
|
'body',
|
|
'type',
|
|
'created_at',
|
|
'time_ago',
|
|
]
|
|
]
|
|
]);
|
|
|
|
$this->assertDatabaseHas('announcements', [
|
|
'title' => 'Holiday Notice',
|
|
'employer_id' => $this->employer->id,
|
|
'type' => 'warning',
|
|
'status' => 'pending',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test employer can delete their own announcement.
|
|
*/
|
|
public function test_employer_can_delete_announcement()
|
|
{
|
|
$announcement = Announcement::create([
|
|
'title' => 'Delete Me',
|
|
'body' => 'Temporary post.',
|
|
'type' => 'info',
|
|
'employer_id' => $this->employer->id,
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->employerToken,
|
|
])->deleteJson('/api/employers/announcements/' . $announcement->id);
|
|
|
|
$response->assertStatus(200);
|
|
$this->assertDatabaseMissing('announcements', [
|
|
'id' => $announcement->id,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test employer cannot delete another employer's announcement.
|
|
*/
|
|
public function test_employer_cannot_delete_other_employers_announcement()
|
|
{
|
|
$otherEmployer = User::create([
|
|
'name' => 'Employer Two',
|
|
'email' => 'emp2@example.com',
|
|
'password' => bcrypt('password'),
|
|
'role' => 'employer',
|
|
]);
|
|
|
|
$announcement = Announcement::create([
|
|
'title' => 'Other Post',
|
|
'body' => 'Do not touch.',
|
|
'type' => 'info',
|
|
'employer_id' => $otherEmployer->id,
|
|
]);
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->employerToken,
|
|
])->deleteJson('/api/employers/announcements/' . $announcement->id);
|
|
|
|
$response->assertStatus(404);
|
|
$this->assertDatabaseHas('announcements', [
|
|
'id' => $announcement->id,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test worker cannot see pending announcements until approved.
|
|
*/
|
|
public function test_worker_cannot_see_pending_announcements_until_approved()
|
|
{
|
|
$announcement = Announcement::create([
|
|
'title' => 'Pending Ann',
|
|
'body' => 'Should not be seen.',
|
|
'type' => 'info',
|
|
'employer_id' => $this->employer->id,
|
|
'status' => 'pending',
|
|
]);
|
|
|
|
// Worker fetches announcements
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->workerToken,
|
|
])->getJson('/api/workers/announcements');
|
|
|
|
$response->assertStatus(200);
|
|
$this->assertCount(0, $response->json('data.announcements'));
|
|
|
|
// Admin approves it
|
|
$announcement->update(['status' => 'approved']);
|
|
|
|
// Worker fetches announcements again
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->workerToken,
|
|
])->getJson('/api/workers/announcements');
|
|
|
|
$response->assertStatus(200);
|
|
$this->assertCount(1, $response->json('data.announcements'));
|
|
$this->assertEquals('Pending Ann', $response->json('data.announcements.0.title'));
|
|
}
|
|
|
|
/**
|
|
* Test admin can reject announcement with remarks.
|
|
*/
|
|
public function test_admin_can_reject_announcement_with_remarks()
|
|
{
|
|
$admin = User::create([
|
|
'name' => 'Admin User',
|
|
'email' => 'admin@example.com',
|
|
'password' => bcrypt('password'),
|
|
'role' => 'admin',
|
|
]);
|
|
|
|
$announcement = Announcement::create([
|
|
'title' => 'Pending Ann',
|
|
'body' => 'Event description.',
|
|
'type' => 'Charity',
|
|
'employer_id' => $this->employer->id,
|
|
'status' => 'pending',
|
|
]);
|
|
|
|
$response = $this->actingAs($admin)
|
|
->withSession(['user' => $admin])
|
|
->post('/admin/events/' . $announcement->id . '/reject', [
|
|
'remarks' => 'Inappropriate content or location details.',
|
|
]);
|
|
|
|
$response->assertStatus(302); // redirects back
|
|
|
|
$this->assertDatabaseHas('announcements', [
|
|
'id' => $announcement->id,
|
|
'status' => 'rejected',
|
|
'remarks' => 'Inappropriate content or location details.',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test employer can post and get charity announcements with contact details.
|
|
*/
|
|
public function test_employer_can_post_and_get_charity_announcement_with_contact_details()
|
|
{
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->employerToken,
|
|
])->postJson('/api/employers/announcements', [
|
|
'title' => 'Free Dental Checkup Camp',
|
|
'content' => 'Emirates Charity is providing free professional dental screening, cleanings, and educational packages for domestic helpers.',
|
|
'provided_items' => 'Free Dental screening, cleanings, and wellness kits',
|
|
'event_date' => '2026-06-15',
|
|
'event_time' => '9:00 AM - 4:00 PM',
|
|
'location_details' => 'Al Quoz Community Hall, Dubai',
|
|
'location_pin' => 'https://maps.app.goo.gl/xyz',
|
|
'contact_person_name' => 'Jane Doe',
|
|
'contact_number' => '551234567',
|
|
'country_code' => '+971',
|
|
]);
|
|
|
|
$response->assertStatus(201)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Announcement posted successfully.',
|
|
])
|
|
->assertJsonStructure([
|
|
'data' => [
|
|
'announcement' => [
|
|
'id',
|
|
'title',
|
|
'body',
|
|
'type',
|
|
'status',
|
|
'charity_details' => [
|
|
'type',
|
|
'provided_items',
|
|
'event_date',
|
|
'event_time',
|
|
'location_details',
|
|
'location_pin',
|
|
'content',
|
|
'contact_person_name',
|
|
'contact_number',
|
|
'country_code',
|
|
]
|
|
]
|
|
]
|
|
]);
|
|
|
|
$announcementId = $response->json('data.announcement.id');
|
|
|
|
// Approve it so it shows up in global get endpoint
|
|
Announcement::find($announcementId)->update(['status' => 'approved']);
|
|
|
|
// Test GET /api/employers/announcements
|
|
$getResponse = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->employerToken,
|
|
])->getJson('/api/employers/announcements');
|
|
|
|
$getResponse->assertStatus(200);
|
|
$announcements = $getResponse->json('data.announcements');
|
|
$postedAnn = collect($announcements)->firstWhere('id', $announcementId);
|
|
|
|
$this->assertNotNull($postedAnn);
|
|
$this->assertEquals('Free Dental Checkup Camp', $postedAnn['title']);
|
|
$this->assertEquals('Jane Doe', $postedAnn['charity_details']['contact_person_name']);
|
|
$this->assertEquals('551234567', $postedAnn['charity_details']['contact_number']);
|
|
$this->assertEquals('+971', $postedAnn['charity_details']['country_code']);
|
|
|
|
// Test GET /api/employers/my-announcements
|
|
$getMyResponse = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $this->employerToken,
|
|
])->getJson('/api/employers/my-announcements');
|
|
|
|
$getMyResponse->assertStatus(200);
|
|
$myAnnouncements = $getMyResponse->json('data.announcements');
|
|
$myPostedAnn = collect($myAnnouncements)->firstWhere('id', $announcementId);
|
|
|
|
$this->assertNotNull($myPostedAnn);
|
|
$this->assertEquals('Free Dental Checkup Camp', $myPostedAnn['title']);
|
|
$this->assertEquals('Jane Doe', $myPostedAnn['charity_details']['contact_person_name']);
|
|
$this->assertEquals('551234567', $myPostedAnn['charity_details']['contact_number']);
|
|
$this->assertEquals('+971', $myPostedAnn['charity_details']['country_code']);
|
|
}
|
|
|
|
/**
|
|
* Test web employer can create charity event with contact details.
|
|
*/
|
|
public function test_web_employer_can_create_charity_event()
|
|
{
|
|
$response = $this->actingAs($this->employer)
|
|
->post(route('employer.events.store'), [
|
|
'title' => 'Web Charity Camp',
|
|
'content' => 'Giving away free wellness items and tools.',
|
|
'provided_items' => 'Wellness Kits',
|
|
'event_date' => '2026-08-20',
|
|
'event_time' => '10:00 AM - 3:00 PM',
|
|
'location_details' => 'Safa Park, Dubai',
|
|
'location_pin' => 'https://maps.app.goo.gl/xyz',
|
|
'contact_person_name' => 'John Doe',
|
|
'contact_number' => '559876543',
|
|
'country_code' => '+971',
|
|
]);
|
|
|
|
$response->assertStatus(302); // Redirect on success
|
|
|
|
$this->assertDatabaseHas('announcements', [
|
|
'title' => 'Web Charity Camp',
|
|
'employer_id' => $this->employer->id,
|
|
'status' => 'pending',
|
|
]);
|
|
|
|
$announcement = Announcement::where('title', 'Web Charity Camp')->first();
|
|
$this->assertNotNull($announcement);
|
|
$body = json_decode($announcement->body, true);
|
|
$this->assertEquals('John Doe', $body['contact_person_name']);
|
|
$this->assertEquals('559876543', $body['contact_number']);
|
|
$this->assertEquals('+971', $body['country_code']);
|
|
}
|
|
|
|
/**
|
|
* Test web admin can create charity event with contact details.
|
|
*/
|
|
public function test_web_admin_can_create_charity_event()
|
|
{
|
|
$admin = User::create([
|
|
'name' => 'Admin User',
|
|
'email' => 'admin@example.com',
|
|
'password' => bcrypt('password'),
|
|
'role' => 'admin',
|
|
]);
|
|
|
|
$response = $this->actingAs($admin)
|
|
->withSession(['user' => $admin])
|
|
->post(route('admin.events.store'), [
|
|
'title' => 'Admin Charity Camp',
|
|
'content' => 'Giving away free medical checkups.',
|
|
'provided_items' => 'Medical Checkups',
|
|
'event_date' => '2026-09-10',
|
|
'event_time' => '08:00 AM - 05:00 PM',
|
|
'location_details' => 'Community Center',
|
|
'location_pin' => 'https://maps.app.goo.gl/abc',
|
|
'contact_person_name' => 'Admin Coordinator',
|
|
'contact_number' => '501234567',
|
|
'country_code' => '+971',
|
|
]);
|
|
|
|
$response->assertStatus(302); // Redirect on success
|
|
|
|
$this->assertDatabaseHas('announcements', [
|
|
'title' => 'Admin Charity Camp',
|
|
'status' => 'approved', // Admin events are auto-approved
|
|
]);
|
|
|
|
$announcement = Announcement::where('title', 'Admin Charity Camp')->first();
|
|
$this->assertNotNull($announcement);
|
|
$body = json_decode($announcement->body, true);
|
|
$this->assertEquals('Admin Coordinator', $body['contact_person_name']);
|
|
$this->assertEquals('501234567', $body['contact_number']);
|
|
$this->assertEquals('+971', $body['country_code']);
|
|
}
|
|
|
|
/**
|
|
* Test admin approving announcement creates database notification for worker.
|
|
*/
|
|
public function test_admin_approving_announcement_creates_database_notification()
|
|
{
|
|
$admin = User::create([
|
|
'name' => 'Admin User',
|
|
'email' => 'admin@example.com',
|
|
'password' => bcrypt('password'),
|
|
'role' => 'admin',
|
|
]);
|
|
|
|
$announcement = Announcement::create([
|
|
'title' => 'Important Community Event',
|
|
'body' => 'Event description.',
|
|
'type' => 'Charity',
|
|
'employer_id' => $this->employer->id,
|
|
'status' => 'pending',
|
|
]);
|
|
|
|
$this->assertEquals(0, $this->worker->notifications()->count());
|
|
|
|
$response = $this->actingAs($admin)
|
|
->withSession(['user' => $admin])
|
|
->post(route('admin.events.approve', $announcement->id));
|
|
|
|
$response->assertStatus(302);
|
|
|
|
// Verify database notification exists for worker
|
|
$this->assertEquals(1, $this->worker->notifications()->count());
|
|
$notification = $this->worker->notifications()->first();
|
|
$this->assertNotNull($notification);
|
|
$this->assertEquals('New Event: Important Community Event', $notification->data['title']);
|
|
$this->assertEquals('announcement', $notification->data['type']);
|
|
$this->assertEquals($announcement->id, $notification->data['announcement_id']);
|
|
}
|
|
}
|
|
|