370 lines
13 KiB
PHP
370 lines
13 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\User;
|
|
use App\Models\Worker;
|
|
use App\Models\JobPost;
|
|
use App\Models\JobApplication;
|
|
use App\Models\JobOffer;
|
|
use App\Models\Conversation;
|
|
use App\Models\Message;
|
|
use App\Models\Review;
|
|
use App\Models\EmployerReview;
|
|
use App\Notifications\WorkerNoResponseNotification;
|
|
use App\Notifications\WorkerReviewReminderNotification;
|
|
use App\Notifications\EmployerReviewReminderNotification;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Notification;
|
|
use Illuminate\Support\Facades\Artisan;
|
|
use Tests\TestCase;
|
|
|
|
class NewRemindersAndSettingsTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function createTestWorker(array $overrides = []): Worker
|
|
{
|
|
return Worker::create(array_merge([
|
|
'name' => '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_no_response_reminders()
|
|
{
|
|
Notification::fake();
|
|
|
|
$worker = $this->createTestWorker();
|
|
$employer = $this->createTestEmployer();
|
|
|
|
// 1. Create a pending direct Job Offer created exactly 14 days ago
|
|
$offer = JobOffer::create([
|
|
'employer_id' => $employer->id,
|
|
'worker_id' => $worker->id,
|
|
'work_date' => now()->addDays(5)->toDateString(),
|
|
'location' => 'Dubai Marina',
|
|
'salary' => 3000,
|
|
'status' => 'pending',
|
|
]);
|
|
// Force created_at to 14 days ago
|
|
$offer->created_at = now()->subDays(14);
|
|
$offer->save();
|
|
|
|
// 2. Create a conversation where the last message is from employer, sent 14 days ago
|
|
$conversation = Conversation::create([
|
|
'employer_id' => $employer->id,
|
|
'worker_id' => $worker->id,
|
|
]);
|
|
$message = Message::create([
|
|
'conversation_id' => $conversation->id,
|
|
'sender_type' => 'App\Models\User',
|
|
'sender_id' => $employer->id,
|
|
'text' => 'Hello worker, are you interested?',
|
|
]);
|
|
$message->created_at = now()->subDays(14);
|
|
$message->save();
|
|
|
|
// Run scheduler
|
|
Artisan::call('app:send-reminders');
|
|
|
|
// Assert Worker got WorkerNoResponseNotification for both
|
|
Notification::assertSentTo(
|
|
$worker,
|
|
WorkerNoResponseNotification::class,
|
|
function ($notification) use ($offer) {
|
|
return $notification->type === 'worker_no_response_offer' &&
|
|
$notification->daysElapsed === 14 &&
|
|
$notification->entityId === $offer->id;
|
|
}
|
|
);
|
|
|
|
Notification::assertSentTo(
|
|
$worker,
|
|
WorkerNoResponseNotification::class,
|
|
function ($notification) use ($message) {
|
|
return $notification->type === 'worker_no_response_chat' &&
|
|
$notification->daysElapsed === 14 &&
|
|
$notification->entityId === $message->id;
|
|
}
|
|
);
|
|
|
|
// Assert reminder logs were created
|
|
$this->assertDatabaseHas('reminder_logs', [
|
|
'user_type' => get_class($worker),
|
|
'user_id' => $worker->id,
|
|
'event_type' => 'worker_no_response_offer',
|
|
'reminder_level' => '14_days',
|
|
]);
|
|
|
|
$this->assertDatabaseHas('reminder_logs', [
|
|
'user_type' => get_class($worker),
|
|
'user_id' => $worker->id,
|
|
'event_type' => 'worker_no_response_chat',
|
|
'reminder_level' => '14_days',
|
|
]);
|
|
|
|
// Run again to verify duplicate prevention
|
|
Notification::fake();
|
|
Artisan::call('app:send-reminders');
|
|
Notification::assertNothingSent();
|
|
}
|
|
|
|
public function test_review_reminders_after_joining_date()
|
|
{
|
|
Notification::fake();
|
|
|
|
$worker = $this->createTestWorker();
|
|
$employer = $this->createTestEmployer();
|
|
|
|
$job = JobPost::create([
|
|
'employer_id' => $employer->id,
|
|
'title' => 'Nanny',
|
|
'location' => 'Dubai',
|
|
'salary' => 2500,
|
|
'workers_needed' => 1,
|
|
'job_type' => 'Full Time',
|
|
'start_date' => now()->subMonths(4)->toDateString(),
|
|
'description' => 'Test job',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// JobApplication with joining_confirmed_at exactly 3 months ago
|
|
$app = JobApplication::create([
|
|
'job_id' => $job->id,
|
|
'worker_id' => $worker->id,
|
|
'status' => 'hired',
|
|
'joining_confirmed_at' => now()->subMonths(3)->toDateString(),
|
|
]);
|
|
|
|
// Run scheduler
|
|
Artisan::call('app:send-reminders');
|
|
|
|
// Assert Worker got review reminder for employer
|
|
Notification::assertSentTo(
|
|
$worker,
|
|
WorkerReviewReminderNotification::class,
|
|
function ($notification) use ($app) {
|
|
return $notification->employerName === 'Alice Employer' &&
|
|
$notification->applicationId === $app->id &&
|
|
$notification->reviewLevel === '3_months';
|
|
}
|
|
);
|
|
|
|
// Assert Employer got review reminder for worker
|
|
Notification::assertSentTo(
|
|
$employer,
|
|
EmployerReviewReminderNotification::class,
|
|
function ($notification) use ($app) {
|
|
return $notification->workerName === 'John Worker' &&
|
|
$notification->applicationId === $app->id &&
|
|
$notification->reviewLevel === '3_months';
|
|
}
|
|
);
|
|
|
|
// Assert reminder logs were created
|
|
$this->assertDatabaseHas('reminder_logs', [
|
|
'user_type' => get_class($worker),
|
|
'user_id' => $worker->id,
|
|
'event_type' => 'review_employer_reminder',
|
|
'reminder_level' => '3_months',
|
|
]);
|
|
|
|
$this->assertDatabaseHas('reminder_logs', [
|
|
'user_type' => get_class($employer),
|
|
'user_id' => $employer->id,
|
|
'event_type' => 'review_worker_reminder',
|
|
'reminder_level' => '3_months',
|
|
]);
|
|
|
|
// Run again to verify duplicate prevention
|
|
Notification::fake();
|
|
Artisan::call('app:send-reminders');
|
|
Notification::assertNothingSent();
|
|
}
|
|
|
|
public function test_worker_review_controller_eligibility_and_edit_window()
|
|
{
|
|
$worker = $this->createTestWorker();
|
|
$employer = $this->createTestEmployer();
|
|
|
|
$job = JobPost::create([
|
|
'employer_id' => $employer->id,
|
|
'title' => 'Test Job',
|
|
'location' => 'Dubai',
|
|
'salary' => 2500,
|
|
'workers_needed' => 1,
|
|
'job_type' => 'Full Time',
|
|
'start_date' => now()->subMonths(4)->toDateString(),
|
|
'description' => 'Test Description',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// 1. Cannot review before eligibility period (set eligibility to 3 months)
|
|
$app = JobApplication::create([
|
|
'job_id' => $job->id,
|
|
'worker_id' => $worker->id,
|
|
'status' => 'hired',
|
|
'joining_confirmed_at' => now()->subMonths(2)->toDateString(),
|
|
]);
|
|
|
|
$response = $this->postJson('/api/workers/reviews', [
|
|
'employer_id' => $employer->id,
|
|
'job_id' => $job->id,
|
|
'rating' => 5,
|
|
'comment' => 'Great employer!',
|
|
], [
|
|
'Authorization' => 'Bearer worker_api_token'
|
|
]);
|
|
|
|
$response->assertStatus(403);
|
|
$response->assertJsonPath('success', false);
|
|
$response->assertJsonPath('message', 'You can write a review only after 3 months from the joining date.');
|
|
|
|
// 2. Can review after eligibility period
|
|
$app->joining_confirmed_at = now()->subMonths(3)->subDays(5)->toDateString();
|
|
$app->save();
|
|
|
|
$response = $this->postJson('/api/workers/reviews', [
|
|
'employer_id' => $employer->id,
|
|
'job_id' => $job->id,
|
|
'rating' => 5,
|
|
'comment' => 'Great employer!',
|
|
], [
|
|
'Authorization' => 'Bearer worker_api_token'
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
$response->assertJsonPath('success', true);
|
|
$reviewId = $response->json('data.review.id');
|
|
|
|
// 3. Edit review within 7 days
|
|
$response = $this->putJson("/api/workers/reviews/{$reviewId}", [
|
|
'rating' => 4,
|
|
'comment' => 'Good employer indeed.',
|
|
], [
|
|
'Authorization' => 'Bearer worker_api_token'
|
|
]);
|
|
$response->assertStatus(200);
|
|
|
|
// 4. Cannot edit review after 7 days
|
|
$review = EmployerReview::find($reviewId);
|
|
$review->created_at = now()->subDays(8);
|
|
$review->save();
|
|
|
|
$response = $this->putJson("/api/workers/reviews/{$reviewId}", [
|
|
'rating' => 3,
|
|
'comment' => 'Okay employer.',
|
|
], [
|
|
'Authorization' => 'Bearer worker_api_token'
|
|
]);
|
|
|
|
$response->assertStatus(403);
|
|
$response->assertJsonPath('success', false);
|
|
$response->assertJsonPath('message', 'The 7-day edit window for this review has expired.');
|
|
}
|
|
|
|
public function test_employer_review_controller_eligibility_and_edit_window()
|
|
{
|
|
$worker = $this->createTestWorker();
|
|
$employer = $this->createTestEmployer();
|
|
|
|
$job = JobPost::create([
|
|
'employer_id' => $employer->id,
|
|
'title' => 'Test Job',
|
|
'location' => 'Dubai',
|
|
'salary' => 2500,
|
|
'workers_needed' => 1,
|
|
'job_type' => 'Full Time',
|
|
'start_date' => now()->subMonths(4)->toDateString(),
|
|
'description' => 'Test Description',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// 1. Cannot review before eligibility period (set eligibility to 3 months)
|
|
$app = JobApplication::create([
|
|
'job_id' => $job->id,
|
|
'worker_id' => $worker->id,
|
|
'status' => 'hired',
|
|
'joining_confirmed_at' => now()->subMonths(2)->toDateString(),
|
|
]);
|
|
|
|
$response = $this->postJson('/api/employers/reviews', [
|
|
'worker_id' => $worker->id,
|
|
'rating' => 5,
|
|
'comment' => 'Great worker!',
|
|
], [
|
|
'Authorization' => 'Bearer employer_api_token'
|
|
]);
|
|
|
|
$response->assertStatus(403);
|
|
$response->assertJsonPath('success', false);
|
|
$response->assertJsonPath('message', 'You can write a review only after 3 months from the joining date.');
|
|
|
|
// 2. Can review after eligibility period
|
|
$app->joining_confirmed_at = now()->subMonths(3)->subDays(5)->toDateString();
|
|
$app->save();
|
|
|
|
$response = $this->postJson('/api/employers/reviews', [
|
|
'worker_id' => $worker->id,
|
|
'rating' => 5,
|
|
'comment' => 'Great worker!',
|
|
], [
|
|
'Authorization' => 'Bearer employer_api_token'
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
$response->assertJsonPath('success', true);
|
|
$reviewId = $response->json('data.review.id');
|
|
|
|
// 3. Edit review within 7 days
|
|
$response = $this->putJson("/api/employers/reviews/{$reviewId}", [
|
|
'rating' => 4,
|
|
'comment' => 'Good worker indeed.',
|
|
], [
|
|
'Authorization' => 'Bearer employer_api_token'
|
|
]);
|
|
$response->assertStatus(200);
|
|
|
|
// 4. Cannot edit review after 7 days
|
|
$review = Review::find($reviewId);
|
|
$review->created_at = now()->subDays(8);
|
|
$review->save();
|
|
|
|
$response = $this->putJson("/api/employers/reviews/{$reviewId}", [
|
|
'rating' => 3,
|
|
'comment' => 'Okay worker.',
|
|
], [
|
|
'Authorization' => 'Bearer employer_api_token'
|
|
]);
|
|
|
|
$response->assertStatus(403);
|
|
$response->assertJsonPath('success', false);
|
|
$response->assertJsonPath('message', 'The 7-day edit window for this review has expired.');
|
|
}
|
|
}
|