changes on api worker employer details, review, issue
This commit is contained in:
parent
2f81865175
commit
52b47cc2ac
@ -933,4 +933,155 @@ private function cleanVisaData(array $visaDataInput): array
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of an employer profile for worker view.
|
||||
* GET /api/workers/employers/{id}
|
||||
*/
|
||||
public function getEmployerProfile(Request $request, $id)
|
||||
{
|
||||
/** @var Worker $worker */
|
||||
$worker = $request->attributes->get('worker');
|
||||
|
||||
try {
|
||||
// Find the employer (role should be 'employer')
|
||||
$employer = \App\Models\User::where('id', $id)->where('role', 'employer')->first();
|
||||
|
||||
if (!$employer) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Employer not found.'
|
||||
], 404);
|
||||
}
|
||||
|
||||
$empProfile = $employer->employerProfile;
|
||||
|
||||
// 1. Check access permissions for contact details
|
||||
$hasAccess = false;
|
||||
|
||||
// Check if there is an active/previous JobOffer
|
||||
$hasOffer = \App\Models\JobOffer::where('employer_id', $employer->id)
|
||||
->where('worker_id', $worker->id)
|
||||
->exists();
|
||||
|
||||
// Check if the worker has applied to any jobs of this employer
|
||||
$hasApplication = \App\Models\JobApplication::where('worker_id', $worker->id)
|
||||
->whereHas('jobPost', function ($query) use ($employer) {
|
||||
$query->where('employer_id', $employer->id);
|
||||
})
|
||||
->exists();
|
||||
|
||||
// Check if there is an active/previous conversation
|
||||
$hasConversation = \App\Models\Conversation::where('employer_id', $employer->id)
|
||||
->where('worker_id', $worker->id)
|
||||
->exists();
|
||||
|
||||
if ($hasOffer || $hasApplication || $hasConversation) {
|
||||
$hasAccess = true;
|
||||
}
|
||||
|
||||
// 2. Fetch active job details (if applicable)
|
||||
$activeJobs = \App\Models\JobPost::where('employer_id', $employer->id)
|
||||
->where('status', 'active')
|
||||
->latest()
|
||||
->get()
|
||||
->map(function ($job) {
|
||||
return [
|
||||
'id' => $job->id,
|
||||
'title' => $job->title,
|
||||
'location' => $job->location,
|
||||
'salary' => (int) $job->salary,
|
||||
'job_type' => $job->job_type,
|
||||
'start_date' => $job->start_date ? $job->start_date->format('Y-m-d') : null,
|
||||
'description' => $job->description,
|
||||
'requirements' => $job->requirements,
|
||||
'posted_at' => $job->created_at->toIso8601String(),
|
||||
];
|
||||
});
|
||||
|
||||
// 3. Overall Rating and Review Summary
|
||||
$reviewsQuery = \App\Models\EmployerReview::where('employer_id', $employer->id);
|
||||
$totalReviews = $reviewsQuery->count();
|
||||
$avgRating = $totalReviews > 0 ? round($reviewsQuery->avg('rating'), 1) : 0.0;
|
||||
|
||||
$starsBreakdown = [
|
||||
'5' => \App\Models\EmployerReview::where('employer_id', $employer->id)->where('rating', 5)->count(),
|
||||
'4' => \App\Models\EmployerReview::where('employer_id', $employer->id)->where('rating', 4)->count(),
|
||||
'3' => \App\Models\EmployerReview::where('employer_id', $employer->id)->where('rating', 3)->count(),
|
||||
'2' => \App\Models\EmployerReview::where('employer_id', $employer->id)->where('rating', 2)->count(),
|
||||
'1' => \App\Models\EmployerReview::where('employer_id', $employer->id)->where('rating', 1)->count(),
|
||||
];
|
||||
|
||||
// 4. Paginated Reviews list
|
||||
$perPage = (int) $request->input('per_page', 10);
|
||||
$reviewsPaginator = \App\Models\EmployerReview::where('employer_id', $employer->id)
|
||||
->with('worker')
|
||||
->latest()
|
||||
->paginate($perPage);
|
||||
|
||||
$reviews = collect($reviewsPaginator->items())->map(function ($rev) {
|
||||
return [
|
||||
'id' => $rev->id,
|
||||
'rating' => $rev->rating,
|
||||
'title' => $rev->title,
|
||||
'comment' => $rev->comment,
|
||||
'created_at' => $rev->created_at->toIso8601String(),
|
||||
'worker' => $rev->worker ? [
|
||||
'id' => $rev->worker->id,
|
||||
'name' => $rev->worker->name,
|
||||
'nationality' => $rev->worker->nationality,
|
||||
] : null,
|
||||
];
|
||||
});
|
||||
|
||||
// 5. Structure the response
|
||||
$employerData = [
|
||||
'id' => $employer->id,
|
||||
'name' => $employer->name,
|
||||
'email' => $hasAccess ? $employer->email : null,
|
||||
'phone' => $hasAccess ? ($empProfile->phone ?? $employer->phone) : null,
|
||||
'company_name' => $empProfile->company_name ?? 'Private Sponsor',
|
||||
'city' => $empProfile->city ?? null,
|
||||
'district' => $empProfile->district ?? null,
|
||||
'nationality' => $empProfile->nationality ?? null,
|
||||
'address' => $empProfile->address ?? null,
|
||||
'accommodation' => $empProfile->accommodation ?? null,
|
||||
'language' => $empProfile->language ?? null,
|
||||
'profile_photo_url' => $empProfile->profile_photo_url ?? null,
|
||||
'rating' => $avgRating,
|
||||
'reviews_count' => $totalReviews,
|
||||
'review_summary' => [
|
||||
'total' => $totalReviews,
|
||||
'average' => $avgRating,
|
||||
'stars' => $starsBreakdown,
|
||||
],
|
||||
'active_jobs' => $activeJobs,
|
||||
];
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'employer' => $employerData,
|
||||
'reviews' => [
|
||||
'data' => $reviews,
|
||||
'pagination' => [
|
||||
'total' => $reviewsPaginator->total(),
|
||||
'per_page' => $reviewsPaginator->perPage(),
|
||||
'current_page' => $reviewsPaginator->currentPage(),
|
||||
'last_page' => $reviewsPaginator->lastPage(),
|
||||
]
|
||||
]
|
||||
]
|
||||
], 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
logger()->error('Worker View Employer Profile Failure: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'An error occurred while loading the employer profile.',
|
||||
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,12 @@ public function addReview(Request $request)
|
||||
/** @var Worker $worker */
|
||||
$worker = $request->attributes->get('worker');
|
||||
|
||||
// Sanitize job_id: if not a valid existing JobPost ID, treat it as null (job id is not needed/optional)
|
||||
$jobIdInput = $request->input('job_id');
|
||||
if (empty($jobIdInput) || !is_numeric($jobIdInput) || !\App\Models\JobPost::where('id', $jobIdInput)->exists()) {
|
||||
$request->merge(['job_id' => null]);
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'employer_id' => 'required|exists:users,id',
|
||||
'job_id' => 'nullable|exists:job_posts,id',
|
||||
|
||||
@ -33,6 +33,8 @@ public function handle(Request $request, Closure $next): Response
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
session()->forget('user');
|
||||
auth()->logout();
|
||||
return redirect()->route('employer.login');
|
||||
}
|
||||
|
||||
|
||||
@ -7305,6 +7305,161 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workers/employers/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Worker/Employers"
|
||||
],
|
||||
"summary": "Worker View Employer Profile",
|
||||
"description": "Allows authenticated workers to view the complete profile of a specific employer, including company details, ratings, review summaries, active jobs, and a paginated list of worker-submitted reviews. Contact details are conditionally visible depending on whether the worker has a past/present connection with the employer.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The unique database ID of the employer.",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"description": "Number of reviews to display per page (default: 10).",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"example": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"description": "The page number of the reviews list to fetch.",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Employer profile loaded successfully.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"employer": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "integer", "example": 1 },
|
||||
"name": { "type": "string", "example": "Jane Sponsor" },
|
||||
"email": { "type": "string", "nullable": true, "example": "sponsor@example.com" },
|
||||
"phone": { "type": "string", "nullable": true, "example": "+971501112222" },
|
||||
"company_name": { "type": "string", "example": "Sponsor Co" },
|
||||
"city": { "type": "string", "nullable": true, "example": "Dubai" },
|
||||
"district": { "type": "string", "nullable": true, "example": "Dubai Marina" },
|
||||
"nationality": { "type": "string", "nullable": true, "example": "Emirati" },
|
||||
"address": { "type": "string", "nullable": true, "example": "123 Street" },
|
||||
"accommodation": { "type": "string", "nullable": true, "example": "Provided" },
|
||||
"language": { "type": "string", "nullable": true, "example": "English" },
|
||||
"profile_photo_url": { "type": "string", "nullable": true, "example": "https://example.com/photo.jpg" },
|
||||
"rating": { "type": "number", "format": "float", "example": 4.5 },
|
||||
"reviews_count": { "type": "integer", "example": 12 },
|
||||
"review_summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": { "type": "integer", "example": 12 },
|
||||
"average": { "type": "number", "example": 4.5 },
|
||||
"stars": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"5": { "type": "integer", "example": 8 },
|
||||
"4": { "type": "integer", "example": 2 },
|
||||
"3": { "type": "integer", "example": 1 },
|
||||
"2": { "type": "integer", "example": 1 },
|
||||
"1": { "type": "integer", "example": 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"active_jobs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "integer", "example": 5 },
|
||||
"title": { "type": "string", "example": "Housekeeper Needed" },
|
||||
"location": { "type": "string", "example": "Dubai Marina" },
|
||||
"salary": { "type": "integer", "example": 2500 },
|
||||
"job_type": { "type": "string", "example": "Full Time" },
|
||||
"start_date": { "type": "string", "format": "date", "example": "2026-08-01" },
|
||||
"description": { "type": "string", "example": "Clean house" },
|
||||
"requirements": { "type": "string", "nullable": true, "example": "Experience required" },
|
||||
"posted_at": { "type": "string", "format": "date-time", "example": "2026-07-04T12:00:00Z" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"reviews": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "integer", "example": 1 },
|
||||
"rating": { "type": "integer", "example": 5 },
|
||||
"title": { "type": "string", "example": "Great employer" },
|
||||
"comment": { "type": "string", "example": "Highly recommended!" },
|
||||
"created_at": { "type": "string", "format": "date-time", "example": "2026-07-04T12:00:00Z" },
|
||||
"worker": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "integer", "example": 2 },
|
||||
"name": { "type": "string", "example": "Worker Name" },
|
||||
"nationality": { "type": "string", "example": "Filipino" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"pagination": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": { "type": "integer", "example": 1 },
|
||||
"per_page": { "type": "integer", "example": 10 },
|
||||
"current_page": { "type": "integer", "example": 1 },
|
||||
"last_page": { "type": "integer", "example": 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Employer not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workers/forgot-password": {
|
||||
"post": {
|
||||
"tags": [
|
||||
|
||||
@ -78,6 +78,7 @@
|
||||
Route::get('/workers/dashboard/views', [WorkerProfileController::class, 'getProfileViews']);
|
||||
Route::get('/workers/dashboard', [WorkerProfileController::class, 'getDashboard']);
|
||||
Route::get('/workers/employers', [WorkerProfileController::class, 'getEmployers']);
|
||||
Route::get('/workers/employers/{id}', [WorkerProfileController::class, 'getEmployerProfile']);
|
||||
Route::post('/workers/change-password', [WorkerProfileController::class, 'changePassword']);
|
||||
|
||||
|
||||
|
||||
@ -85,4 +85,31 @@ public function test_employer_upload_emirates_id_ocr_and_purge()
|
||||
$this->assertNotNull($profile->emirates_id_expiry);
|
||||
$this->assertEquals('approved', $profile->verification_status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a stale session with an invalid user ID does not cause a redirect loop.
|
||||
*/
|
||||
public function test_stale_session_does_not_cause_redirect_loop()
|
||||
{
|
||||
// 1. Visit with a session user object containing a non-existent ID
|
||||
$staleUser = (object)[
|
||||
'id' => 999999, // Doesn't exist
|
||||
'name' => 'Stale User',
|
||||
'email' => 'stale@example.com',
|
||||
'role' => 'employer',
|
||||
'subscription_status' => 'active',
|
||||
'verification_status' => 'approved',
|
||||
];
|
||||
|
||||
// Accessing dashboard should fail auth, clear session, and redirect to login
|
||||
$response = $this->withSession(['user' => $staleUser])
|
||||
->get('/employer/dashboard');
|
||||
|
||||
$response->assertRedirect(route('employer.login'));
|
||||
$this->assertNull(session('user')); // Session must be cleared
|
||||
|
||||
// Subsequent access to login page should render successfully (no redirect)
|
||||
$loginResponse = $this->get('/employer/login');
|
||||
$loginResponse->assertStatus(200);
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,4 +236,172 @@ public function test_worker_employers_list_pagination_and_sorting()
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,4 +268,37 @@ public function test_view_and_list_reviews()
|
||||
$response->assertJsonCount(1, 'data.reviews');
|
||||
$response->assertJsonPath('data.reviews.0.title', 'Awesome place');
|
||||
}
|
||||
|
||||
public function test_review_with_invalid_or_missing_job_id_passes_and_saves_null()
|
||||
{
|
||||
// Setup job application with hired status and joining_confirmed_at 3.5 months ago
|
||||
JobApplication::create([
|
||||
'job_id' => $this->job->id,
|
||||
'worker_id' => $this->worker->id,
|
||||
'status' => 'hired',
|
||||
'joining_confirmed_at' => now()->subMonths(3)->subDays(15)->toDateString(),
|
||||
]);
|
||||
|
||||
// Act: Post review with an invalid job_id (e.g. 'invalid-id-or-empty')
|
||||
$response = $this->postJson('/api/workers/reviews', [
|
||||
'employer_id' => $this->employer->id,
|
||||
'job_id' => 'invalid-id-or-empty',
|
||||
'rating' => 4,
|
||||
'title' => 'Fair Employer',
|
||||
'comment' => 'Very good experience overall.',
|
||||
], [
|
||||
'Authorization' => 'Bearer worker_api_token'
|
||||
]);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$response->assertJsonPath('success', true);
|
||||
$response->assertJsonPath('data.review.job_id', null); // Resolved to null
|
||||
|
||||
$this->assertDatabaseHas('employer_reviews', [
|
||||
'worker_id' => $this->worker->id,
|
||||
'employer_id' => $this->employer->id,
|
||||
'job_id' => null,
|
||||
'rating' => 4,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user