'HR Manager', 'email' => 'hr@company.com', 'role' => 'hr', ]); $interviewer1 = User::create([ 'name' => 'Tech Lead', 'email' => 'techlead@company.com', 'role' => 'user', ]); $interviewer2 = User::create([ 'name' => 'Senior Engineer', 'email' => 'srengineer@company.com', 'role' => 'user', ]); $response = $this->actingAs($hr)->post(route('interview.store'), [ 'candidate_name' => 'Soumyadeep Mondal', 'candidate_email' => 'soumyadeep@example.com', 'candidate_phone' => '9876543210', 'job_title' => 'AIML (Computer Vision & Agentic AI) Engineer', 'round' => 'R1', 'description' => 'Live coding session on Agentic workflows', 'scheduled_at' => now()->addDays(2)->format('Y-m-d\TH:i'), 'valid_hours' => 2, 'language' => 'python', 'assigned_interviewers' => [$interviewer1->id, $interviewer2->id], ]); $response->assertRedirect(route('interview.index')); // Database assertion $this->assertDatabaseHas('interviews', [ 'candidate_name' => 'Soumyadeep Mondal', 'candidate_email' => 'soumyadeep@example.com', 'job_title' => 'AIML (Computer Vision & Agentic AI) Engineer', 'round' => 'R1', 'description' => 'Live coding session on Agentic workflows', 'language' => 'python', 'status' => 'scheduled', ]); $interview = Interview::where('candidate_email', 'soumyadeep@example.com')->first(); $this->assertNotNull($interview); // Candidate mail assertion Mail::assertQueued(CandidateInterviewInvitationMail::class, function ($mail) use ($interview) { return $mail->hasTo('soumyadeep@example.com') && $mail->interview->id === $interview->id && ! empty($mail->icsContent); }); // Interviewers mail assertions Mail::assertQueued(InterviewerAssessmentNotificationMail::class, function ($mail) use ($interviewer1) { return $mail->hasTo('techlead@company.com') && $mail->interviewer->id === $interviewer1->id; }); Mail::assertQueued(InterviewerAssessmentNotificationMail::class, function ($mail) use ($interviewer2) { return $mail->hasTo('srengineer@company.com') && $mail->interviewer->id === $interviewer2->id; }); } public function test_send_interview_reminders_command_dispatches_15min_advance_emails(): void { Mail::fake(); $interviewer = User::create([ 'name' => 'Panelist User', 'email' => 'panelist@company.com', 'role' => 'user', ]); // Interview scheduled 10 minutes from now (within 20m window) $interview = Interview::create([ 'candidate_name' => 'Upcoming Candidate', 'candidate_email' => 'upcoming@example.com', 'candidate_phone' => '1122334455', 'job_title' => 'Backend Architect', 'round' => 'Technical Round', 'temp_password' => 'Pass-778899', 'scheduled_at' => now()->addMinutes(10), 'expires_at' => now()->addHours(2), 'language' => 'php', 'status' => 'scheduled', 'assigned_interviewers' => [$interviewer->id], 'submission_unique_id' => 'upcoming-candidate_1122334455_1752000099', 'reminder_sent_at' => null, ]); $this->artisan('interview:send-reminders') ->expectsOutputToContain('Successfully processed and dispatched reminders for 1 interview session(s).') ->assertExitCode(0); // Assert reminder email sent to candidate Mail::assertQueued(InterviewReminderMail::class, function ($mail) { return $mail->hasTo('upcoming@example.com') && $mail->recipientType === 'candidate'; }); // Assert reminder email sent to interviewer Mail::assertQueued(InterviewReminderMail::class, function ($mail) { return $mail->hasTo('panelist@company.com') && $mail->recipientType === 'interviewer'; }); $interview->refresh(); $this->assertNotNull($interview->reminder_sent_at); } public function test_scheduling_validation_errors_render_open_drawer_and_error_directives(): void { $this->withMiddleware(); $hr = User::create([ 'name' => 'HR Manager', 'email' => 'hr@company.com', 'role' => 'hr', ]); $response = $this->actingAs($hr) ->from(route('interview.index')) ->followingRedirects() ->post(route('interview.store'), [ 'candidate_name' => '', 'candidate_email' => 'invalid-email-address', 'candidate_phone' => '', 'job_title' => '', 'valid_hours' => 2, 'language' => 'python', 'description' => 'Test instructions', ]); $response->assertOk(); $response->assertSee('create-interview-drawer'); $response->assertSee('active'); $response->assertSee('Please correct the following errors:'); $response->assertSee('The candidate name is required.'); $response->assertSee('Please provide a valid candidate email address.'); $response->assertSee('The candidate phone number is required.'); $response->assertSee('The job title / position is required.'); $response->assertSee('Test instructions'); } }